<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:dcterms="http://purl.org/dc/terms/"
     xmlns:media="http://search.yahoo.com/mrss/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:cf="https://www.futureplc.com/rss/content-flags"
>
    <channel>
                    <atom:link href="https://www.tomsguide.com/feeds/tag/homes" rel="self" type="application/rss+xml" />
                            <title><![CDATA[ Latest from Tom's Guide in Homes ]]></title>
                <link>https://www.tomsguide.com/tag/homes</link>
        <description><![CDATA[ All the latest homes content from the Tom's Guide team ]]></description>
                                    <lastBuildDate>Fri, 30 Oct 2026 05:00:00 +0000</lastBuildDate>
                            <language>en</language>
                                <item>
                                                            <title><![CDATA[ Can boiling water cause damage to your pipes? My plumber husband reveals his expert tips ]]></title>
                                                                                                <dc:content><![CDATA[ <p>I'll be honest, despite living with a plumber, there's still plenty of things I do wrong when it comes to the pipes in my home. And while my husband's more than happy to tell me why I need to stop clogging the bathtub drain with my hair, there are some things we never discuss.</p><p>When someone recently asked me whether it was safe to pour boiling water down the sink, I didn't know what to say. So, I turned to my husband, just as I did when I wanted to know <a href="https://www.tomsguide.com/home/how-often-should-you-actually-clean-your-shower-head-my-plumber-husband-reveals-his-top-expert-tips">how often you should actually clean your shower head</a>?</p><p>It turns out when it comes to pouring boiling water down your drains, most of the time it's no problem at all. In fact, sometimes it can actually be helpful. But, there's still some instances when you need to be more careful. Here's my plumber husband's top tips.</p><h2 id="is-it-safe-to-pour-boiling-water-down-your-sink">Is it safe to pour boiling water down your sink?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="teJZZQNvpB7HKpxLJbX94T" name="Shutterstock 2241103075 boiling water down drain" alt="Households urged not to pour boiling water down drains" src="https://cdn.mos.cms.futurecdn.net/teJZZQNvpB7HKpxLJbX94T-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>My plumber husband's first response was to simply say: "Yes, it's not a problem." With most home pipes, exposure to boiling water won't cause any issues. But, when I poked him for some extra advice, he added: "It's not going to damage anything and it could potentially clear minor blockages.</p><p>"It's actually probably something you want to start with if you think you've got a blockage, before you move onto using chemicals or anything more potent," he explains.</p><p>But, there are still some instances, he warned, that can cause your pipes to suffer from long-term exposure to boiling water.</p><h2 id="when-is-it-not-safe-to-pour-boiling-water-down-your-sink">When is it not safe to pour boiling water down your sink?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5193px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="jai6BJX4iCiWCuFDCQgCwJ" name="sink crop2.jpg" alt="Stainless steel sink" src="https://cdn.mos.cms.futurecdn.net/jai6BJX4iCiWCuFDCQgCwJ-1920-80.jpg" mos="" align="middle" fullscreen="" width="5193" height="2921" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>While a lot of households have metal pipes, there are still a proportion that don't (especially newer builds). "If you have plastic or PVC pipes, you should be more cautious. There's potential for the hot water to melt or misshape your pipes with excessive exposure," he reveals.</p><p>Though, he was quick to add that excessive exposure means doing it <em>a heck of a lot</em>, which he doesn't believe anyone would be doing. Simply pouring away the remains of a kettle or draining your pasta water won't have devastating effects to your pipes, but if you're inclined to do it regularly than you may be causing an issue.</p><div class="product"><a data-dimension112="4d8be98e-cdfc-11f1-b42f-f7389ba25c0a" data-action="Deal Block" data-label="Max Gel Drain Clog Remover" data-dimension48="Max Gel Drain Clog Remover" data-dimension25="$5.17" href="https://www.amazon.com/Drano-Drain-Remover-Cleaner-Septic/dp/B000ST1DZO" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="HTef474W6VDknoQHRpAwmi" name="clog_remover_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HTef474W6VDknoQHRpAwmi-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>While you may want to grab your drain clog remover when you notice your sink backing up, it might still be worth pouring some boiling water down the sink as your first port of call. If that doesn't budget it, you can try a solution like Drano's Max Gel Drain Clog Remover and allow it to sit for 15-30 minutes before flushing with hot tap water.<a class="view-deal button" href="https://www.amazon.com/Drano-Drain-Remover-Cleaner-Septic/dp/B000ST1DZO" target="_blank" rel="nofollow" data-dimension112="4d8be98e-cdfc-11f1-b42f-f7389ba25c0a" data-action="Deal Block" data-label="Max Gel Drain Clog Remover" data-dimension48="Max Gel Drain Clog Remover" data-dimension25="$5.17">View Deal</a></p></div><h2 id="does-running-cold-water-at-the-same-time-help">Does running cold water at the same time help?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3594px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="5smVdMmGGGTcK6LtTYMKHa" name="Pouring oil in sink - crop.jpg" alt="Pouring oil down the sink" src="https://cdn.mos.cms.futurecdn.net/5smVdMmGGGTcK6LtTYMKHa-1920-80.jpg" mos="" align="middle" fullscreen="" width="3594" height="2022" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>You might have heard of a 'hack' that some people suggest where you run cold water from your tap at the same time as pouring the boiling water down the sink to lower the temperature. </p><p>And while my husband plumber suggests it would cool it down, he adds: "It'd just be like running the hot water tap, only you do run a small risk of thermal shock. I'm not sure what would be the benefit. All you're doing is cooling down the water, but it wouldn't be causing an issue in the first place."</p><p>He suggests that if you're looking to protect your pipes, you shouldn't be wary of boiling water. Instead, you should be focusing on not washing down any grease, fats or food waste into your sink as that could cause blockages that are a lot harder to solve.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/this-tiktok-hack-claims-vinegar-will-clean-your-shower-head-i-asked-my-plumber-husband-if-it-actually-works">This TikTok hack claims vinegar will clean your shower head — I asked my plumber husband if it actually works</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/people-are-using-dish-soap-to-break-down-drain-blockages-i-asked-a-plumber-if-its-a-good-idea">You asked: Can dish soap fix your clogged drain? A plumber explains the facts</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/households-urged-not-to-pour-boiling-water-down-drains-this-winter-i-asked-a-plumber-what-to-do-instead">Households urged not to pour boiling water down drains this winter — I asked a plumber what to do instead</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/can-boiling-water-cause-damage-to-your-pipes-my-plumber-husband-reveals-his-expert-tips</link>
                                                                            <description>
                            <![CDATA[ You might be in the habit of pouring freshly boiled water down your sink – to clean it or just to discard it. But here's what you need to know about what effect it's having on your pipes, thanks to expert tips from my plumber husband. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">nJ7sy5VHRiHBVn7x4KeZoF</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Uhh48A7RYGpHeVGLABWBzV-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 30 Oct 2026 05:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/Uhh48A7RYGpHeVGLABWBzV-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                        <media:description><![CDATA[Kitchen sink]]></media:description>                                                            <media:text><![CDATA[Kitchen sink]]></media:text>
                                <media:title type="plain"><![CDATA[Kitchen sink]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Uhh48A7RYGpHeVGLABWBzV-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I'll be honest, despite living with a plumber, there's still plenty of things I do wrong when it comes to the pipes in my home. And while my husband's more than happy to tell me why I need to stop clogging the bathtub drain with my hair, there are some things we never discuss.</p><p>When someone recently asked me whether it was safe to pour boiling water down the sink, I didn't know what to say. So, I turned to my husband, just as I did when I wanted to know <a href="https://www.tomsguide.com/home/how-often-should-you-actually-clean-your-shower-head-my-plumber-husband-reveals-his-top-expert-tips">how often you should actually clean your shower head</a>?</p><p>It turns out when it comes to pouring boiling water down your drains, most of the time it's no problem at all. In fact, sometimes it can actually be helpful. But, there's still some instances when you need to be more careful. Here's my plumber husband's top tips.</p><h2 id="is-it-safe-to-pour-boiling-water-down-your-sink">Is it safe to pour boiling water down your sink?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="teJZZQNvpB7HKpxLJbX94T" name="Shutterstock 2241103075 boiling water down drain" alt="Households urged not to pour boiling water down drains" src="https://cdn.mos.cms.futurecdn.net/teJZZQNvpB7HKpxLJbX94T-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>My plumber husband's first response was to simply say: "Yes, it's not a problem." With most home pipes, exposure to boiling water won't cause any issues. But, when I poked him for some extra advice, he added: "It's not going to damage anything and it could potentially clear minor blockages.</p><p>"It's actually probably something you want to start with if you think you've got a blockage, before you move onto using chemicals or anything more potent," he explains.</p><p>But, there are still some instances, he warned, that can cause your pipes to suffer from long-term exposure to boiling water.</p><h2 id="when-is-it-not-safe-to-pour-boiling-water-down-your-sink">When is it not safe to pour boiling water down your sink?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5193px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="jai6BJX4iCiWCuFDCQgCwJ" name="sink crop2.jpg" alt="Stainless steel sink" src="https://cdn.mos.cms.futurecdn.net/jai6BJX4iCiWCuFDCQgCwJ-1920-80.jpg" mos="" align="middle" fullscreen="" width="5193" height="2921" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>While a lot of households have metal pipes, there are still a proportion that don't (especially newer builds). "If you have plastic or PVC pipes, you should be more cautious. There's potential for the hot water to melt or misshape your pipes with excessive exposure," he reveals.</p><p>Though, he was quick to add that excessive exposure means doing it <em>a heck of a lot</em>, which he doesn't believe anyone would be doing. Simply pouring away the remains of a kettle or draining your pasta water won't have devastating effects to your pipes, but if you're inclined to do it regularly than you may be causing an issue.</p><div class="product"><a data-dimension112="4d8be98e-cdfc-11f1-b42f-f7389ba25c0a" data-action="Deal Block" data-label="Max Gel Drain Clog Remover" data-dimension48="Max Gel Drain Clog Remover" data-dimension25="$5.17" href="https://www.amazon.com/Drano-Drain-Remover-Cleaner-Septic/dp/B000ST1DZO" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="HTef474W6VDknoQHRpAwmi" name="clog_remover_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HTef474W6VDknoQHRpAwmi-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>While you may want to grab your drain clog remover when you notice your sink backing up, it might still be worth pouring some boiling water down the sink as your first port of call. If that doesn't budget it, you can try a solution like Drano's Max Gel Drain Clog Remover and allow it to sit for 15-30 minutes before flushing with hot tap water.<a class="view-deal button" href="https://www.amazon.com/Drano-Drain-Remover-Cleaner-Septic/dp/B000ST1DZO" target="_blank" rel="nofollow" data-dimension112="4d8be98e-cdfc-11f1-b42f-f7389ba25c0a" data-action="Deal Block" data-label="Max Gel Drain Clog Remover" data-dimension48="Max Gel Drain Clog Remover" data-dimension25="$5.17">View Deal</a></p></div><h2 id="does-running-cold-water-at-the-same-time-help">Does running cold water at the same time help?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3594px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="5smVdMmGGGTcK6LtTYMKHa" name="Pouring oil in sink - crop.jpg" alt="Pouring oil down the sink" src="https://cdn.mos.cms.futurecdn.net/5smVdMmGGGTcK6LtTYMKHa-1920-80.jpg" mos="" align="middle" fullscreen="" width="3594" height="2022" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>You might have heard of a 'hack' that some people suggest where you run cold water from your tap at the same time as pouring the boiling water down the sink to lower the temperature. </p><p>And while my husband plumber suggests it would cool it down, he adds: "It'd just be like running the hot water tap, only you do run a small risk of thermal shock. I'm not sure what would be the benefit. All you're doing is cooling down the water, but it wouldn't be causing an issue in the first place."</p><p>He suggests that if you're looking to protect your pipes, you shouldn't be wary of boiling water. Instead, you should be focusing on not washing down any grease, fats or food waste into your sink as that could cause blockages that are a lot harder to solve.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/this-tiktok-hack-claims-vinegar-will-clean-your-shower-head-i-asked-my-plumber-husband-if-it-actually-works">This TikTok hack claims vinegar will clean your shower head — I asked my plumber husband if it actually works</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/people-are-using-dish-soap-to-break-down-drain-blockages-i-asked-a-plumber-if-its-a-good-idea">You asked: Can dish soap fix your clogged drain? A plumber explains the facts</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/households-urged-not-to-pour-boiling-water-down-drains-this-winter-i-asked-a-plumber-what-to-do-instead">Households urged not to pour boiling water down drains this winter — I asked a plumber what to do instead</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 3 simple ways to coax one last bloom from your peace lily before winter sets in ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Few indoor plants are as forgiving as the peace lily, but coaxing one to put out its sculptural, creamy white spathes once October slips away is a different challenge entirely. As fall sets in, the window to encourage fresh flowers is closing fast. </p><p>Temperatures are dipping, natural daylight is fading by the afternoon, and central heating systems are beginning to strip indoor air of its ambient moisture. Left to fend for itself in a dim corner, a peace lily will naturally wind down its metabolic engine and head straight into winter dormancy.</p><p>Triggering one final, dramatic flush of fall blooms before the cold locks in requires working with the plant's seasonal biology, rather than fighting it.</p><section class="howto-block">                    <h3>1. Shift to bright, indirect morning light</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/EG8HEq9b3H35ajPKvroQDd.jpg"                                        alt="Peace lily plant in the corner of a space"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/EG8HEq9b3H35ajPKvroQDd.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>In the height of midsummer, direct sunlight is the fastest way to scorch peace lily foliage. But as fall sets in, daylight becomes far weaker, and a lack of adequate light intensity is the number one reason these plants stall out into pure foliage producers.</p><p>To give it the energy needed to produce flower stalks, <strong>move your pot out of deep shade and place it roughly three feet away from an east or south-facing window</strong>. You want plenty of soft, filtered light throughout the morning without baking the leaves against cold window glass. </p><p>If the plant remains marooned in a dim hallway, it will conserve its carbohydrates strictly for root and leaf maintenance, abandoning flower production until next spring.</p></p>                </section><section class="howto-block">                    <h3>2. Dial back water to protect against root chill</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/Usz7J2Fa5XZPmD8kJuDHcG.jpg"                                        alt="Watering a peace lily"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/Usz7J2Fa5XZPmD8kJuDHcG.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>The cardinal sin of fall houseplant care is maintaining a summer watering schedule. As temperatures drop, potting compost stays wet for far longer. Saturation combined with cool room air is an open invitation for root rot, <a href="https://www.tomsguide.com/home/gardening/peace-lily-leaves-drooping-3-causes-and-quick-fixes">the primary culprit behind sad, droopy leaves</a> that kill off developing flower buds before they can emerge.</p><p>Ditch a rigid calendar schedule and inspect the soil directly: <strong>push your finger two inches into the potting mix, and only water when the top half feels distinctly dry </strong>to the touch. </p><p>When you do water, <strong>use tepid room-temperature water</strong> rather than freezing cold tap water, which shocks the roots and makes the plant kill off any new buds before they have a chance to bloom.</p></p>                </section><section class="howto-block">                    <h3>3. Cut the fertilizer and boost humidity</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/hjMM8nP3Q988Tbo3VmpkAo.jpg"                                        alt="Peace lily refreshed with pruned brown flowers removed"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/hjMM8nP3Q988Tbo3VmpkAo.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Tom's Guide / Camilla Sharman)</div></figure>                    <p><p>Dumping fertilizer into the pot right now will backfire. Plant foods push out soft, leggy green leaves at the expense of flowers, and excess fertilizer salts can easily burn roots that are naturally slowing down for the season.</p><p>If you feed at all during this final fall window, switch to a potassium-rich, diluted tomato feed or high-phosphorus bloom booster at quarter strength, applied just once before mid-November.</p><p>At the same time, <strong>keep the plant far away from blasting heat vents, radiators, or drafty exterior doors</strong>. Central heating parches indoor air, <a href="https://www.tomsguide.com/home/gardening/peace-lily-tips-turning-brown-youre-probably-blaming-the-wrong-thing">turning leaf tips brown</a> and drying out fragile buds before they unfurl. </p><p>To boost humidity, <strong>set the pot on a wide tray filled with pebbles and water</strong>. As the water evaporates. it creates a pocket of moisture that mimics the tropical environment peace lilies need to push out their signature white blooms.</p></p>                </section><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-W0EdRO"></div>                            </div>                            <script src="https://kwizly.com/embed/W0EdRO.js" async=""></script><figure class="van-image-figure pull-right inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:676px;"><p class="vanilla-image-block" style="padding-top:31.51%;"><img id="ZCwuUFRE3YeboHR4zyEWmb" name="r3t8zZ5ve4GewFTeoCM3R6" alt="Google" src="https://cdn.mos.cms.futurecdn.net/ZCwuUFRE3YeboHR4zyEWmb-1920-80.jpg" mos="" align="right" fullscreen="" width="676" height="213" attribution="" endorsement="" class="pull-rightinline" /></p></div></div><figcaption itemprop="caption description" class="pull-right inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide </span></h3><ul><li><a href="https://www.tomsguide.com/home/gardening/why-are-my-peace-lily-leaves-turning-yellow-3-steps-to-bring-back-the-green">Why are my peace lily leaves turning yellow? 3 steps to bring back the green</a></li><li><a href="https://www.tomsguide.com/home/gardening/where-to-put-a-peace-lily-so-it-actually-flowers-5-ideal-spots-in-your-home">Where to put a peace lily so it actually flowers — 5 ideal spots in your home</a></li><li><a href="https://www.tomsguide.com/home/gardening/your-peace-lily-needs-dividing-if-you-see-these-signs-heres-how-to-do-it">Your peace lily needs dividing if you see these signs — here's how to do it</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/gardening/3-simple-ways-to-coax-one-last-bloom-from-your-peace-lily-before-winter-sets-in</link>
                                                                            <description>
                            <![CDATA[ Learn how to get your peace lily to flower again this fall and keep it blooming before dormancy sets in. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">jHeRqK6BdypMLf3yXQRbBV</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/xxW2FQFAdFPwn6noiGRepQ-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 29 Oct 2026 05:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gardening]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                <author><![CDATA[ kaycee.hill@futurenet.com (Kaycee Hill) ]]></author>                    <dc:creator><![CDATA[ Kaycee Hill ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/xHn6RmpEqg87cvtLwrBu9G-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/xxW2FQFAdFPwn6noiGRepQ-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Peace lily plant close up ]]></media:description>                                                            <media:text><![CDATA[Peace lily plant close up ]]></media:text>
                                <media:title type="plain"><![CDATA[Peace lily plant close up ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/xxW2FQFAdFPwn6noiGRepQ-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Few indoor plants are as forgiving as the peace lily, but coaxing one to put out its sculptural, creamy white spathes once October slips away is a different challenge entirely. As fall sets in, the window to encourage fresh flowers is closing fast. </p><p>Temperatures are dipping, natural daylight is fading by the afternoon, and central heating systems are beginning to strip indoor air of its ambient moisture. Left to fend for itself in a dim corner, a peace lily will naturally wind down its metabolic engine and head straight into winter dormancy.</p><p>Triggering one final, dramatic flush of fall blooms before the cold locks in requires working with the plant's seasonal biology, rather than fighting it.</p><section class="howto-block">                    <h3>1. Shift to bright, indirect morning light</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/EG8HEq9b3H35ajPKvroQDd.jpg"                                        alt="Peace lily plant in the corner of a space"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/EG8HEq9b3H35ajPKvroQDd.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>In the height of midsummer, direct sunlight is the fastest way to scorch peace lily foliage. But as fall sets in, daylight becomes far weaker, and a lack of adequate light intensity is the number one reason these plants stall out into pure foliage producers.</p><p>To give it the energy needed to produce flower stalks, <strong>move your pot out of deep shade and place it roughly three feet away from an east or south-facing window</strong>. You want plenty of soft, filtered light throughout the morning without baking the leaves against cold window glass. </p><p>If the plant remains marooned in a dim hallway, it will conserve its carbohydrates strictly for root and leaf maintenance, abandoning flower production until next spring.</p></p>                </section><section class="howto-block">                    <h3>2. Dial back water to protect against root chill</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/Usz7J2Fa5XZPmD8kJuDHcG.jpg"                                        alt="Watering a peace lily"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/Usz7J2Fa5XZPmD8kJuDHcG.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>The cardinal sin of fall houseplant care is maintaining a summer watering schedule. As temperatures drop, potting compost stays wet for far longer. Saturation combined with cool room air is an open invitation for root rot, <a href="https://www.tomsguide.com/home/gardening/peace-lily-leaves-drooping-3-causes-and-quick-fixes">the primary culprit behind sad, droopy leaves</a> that kill off developing flower buds before they can emerge.</p><p>Ditch a rigid calendar schedule and inspect the soil directly: <strong>push your finger two inches into the potting mix, and only water when the top half feels distinctly dry </strong>to the touch. </p><p>When you do water, <strong>use tepid room-temperature water</strong> rather than freezing cold tap water, which shocks the roots and makes the plant kill off any new buds before they have a chance to bloom.</p></p>                </section><section class="howto-block">                    <h3>3. Cut the fertilizer and boost humidity</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/hjMM8nP3Q988Tbo3VmpkAo.jpg"                                        alt="Peace lily refreshed with pruned brown flowers removed"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/hjMM8nP3Q988Tbo3VmpkAo.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Tom's Guide / Camilla Sharman)</div></figure>                    <p><p>Dumping fertilizer into the pot right now will backfire. Plant foods push out soft, leggy green leaves at the expense of flowers, and excess fertilizer salts can easily burn roots that are naturally slowing down for the season.</p><p>If you feed at all during this final fall window, switch to a potassium-rich, diluted tomato feed or high-phosphorus bloom booster at quarter strength, applied just once before mid-November.</p><p>At the same time, <strong>keep the plant far away from blasting heat vents, radiators, or drafty exterior doors</strong>. Central heating parches indoor air, <a href="https://www.tomsguide.com/home/gardening/peace-lily-tips-turning-brown-youre-probably-blaming-the-wrong-thing">turning leaf tips brown</a> and drying out fragile buds before they unfurl. </p><p>To boost humidity, <strong>set the pot on a wide tray filled with pebbles and water</strong>. As the water evaporates. it creates a pocket of moisture that mimics the tropical environment peace lilies need to push out their signature white blooms.</p></p>                </section><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-W0EdRO"></div>                            </div>                            <script src="https://kwizly.com/embed/W0EdRO.js" async=""></script><figure class="van-image-figure pull-right inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:676px;"><p class="vanilla-image-block" style="padding-top:31.51%;"><img id="ZCwuUFRE3YeboHR4zyEWmb" name="r3t8zZ5ve4GewFTeoCM3R6" alt="Google" src="https://cdn.mos.cms.futurecdn.net/ZCwuUFRE3YeboHR4zyEWmb-1920-80.jpg" mos="" align="right" fullscreen="" width="676" height="213" attribution="" endorsement="" class="pull-rightinline" /></p></div></div><figcaption itemprop="caption description" class="pull-right inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide </span></h3><ul><li><a href="https://www.tomsguide.com/home/gardening/why-are-my-peace-lily-leaves-turning-yellow-3-steps-to-bring-back-the-green">Why are my peace lily leaves turning yellow? 3 steps to bring back the green</a></li><li><a href="https://www.tomsguide.com/home/gardening/where-to-put-a-peace-lily-so-it-actually-flowers-5-ideal-spots-in-your-home">Where to put a peace lily so it actually flowers — 5 ideal spots in your home</a></li><li><a href="https://www.tomsguide.com/home/gardening/your-peace-lily-needs-dividing-if-you-see-these-signs-heres-how-to-do-it">Your peace lily needs dividing if you see these signs — here's how to do it</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tried the 'tarp burrito' method to clear leaves from my yard — and it's a game changer ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Just as you start to enjoy the fall colors of the leaves turning to charming shades of oranges, reds and yellows, they start dropping. And unfortunately, if you live near any trees, it's likely that those leaves are landing on your lawn.</p><p>Mine has become swamped in what feels like a matter of days and every year, I find myself with a rake and a dream hoping I can get the job done as quickly as possible.</p><p>But this year looks like it might go differently. I recently came across the 'tarp burrito', a hack that suggests that you can get your leaves cleaned up <em>fast</em>. So, I had to give it a try – and I have to say I was very surprised with the results.</p><h2 id="how-does-it-work">How does it work?</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@theblowmaster/video/7434234506036383007" data-video-id="7434234506036383007" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@theblowmaster" href="https://www.tiktok.com/@theblowmaster">@theblowmaster</a>                            <p></p><a target="_blank" title="♬ original sound - Blow Master" href="https://www.tiktok.com/music/original-sound-7434234446305430302">♬ original sound - Blow Master</a></section>                    </blockquote></div>                <p>On TikTok, <a href="https://www.tiktok.com/@theblowmaster" target="_blank" rel="nofollow">@theblowmaster</a> shares 'landscape industry secrets' to his over 40k followers. But it's his 'tarp burrito' method that caught my eye. While I've followed the <a href="https://www.tomsguide.com/how-to/how-to-rake-leaves">7 tips and tricks to raking leaves the easy way</a>, one of which is using a tarp to load up your leaves, I never thought to try this.</p><p>It's simple. Once you've laid your tarp out, you need to tie up the one end in a knot to securely hold your leaves. He explains: "That way, when you carry it, it folds up like a burrito." He then demonstrates dragging it along the lawn, exclaiming: "You see? It's not going anywhere."</p><div class="product"><a data-dimension112="bc004f76-ce02-11f1-a878-2b60ad60bd80" data-action="Deal Block" data-label="6ft x 8ft Waterproof Tarp" data-dimension48="6ft x 8ft Waterproof Tarp" data-dimension25="$9.99" href="https://www.amazon.com/CARTMAN-Waterproof-Multipurpose-Protective-Emergency/dp/B0BTLZBWQK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="aqnPkkTpA6ETvLYfCbZiYj" name="tarp_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/aqnPkkTpA6ETvLYfCbZiYj-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/CARTMAN-Waterproof-Multipurpose-Protective-Emergency/dp/B0BTLZBWQK" target="_blank" rel="nofollow" data-dimension112="bc004f76-ce02-11f1-a878-2b60ad60bd80" data-action="Deal Block" data-label="6ft x 8ft Waterproof Tarp" data-dimension48="6ft x 8ft Waterproof Tarp" data-dimension25="$9.99">6ft x 8ft Waterproof Tarp: $9.99</a></strong><br />This dustproof and waterproof tarp is ideal for lots of outdoor jobs, especially in harsher weather conditions. All four sides of the tarp are heat-sealed and folded, meaning it's both rip and tear proof. Perfect for garden chores like clearing up leaves or covering up outdoor furniture.<a class="view-deal button" href="https://www.amazon.com/CARTMAN-Waterproof-Multipurpose-Protective-Emergency/dp/B0BTLZBWQK" target="_blank" rel="nofollow" data-dimension112="bc004f76-ce02-11f1-a878-2b60ad60bd80" data-action="Deal Block" data-label="6ft x 8ft Waterproof Tarp" data-dimension48="6ft x 8ft Waterproof Tarp" data-dimension25="$9.99">View Deal</a></p></div><h2 id="here-39-s-what-happened-when-i-tried-it">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="vTQnB4C9ULXrf2LxT9vNnk" name="tarpburrito_2" alt="Laying out a tarp on a lawn and tying up one end" src="https://cdn.mos.cms.futurecdn.net/vTQnB4C9ULXrf2LxT9vNnk-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Thankfully, I already had a tarp ready to use (after a good shake of spiders from the garage). But, if you don't have one already, it'll only cost you around $10 to pick one up.</p><p>Firstly, I laid the tarp out flat on my lawn so that I could rake all the leaves onto it. And as I started to collect leaves, I realized the wind was working against me. So, I weighed down two corners and decided to tie up my 'tarp burrito' straight away so that I'd stop losing the leaves out the back.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="y6XwwvDarvMgK9r3xzCZnk" name="tarpburrito_3" alt="The end of a tarp tied up securely" src="https://cdn.mos.cms.futurecdn.net/y6XwwvDarvMgK9r3xzCZnk-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>It actually worked surprisingly well, keeping the leaves secure as I moved between the waste and compost bin. I also have side access to my house, so I was able to pull the 'tarp burrito' all the way round to the front of my house to gather more leaves on the front yard. </p><p>While I was concerned that tying up the ends would be difficult with the stiffness of the tarp, if anything it worked better. Sure, I still lost some leaves because it was a windy day, but I figure I'd have lost a lot more if I hadn't tried out this hack.</p><p>I'd recommend attaching a peg or two or tying up the knot with a rubber band to fully secure it if you're going to be moving the tarp around a lot. But, for a simple leaf clear up on my lawn, it certainly does the job. I'll be using it again every year.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><strong></strong><a href="https://www.tomsguide.com/home/how-to-remove-leaf-stains-from-concrete-no-vinegar-required"><strong>How to remove leaf stains from concrete — no vinegar required</strong></a><strong></strong></li><li><strong></strong><a href=""><strong>Don’t clear those fallen leaves: The free fall hack that stops weeds in their tracks</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/opinion/i-used-four-different-tools-to-get-rid-of-leaves-heres-what-worked-best"><strong>I used four different tools to get rid of leaves in my yard, and this is the one I recommend</strong></a><strong></strong></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/i-tried-the-tarp-burrito-method-to-clear-leaves-from-my-yard-and-its-a-game-changer</link>
                                                                            <description>
                            <![CDATA[ The fall leaves look lovely on the trees, but not so lovely when they start to swamp your entire yard. Here's what happened when I tried making a 'tarp burrito' to clear up my lawn. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">yCX9JYjvthDG3mBN7MQmTb</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/baf83uCjUfihnuMTZ9Hpnk-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 28 Oct 2026 06:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/baf83uCjUfihnuMTZ9Hpnk-1920-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Laying out a tarp on a lawn]]></media:description>                                                            <media:text><![CDATA[Laying out a tarp on a lawn]]></media:text>
                                <media:title type="plain"><![CDATA[Laying out a tarp on a lawn]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/baf83uCjUfihnuMTZ9Hpnk-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Just as you start to enjoy the fall colors of the leaves turning to charming shades of oranges, reds and yellows, they start dropping. And unfortunately, if you live near any trees, it's likely that those leaves are landing on your lawn.</p><p>Mine has become swamped in what feels like a matter of days and every year, I find myself with a rake and a dream hoping I can get the job done as quickly as possible.</p><p>But this year looks like it might go differently. I recently came across the 'tarp burrito', a hack that suggests that you can get your leaves cleaned up <em>fast</em>. So, I had to give it a try – and I have to say I was very surprised with the results.</p><h2 id="how-does-it-work">How does it work?</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@theblowmaster/video/7434234506036383007" data-video-id="7434234506036383007" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@theblowmaster" href="https://www.tiktok.com/@theblowmaster">@theblowmaster</a>                            <p></p><a target="_blank" title="♬ original sound - Blow Master" href="https://www.tiktok.com/music/original-sound-7434234446305430302">♬ original sound - Blow Master</a></section>                    </blockquote></div>                <p>On TikTok, <a href="https://www.tiktok.com/@theblowmaster" target="_blank" rel="nofollow">@theblowmaster</a> shares 'landscape industry secrets' to his over 40k followers. But it's his 'tarp burrito' method that caught my eye. While I've followed the <a href="https://www.tomsguide.com/how-to/how-to-rake-leaves">7 tips and tricks to raking leaves the easy way</a>, one of which is using a tarp to load up your leaves, I never thought to try this.</p><p>It's simple. Once you've laid your tarp out, you need to tie up the one end in a knot to securely hold your leaves. He explains: "That way, when you carry it, it folds up like a burrito." He then demonstrates dragging it along the lawn, exclaiming: "You see? It's not going anywhere."</p><div class="product"><a data-dimension112="bc004f76-ce02-11f1-a878-2b60ad60bd80" data-action="Deal Block" data-label="6ft x 8ft Waterproof Tarp" data-dimension48="6ft x 8ft Waterproof Tarp" data-dimension25="$9.99" href="https://www.amazon.com/CARTMAN-Waterproof-Multipurpose-Protective-Emergency/dp/B0BTLZBWQK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="aqnPkkTpA6ETvLYfCbZiYj" name="tarp_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/aqnPkkTpA6ETvLYfCbZiYj-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/CARTMAN-Waterproof-Multipurpose-Protective-Emergency/dp/B0BTLZBWQK" target="_blank" rel="nofollow" data-dimension112="bc004f76-ce02-11f1-a878-2b60ad60bd80" data-action="Deal Block" data-label="6ft x 8ft Waterproof Tarp" data-dimension48="6ft x 8ft Waterproof Tarp" data-dimension25="$9.99">6ft x 8ft Waterproof Tarp: $9.99</a></strong><br />This dustproof and waterproof tarp is ideal for lots of outdoor jobs, especially in harsher weather conditions. All four sides of the tarp are heat-sealed and folded, meaning it's both rip and tear proof. Perfect for garden chores like clearing up leaves or covering up outdoor furniture.<a class="view-deal button" href="https://www.amazon.com/CARTMAN-Waterproof-Multipurpose-Protective-Emergency/dp/B0BTLZBWQK" target="_blank" rel="nofollow" data-dimension112="bc004f76-ce02-11f1-a878-2b60ad60bd80" data-action="Deal Block" data-label="6ft x 8ft Waterproof Tarp" data-dimension48="6ft x 8ft Waterproof Tarp" data-dimension25="$9.99">View Deal</a></p></div><h2 id="here-39-s-what-happened-when-i-tried-it">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="vTQnB4C9ULXrf2LxT9vNnk" name="tarpburrito_2" alt="Laying out a tarp on a lawn and tying up one end" src="https://cdn.mos.cms.futurecdn.net/vTQnB4C9ULXrf2LxT9vNnk-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Thankfully, I already had a tarp ready to use (after a good shake of spiders from the garage). But, if you don't have one already, it'll only cost you around $10 to pick one up.</p><p>Firstly, I laid the tarp out flat on my lawn so that I could rake all the leaves onto it. And as I started to collect leaves, I realized the wind was working against me. So, I weighed down two corners and decided to tie up my 'tarp burrito' straight away so that I'd stop losing the leaves out the back.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="y6XwwvDarvMgK9r3xzCZnk" name="tarpburrito_3" alt="The end of a tarp tied up securely" src="https://cdn.mos.cms.futurecdn.net/y6XwwvDarvMgK9r3xzCZnk-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>It actually worked surprisingly well, keeping the leaves secure as I moved between the waste and compost bin. I also have side access to my house, so I was able to pull the 'tarp burrito' all the way round to the front of my house to gather more leaves on the front yard. </p><p>While I was concerned that tying up the ends would be difficult with the stiffness of the tarp, if anything it worked better. Sure, I still lost some leaves because it was a windy day, but I figure I'd have lost a lot more if I hadn't tried out this hack.</p><p>I'd recommend attaching a peg or two or tying up the knot with a rubber band to fully secure it if you're going to be moving the tarp around a lot. But, for a simple leaf clear up on my lawn, it certainly does the job. I'll be using it again every year.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><strong></strong><a href="https://www.tomsguide.com/home/how-to-remove-leaf-stains-from-concrete-no-vinegar-required"><strong>How to remove leaf stains from concrete — no vinegar required</strong></a><strong></strong></li><li><strong></strong><a href=""><strong>Don’t clear those fallen leaves: The free fall hack that stops weeds in their tracks</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/opinion/i-used-four-different-tools-to-get-rid-of-leaves-heres-what-worked-best"><strong>I used four different tools to get rid of leaves in my yard, and this is the one I recommend</strong></a><strong></strong></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I got rid of my fruit flies with this easy $5 DIY trick using 3 common household items ]]></title>
                                                                                                <dc:content><![CDATA[ <p>I've been having a battle with fruit flies. In my home, we eat a lot of bananas and I also like to make sure some of them ripen fully so I can bake up a loaf of banana bread (or two). </p><p>But with bananas on the countertop, I've also had an influx of fruit fly visitors that are not welcome in my home.</p><p>There are plenty of reasons fruit flies can turn up in your home, including buildup in your drains, unwashed trash in your bins, and crumbs and food scraps you might not have noticed. </p><p>Whatever it is, I'm on a mission to find a way to get rid of fruit flies, and social media has brought me an answer.</p><p>While I've tried <a href="https://www.tomsguide.com/home/i-tested-3-different-diy-fruit-fly-traps-this-3-ingredient-build-worked-best">3 different DIY fruit fly traps</a> with varying results, I recently came across a hack I'd never seen before that I just <em>had</em> to try. It also helped that I had all the ingredients already in my home. </p><p>Spoiler alert: I've been very surprised by the results.</p><h2 id="how-does-it-work-2">How does it work?</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@jeffandlaurenshow/video/7386733116112506154" data-video-id="7386733116112506154" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@jeffandlaurenshow" href="https://www.tiktok.com/@jeffandlaurenshow">@jeffandlaurenshow</a>                            <p></p><a target="_blank" title="♬ Flor Sin Retorno - Pedro Infante" href="https://www.tiktok.com/music/Flor-Sin-Retorno-6758190348750571521">♬ Flor Sin Retorno - Pedro Infante</a></section>                    </blockquote></div>                <p>TikTok pair, <a href="https://www.tiktok.com/@jeffandlaurenshow?lang=en" target="_blank" rel="nofollow">@jeffandlaurenshow</a>, share wildly varied from food hacks to home organization to their 2 million followers. But, they're also really great at sharing DIY pest control hacks that require minimum effort.</p><p>And for their DIY fruit fly trap, all you need is a lidded mason jar, apple cider vinegar and some dish soap. To save on costs, you can also easily recycle any old food jar you have, rather than buying a new one.</p><p><strong>To follow this hack, carry out these five simple steps:</strong></p><ul><li><strong>Poke several holes in the lid of the mason jar</strong></li><li><strong>Add around a cup of apple cider vinegar</strong></li><li><strong>Add a couple of squirts of dish soap</strong></li><li><strong>Swirl the mixture around in the jar</strong></li><li><strong>Place the jar wherever you notice the fruit flies</strong></li></ul><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="MWhX2Nb4rWkvSNFhaRHvEN" name="fruitflyhack_2" alt="Holes made in the lid of a mason jar" src="https://cdn.mos.cms.futurecdn.net/MWhX2Nb4rWkvSNFhaRHvEN-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>It's important to note that you should be very careful when poking the holes in your mason jar lid (as I quickly learned). </p><p>While you can use a hammer and nail, screwdriver or power drill, you also need to be careful of the sharp edges that remain on the lid. I opted for the power drill as it tends to leave the cleanest holes.</p><p>It's also worth noting that fruit flies are a lot smaller than regular flies, so if you're worried that the holes are <em>too</em> small, don't be.</p><div class="product"><a data-dimension112="4e94247c-cd39-11f1-8ac2-3b2577c34657" data-action="Deal Block" data-label="Organic Raw Apple Cider Vinegar" data-dimension48="Organic Raw Apple Cider Vinegar" data-dimension25="$3.99" href="https://www.amazon.com/365-Everyday-Value-Organic-Vinegar/dp/B07NRSPWL2/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="zHVCMbJcJKesYoLKNJHZKk" name="apple_cider_vinegar_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/zHVCMbJcJKesYoLKNJHZKk-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/365-Everyday-Value-Organic-Vinegar/dp/B07NRSPWL2/" target="_blank" rel="nofollow" data-dimension112="4e94247c-cd39-11f1-8ac2-3b2577c34657" data-action="Deal Block" data-label="Organic Raw Apple Cider Vinegar" data-dimension48="Organic Raw Apple Cider Vinegar" data-dimension25="$3.99">Organic Raw Apple Cider Vinegar: $3.99</a></strong><br />There's plenty of uses for apple cider vinegar from cleaning to drinking it, so this 16 fl oz bottle will come in handy for a lot more than just DIY fruit fly traps. From Whole Foods Market, you'll also get an apple cider vinegar that's organic, non-GMO, kosher and vegan certified.<a class="view-deal button" href="https://www.amazon.com/365-Everyday-Value-Organic-Vinegar/dp/B07NRSPWL2/" target="_blank" rel="nofollow" data-dimension112="4e94247c-cd39-11f1-8ac2-3b2577c34657" data-action="Deal Block" data-label="Organic Raw Apple Cider Vinegar" data-dimension48="Organic Raw Apple Cider Vinegar" data-dimension25="$3.99">View Deal</a></p></div><h2 id="here-39-s-what-happened-when-i-tried-it-2">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="m3hZcQ3pKeHKGBkSETvnEN" name="fruitflyhack_4" alt="Pouring dish soap into a jar of apple cider vinegar" src="https://cdn.mos.cms.futurecdn.net/m3hZcQ3pKeHKGBkSETvnEN-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>To complete this hack, I picked up a bottle of apple cider vinegar, fairly cheap at my local grocery store. I already had an old jam jar to clean out and dish soap at home, so it only cost me around $5 to put this DIY fruit fly trap together.</p><p>After a failed attempt with a screwdriver to make the holes, I recruited my husband and his power drill to make them for me neatly instead. </p><p>Then, all I had to do was simply add about a cup of apple cider vinegar, as well as a couple of generous squirts of dish soap.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="8sJ3JThXAAvdJ6f6JDF3FN" name="fruitflyhack_5" alt="A jar of dish soap and apple cider vinegar on a windowsill next to two plants" src="https://cdn.mos.cms.futurecdn.net/8sJ3JThXAAvdJ6f6JDF3FN-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>After replacing the lid and agitating the mixture, I placed the DIY fruit fly trap onto my windowsill directly above where I keep the bananas. I'll be honest, my expectations were low for this one as I've already had several failed attempts at getting rid of the fruit flies in my kitchen. But, I was happy to give it a go since it took me less than a minute to do and cost me very little.</p><p>I left it overnight and returned in the morning to find that the mixture had caught not one, not two, but what appeared to be three fruit flies. At first, I thought it had failed as the mixture was pretty cloudy, but after a swirl around it uncovered the truth – it had worked! </p><p>I feel like I don't get to say that a lot about DIY hacks, but with it's safe to say with this one I've been pleasantly surprised.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/my-kitchen-was-suddenly-swarming-with-fruit-flies-this-dish-soap-trick-saved-my-sanity">This 2-ingredient dish soap spray kills fruit flies instantly</a></li><li><a href="https://www.tomsguide.com/home/how-to-banish-fruit-flies-with-apple-cider-vinegar-and-prevent-them-from-coming-back">How to banish fruit flies with apple cider vinegar — and prevent them from coming back</a></li><li><a href="https://www.tomsguide.com/home/ive-got-a-fly-infestation-heres-the-hack-i-found-to-tackle-the-problem-for-good">I've got a fly infestation — here's the hack I found to tackle the problem for good</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/i-got-rid-of-my-fruit-flies-with-this-easy-usd5-diy-trick-using-3-common-household-items</link>
                                                                            <description>
                            <![CDATA[ This clever fruit fly hack is not only simple and affordable, but after trying it out, I can vouch that it's also incredibly effective. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">cMHQqXkybReqNkJQ6Jj2zF</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/tAxF5ar2Q6ZaKqxVjgGgyM-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 26 Oct 2026 06:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/tAxF5ar2Q6ZaKqxVjgGgyM-1920-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Apple cider vinegar, dish soap and a mason jar on a countertop]]></media:description>                                                            <media:text><![CDATA[Apple cider vinegar, dish soap and a mason jar on a countertop]]></media:text>
                                <media:title type="plain"><![CDATA[Apple cider vinegar, dish soap and a mason jar on a countertop]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/tAxF5ar2Q6ZaKqxVjgGgyM-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I've been having a battle with fruit flies. In my home, we eat a lot of bananas and I also like to make sure some of them ripen fully so I can bake up a loaf of banana bread (or two). </p><p>But with bananas on the countertop, I've also had an influx of fruit fly visitors that are not welcome in my home.</p><p>There are plenty of reasons fruit flies can turn up in your home, including buildup in your drains, unwashed trash in your bins, and crumbs and food scraps you might not have noticed. </p><p>Whatever it is, I'm on a mission to find a way to get rid of fruit flies, and social media has brought me an answer.</p><p>While I've tried <a href="https://www.tomsguide.com/home/i-tested-3-different-diy-fruit-fly-traps-this-3-ingredient-build-worked-best">3 different DIY fruit fly traps</a> with varying results, I recently came across a hack I'd never seen before that I just <em>had</em> to try. It also helped that I had all the ingredients already in my home. </p><p>Spoiler alert: I've been very surprised by the results.</p><h2 id="how-does-it-work-2">How does it work?</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@jeffandlaurenshow/video/7386733116112506154" data-video-id="7386733116112506154" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@jeffandlaurenshow" href="https://www.tiktok.com/@jeffandlaurenshow">@jeffandlaurenshow</a>                            <p></p><a target="_blank" title="♬ Flor Sin Retorno - Pedro Infante" href="https://www.tiktok.com/music/Flor-Sin-Retorno-6758190348750571521">♬ Flor Sin Retorno - Pedro Infante</a></section>                    </blockquote></div>                <p>TikTok pair, <a href="https://www.tiktok.com/@jeffandlaurenshow?lang=en" target="_blank" rel="nofollow">@jeffandlaurenshow</a>, share wildly varied from food hacks to home organization to their 2 million followers. But, they're also really great at sharing DIY pest control hacks that require minimum effort.</p><p>And for their DIY fruit fly trap, all you need is a lidded mason jar, apple cider vinegar and some dish soap. To save on costs, you can also easily recycle any old food jar you have, rather than buying a new one.</p><p><strong>To follow this hack, carry out these five simple steps:</strong></p><ul><li><strong>Poke several holes in the lid of the mason jar</strong></li><li><strong>Add around a cup of apple cider vinegar</strong></li><li><strong>Add a couple of squirts of dish soap</strong></li><li><strong>Swirl the mixture around in the jar</strong></li><li><strong>Place the jar wherever you notice the fruit flies</strong></li></ul><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="MWhX2Nb4rWkvSNFhaRHvEN" name="fruitflyhack_2" alt="Holes made in the lid of a mason jar" src="https://cdn.mos.cms.futurecdn.net/MWhX2Nb4rWkvSNFhaRHvEN-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>It's important to note that you should be very careful when poking the holes in your mason jar lid (as I quickly learned). </p><p>While you can use a hammer and nail, screwdriver or power drill, you also need to be careful of the sharp edges that remain on the lid. I opted for the power drill as it tends to leave the cleanest holes.</p><p>It's also worth noting that fruit flies are a lot smaller than regular flies, so if you're worried that the holes are <em>too</em> small, don't be.</p><div class="product"><a data-dimension112="4e94247c-cd39-11f1-8ac2-3b2577c34657" data-action="Deal Block" data-label="Organic Raw Apple Cider Vinegar" data-dimension48="Organic Raw Apple Cider Vinegar" data-dimension25="$3.99" href="https://www.amazon.com/365-Everyday-Value-Organic-Vinegar/dp/B07NRSPWL2/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="zHVCMbJcJKesYoLKNJHZKk" name="apple_cider_vinegar_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/zHVCMbJcJKesYoLKNJHZKk-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/365-Everyday-Value-Organic-Vinegar/dp/B07NRSPWL2/" target="_blank" rel="nofollow" data-dimension112="4e94247c-cd39-11f1-8ac2-3b2577c34657" data-action="Deal Block" data-label="Organic Raw Apple Cider Vinegar" data-dimension48="Organic Raw Apple Cider Vinegar" data-dimension25="$3.99">Organic Raw Apple Cider Vinegar: $3.99</a></strong><br />There's plenty of uses for apple cider vinegar from cleaning to drinking it, so this 16 fl oz bottle will come in handy for a lot more than just DIY fruit fly traps. From Whole Foods Market, you'll also get an apple cider vinegar that's organic, non-GMO, kosher and vegan certified.<a class="view-deal button" href="https://www.amazon.com/365-Everyday-Value-Organic-Vinegar/dp/B07NRSPWL2/" target="_blank" rel="nofollow" data-dimension112="4e94247c-cd39-11f1-8ac2-3b2577c34657" data-action="Deal Block" data-label="Organic Raw Apple Cider Vinegar" data-dimension48="Organic Raw Apple Cider Vinegar" data-dimension25="$3.99">View Deal</a></p></div><h2 id="here-39-s-what-happened-when-i-tried-it-2">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="m3hZcQ3pKeHKGBkSETvnEN" name="fruitflyhack_4" alt="Pouring dish soap into a jar of apple cider vinegar" src="https://cdn.mos.cms.futurecdn.net/m3hZcQ3pKeHKGBkSETvnEN-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>To complete this hack, I picked up a bottle of apple cider vinegar, fairly cheap at my local grocery store. I already had an old jam jar to clean out and dish soap at home, so it only cost me around $5 to put this DIY fruit fly trap together.</p><p>After a failed attempt with a screwdriver to make the holes, I recruited my husband and his power drill to make them for me neatly instead. </p><p>Then, all I had to do was simply add about a cup of apple cider vinegar, as well as a couple of generous squirts of dish soap.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="8sJ3JThXAAvdJ6f6JDF3FN" name="fruitflyhack_5" alt="A jar of dish soap and apple cider vinegar on a windowsill next to two plants" src="https://cdn.mos.cms.futurecdn.net/8sJ3JThXAAvdJ6f6JDF3FN-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>After replacing the lid and agitating the mixture, I placed the DIY fruit fly trap onto my windowsill directly above where I keep the bananas. I'll be honest, my expectations were low for this one as I've already had several failed attempts at getting rid of the fruit flies in my kitchen. But, I was happy to give it a go since it took me less than a minute to do and cost me very little.</p><p>I left it overnight and returned in the morning to find that the mixture had caught not one, not two, but what appeared to be three fruit flies. At first, I thought it had failed as the mixture was pretty cloudy, but after a swirl around it uncovered the truth – it had worked! </p><p>I feel like I don't get to say that a lot about DIY hacks, but with it's safe to say with this one I've been pleasantly surprised.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/my-kitchen-was-suddenly-swarming-with-fruit-flies-this-dish-soap-trick-saved-my-sanity">This 2-ingredient dish soap spray kills fruit flies instantly</a></li><li><a href="https://www.tomsguide.com/home/how-to-banish-fruit-flies-with-apple-cider-vinegar-and-prevent-them-from-coming-back">How to banish fruit flies with apple cider vinegar — and prevent them from coming back</a></li><li><a href="https://www.tomsguide.com/home/ive-got-a-fly-infestation-heres-the-hack-i-found-to-tackle-the-problem-for-good">I've got a fly infestation — here's the hack I found to tackle the problem for good</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ How can I tell if my lawn is compacted? Here’s what the garden experts say (and how to fix it) ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Fall weather may be upon us, but that doesn’t mean our lawncare duties should go into hibernation just yet. In fact, now is the time to tend to our lawns and ensure they’re in good shape come spring.</p><p>And if you’ve noticed that your once lush lawn is looking patchy, soggy, or generally in bad condition, it could point to compacted soil. Essentially, this is when pressure or certain weight squeezes soil particles together. This thick layer blocks any water, essential nutrients, or air from getting into the roots — affecting healthy growth. </p><p>But how do you know? And more importantly, what can you do to repair it? To help solve this dilemma, I asked the garden experts to share the key signs of compacted soil, how to test for it, and the best ways to fix it this fall.</p><h2 id="1-water-sits-on-your-lawn">1. Water sits on your lawn</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:998px;"><p class="vanilla-image-block" style="padding-top:56.21%;"><img id="wwdCGn8dXtKSbRwizsUB2n" name="waterlogged grass.jpg" alt="Waterlogged grass" src="https://cdn.mos.cms.futurecdn.net/wwdCGn8dXtKSbRwizsUB2n-1920-80.jpg" mos="" align="middle" fullscreen="" width="998" height="561" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Waterlogged grass </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Puddles or standing water on your lawn clearly indicate compacted soil underneath. This is because tightly packed ground prevents proper drainage, which can lead to waterlogging, patchy spots, and root disease.</p><p>“One of the clearest signs is water sitting on the surface after rain,” states Chris Bonnett, the founder of <a href="https://www.gardeningexpress.co.uk/" target="_blank">GardeningExpress</a>. </p><p>“If puddles take a long time to drain, it could indicate that compacted soil is preventing water from soaking into the ground properly.</p><p>The first step to fix this is to aerate the soil (making holes) to allow it to breathe. Typically, there are two types of aerators – spike and core aerators. </p><p>Spike aerators literally have long spikes that puncture the ground as you pass over it, while core aerators pull up ‘cores’ of soil as they work, leaving them on the surface. </p><p>“If the lawn is badly compacted, a hollow-tine aerator, which removes small plugs of soil and removes the pressure from the soil, may be more effective,” advises Alex Dobson, garden and outdoor space expert at<a href="https://www.charlesandivy.co.uk/" target="_blank"> Charles &amp; Ivy</a>. </p><p>“For smaller gardens, use a garden fork to make holes across the affected areas, gently rocking it backwards and forwards to open up the soil.” </p><p>Just avoid aerating when the ground is very wet or frozen, as this could make waterlogging worse. If in doubt, check out<a href="https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best"> </a>these expert tips on<a href="https://www.tomsguide.com/home/lawn-care/can-i-aerate-a-wet-lawn-heres-what-a-grass-expert-says"> aerating a wet lawn</a>.</p><h3 class="article-body__section" id="section-2-the-ground-feels-hard"><span>2. The ground feels hard</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5990px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="FjNxqndRp3GRZ7XyLTRMJU" name="Standing on lawn - crop.jpg" alt="Shoes on frosty lawn" src="https://cdn.mos.cms.futurecdn.net/FjNxqndRp3GRZ7XyLTRMJU-1920-80.jpg" mos="" align="middle" fullscreen="" width="5990" height="3369" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Shoes on frosty lawn </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>As well as the ground feeling squishy to walk on, you might also encounter a hardened surface. This is especially during the colder fall months.</p><p>“You may also notice that the ground feels unusually hard, grass growth has become thin, or moss and algae are appearing in persistently damp areas,” adds Bonnett.</p><p>So how do I check for this? Luckily, there is a simple way to check for compaction before you aerate. “A simple way to check is to push a screwdriver or garden fork into the soil when it is slightly moist. If it is difficult to penetrate the ground, particularly in areas where people regularly walk, compaction could be the issue.”</p><p>“Fall is a good time to do this, as long as the ground isn’t waterlogged. You can also overseed bare patches to encourage fresh growth. Try to avoid walking on the lawn when it’s wet too, as this can make compaction worse.” </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OKyEoe"></div>                            </div>                            <script src="https://kwizly.com/embed/OKyEoe.js" async=""></script><h3 class="article-body__section" id="section-3-the-grass-is-thin-or-patchy"><span>3. The grass is thin or patchy</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="4epvvvNMkhGqBND75MaTv5" name="shutterstock_2233794845edit" alt="Patchy lawn" src="https://cdn.mos.cms.futurecdn.net/4epvvvNMkhGqBND75MaTv5-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Patchy lawn </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Another clear warning sign is when your once-lush lawn starts to turn sparse and patchy. When soil becomes heavily compacted, grass roots are starved of essential air and water, making it nearly impossible for your lawn to thrive.</p><p>One way to fix this is to overseed your lawn. But before sprinkling more grass seed or lawn feed, you’ll need to check and deal with compacted soil first. </p><p>“For lawns with bare patches, overseeding can help the grass fill in once the soil has been improved and conditions are suitable for new growth,” advises Dobson. “If water continues to collect in the same spots, you may also need to look at the garden's drainage rather than relying on aeration alone”.</p><p>“Once you've aerated the lawn, try to avoid repeatedly walking over the same areas, particularly when the ground is wet. You can also add stepping stones to the lawn to help prevent the soil from becoming compacted again.” </p><p>So if you’ve spotted any of these warning signs on your lawn, the key thing is to loosen the soil and reduce pressure on the grass. Once these issues are fixed immediately, you’ll have lush and healthy grass all year round.</p><p>For more top tips, check out<a href="https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best"> how often you should aerate your lawn and how many passes are best</a>.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-common-lawn-care-mistakes-you-are-probably-making-right-now">7 common lawn care mistakes you’re probably making right now</a></li><li><a href="https://www.tomsguide.com/how-to/9-ways-to-get-the-most-out-of-your-lawn-mower">9 ways to get the most out of your lawn mower</a></li><li><a href="https://www.tomsguide.com/how-to/5-plants-that-will-keep-wasps-out-of-your-yard">5 plants that will keep wasps out of your yard</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/lawn-care/how-can-i-tell-if-my-lawn-is-compacted-heres-what-the-garden-experts-say-and-how-to-fix-it</link>
                                                                            <description>
                            <![CDATA[ I asked grass experts how to tell if my lawn is compacted. Here are the telltale signs and what you can do to fix it. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">5GjN2ytRMNBnWhPKQ2y6PE</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Dzg3UWE9aBJfJQ7KEfxNUW-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 24 Oct 2026 06:30:00 +0000</pubDate>                                                                                                                                <updated>Sat, 24 Oct 2026 12:20:28 +0000</updated>
                                                                                                                                            <category><![CDATA[Lawn Care]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                                    <dc:creator><![CDATA[ Cynthia Lawrence ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/4hFvAy3JvgCJamhKf5KoPU-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/Dzg3UWE9aBJfJQ7KEfxNUW-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A core aerator being used to aerate a lawn]]></media:description>                                                            <media:text><![CDATA[A core aerator being used to aerate a lawn]]></media:text>
                                <media:title type="plain"><![CDATA[A core aerator being used to aerate a lawn]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Dzg3UWE9aBJfJQ7KEfxNUW-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Fall weather may be upon us, but that doesn’t mean our lawncare duties should go into hibernation just yet. In fact, now is the time to tend to our lawns and ensure they’re in good shape come spring.</p><p>And if you’ve noticed that your once lush lawn is looking patchy, soggy, or generally in bad condition, it could point to compacted soil. Essentially, this is when pressure or certain weight squeezes soil particles together. This thick layer blocks any water, essential nutrients, or air from getting into the roots — affecting healthy growth. </p><p>But how do you know? And more importantly, what can you do to repair it? To help solve this dilemma, I asked the garden experts to share the key signs of compacted soil, how to test for it, and the best ways to fix it this fall.</p><h2 id="1-water-sits-on-your-lawn">1. Water sits on your lawn</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:998px;"><p class="vanilla-image-block" style="padding-top:56.21%;"><img id="wwdCGn8dXtKSbRwizsUB2n" name="waterlogged grass.jpg" alt="Waterlogged grass" src="https://cdn.mos.cms.futurecdn.net/wwdCGn8dXtKSbRwizsUB2n-1920-80.jpg" mos="" align="middle" fullscreen="" width="998" height="561" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Waterlogged grass </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Puddles or standing water on your lawn clearly indicate compacted soil underneath. This is because tightly packed ground prevents proper drainage, which can lead to waterlogging, patchy spots, and root disease.</p><p>“One of the clearest signs is water sitting on the surface after rain,” states Chris Bonnett, the founder of <a href="https://www.gardeningexpress.co.uk/" target="_blank">GardeningExpress</a>. </p><p>“If puddles take a long time to drain, it could indicate that compacted soil is preventing water from soaking into the ground properly.</p><p>The first step to fix this is to aerate the soil (making holes) to allow it to breathe. Typically, there are two types of aerators – spike and core aerators. </p><p>Spike aerators literally have long spikes that puncture the ground as you pass over it, while core aerators pull up ‘cores’ of soil as they work, leaving them on the surface. </p><p>“If the lawn is badly compacted, a hollow-tine aerator, which removes small plugs of soil and removes the pressure from the soil, may be more effective,” advises Alex Dobson, garden and outdoor space expert at<a href="https://www.charlesandivy.co.uk/" target="_blank"> Charles &amp; Ivy</a>. </p><p>“For smaller gardens, use a garden fork to make holes across the affected areas, gently rocking it backwards and forwards to open up the soil.” </p><p>Just avoid aerating when the ground is very wet or frozen, as this could make waterlogging worse. If in doubt, check out<a href="https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best"> </a>these expert tips on<a href="https://www.tomsguide.com/home/lawn-care/can-i-aerate-a-wet-lawn-heres-what-a-grass-expert-says"> aerating a wet lawn</a>.</p><h3 class="article-body__section" id="section-2-the-ground-feels-hard"><span>2. The ground feels hard</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5990px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="FjNxqndRp3GRZ7XyLTRMJU" name="Standing on lawn - crop.jpg" alt="Shoes on frosty lawn" src="https://cdn.mos.cms.futurecdn.net/FjNxqndRp3GRZ7XyLTRMJU-1920-80.jpg" mos="" align="middle" fullscreen="" width="5990" height="3369" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Shoes on frosty lawn </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>As well as the ground feeling squishy to walk on, you might also encounter a hardened surface. This is especially during the colder fall months.</p><p>“You may also notice that the ground feels unusually hard, grass growth has become thin, or moss and algae are appearing in persistently damp areas,” adds Bonnett.</p><p>So how do I check for this? Luckily, there is a simple way to check for compaction before you aerate. “A simple way to check is to push a screwdriver or garden fork into the soil when it is slightly moist. If it is difficult to penetrate the ground, particularly in areas where people regularly walk, compaction could be the issue.”</p><p>“Fall is a good time to do this, as long as the ground isn’t waterlogged. You can also overseed bare patches to encourage fresh growth. Try to avoid walking on the lawn when it’s wet too, as this can make compaction worse.” </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OKyEoe"></div>                            </div>                            <script src="https://kwizly.com/embed/OKyEoe.js" async=""></script><h3 class="article-body__section" id="section-3-the-grass-is-thin-or-patchy"><span>3. The grass is thin or patchy</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="4epvvvNMkhGqBND75MaTv5" name="shutterstock_2233794845edit" alt="Patchy lawn" src="https://cdn.mos.cms.futurecdn.net/4epvvvNMkhGqBND75MaTv5-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Patchy lawn </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Another clear warning sign is when your once-lush lawn starts to turn sparse and patchy. When soil becomes heavily compacted, grass roots are starved of essential air and water, making it nearly impossible for your lawn to thrive.</p><p>One way to fix this is to overseed your lawn. But before sprinkling more grass seed or lawn feed, you’ll need to check and deal with compacted soil first. </p><p>“For lawns with bare patches, overseeding can help the grass fill in once the soil has been improved and conditions are suitable for new growth,” advises Dobson. “If water continues to collect in the same spots, you may also need to look at the garden's drainage rather than relying on aeration alone”.</p><p>“Once you've aerated the lawn, try to avoid repeatedly walking over the same areas, particularly when the ground is wet. You can also add stepping stones to the lawn to help prevent the soil from becoming compacted again.” </p><p>So if you’ve spotted any of these warning signs on your lawn, the key thing is to loosen the soil and reduce pressure on the grass. Once these issues are fixed immediately, you’ll have lush and healthy grass all year round.</p><p>For more top tips, check out<a href="https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best"> how often you should aerate your lawn and how many passes are best</a>.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-common-lawn-care-mistakes-you-are-probably-making-right-now">7 common lawn care mistakes you’re probably making right now</a></li><li><a href="https://www.tomsguide.com/how-to/9-ways-to-get-the-most-out-of-your-lawn-mower">9 ways to get the most out of your lawn mower</a></li><li><a href="https://www.tomsguide.com/how-to/5-plants-that-will-keep-wasps-out-of-your-yard">5 plants that will keep wasps out of your yard</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Want to lower your energy bills this season? A heating expert shares these 5 checks you need to do right now ]]></title>
                                                                                                <dc:content><![CDATA[ <p>As the weather drops, we all start asking ourselves: "Is it time to put the heating on?" And after months of not needing it, it's also when you might realize that your heating isn't doing as efficient a job as it was the year before. </p><p>I should know, my husband's a heating engineer and it's around the same time each year that his phone doesn't stop ringing with people wanting to know why their house isn't warming up like it used to.</p><p>But, before you call in a professional, there's a few things you can do around your home to make sure your property isn't losing heat – and they're pretty simple to do <em>and</em> fairly inexpensive. Add in the fact that you could also be saving yourself money on heating bills in the long term and this should become part of your fall/winter routine.</p><h2 id="1-use-a-sheet-of-paper-to-identify-gaps">1. Use a sheet of paper to identify gaps</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:8081px;"><p class="vanilla-image-block" style="padding-top:54.55%;"><img id="Gbq9N2xmDUaesw2mzacVJ4" name="shutterstock_2219885693ex.jpg" alt="Woman draught proofing a window with plastic sealing strip" src="https://cdn.mos.cms.futurecdn.net/Gbq9N2xmDUaesw2mzacVJ4-1920-80.jpg" mos="" align="middle" fullscreen="" width="8081" height="4408" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>As Kaitlin Wood, Senior Category Manager for Bathrooms, Plumbing, Heating and Renewables at<a href="https://www.travisperkins.co.uk/" target="_blank"> Travis Perkins</a> says: "Homeowners often focus on their boiler or thermostat when preparing for winter, but heat can also escape through small gaps and poorly insulated areas around the property."</p><p>And one really important place to check is your windows. Fortunately, you can do so with just a simple strip of paper. All you have to do is place it between an open window and its frame before closing the window and locking it. If you can remove the paper once it's closed with little resistance, there's clearly an issue with the seal around the window. </p><p>You should check this in several places around the window to ensure <em>where</em> the problem is, and once you've identified the problem, you can use draught-proofing strips around the windows to fix it.</p><p>Though it's important to identify what the issue actually is, too. Whether it's a worn seal, a misaligned window, damaged hinges or a gap around the outer frame. "A joiner or window fitter can establish whether the window needs a replacement seal, an adjustment, or a more substantial repair, helping homeowners avoid applying a product that is unsuitable for the window," advises Rob Haddock, Senior Group Commercial Category Manager at Travis Perkins.</p><h2 id="2-check-your-attic">2. Check your attic</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4492px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="xeD8pEkNPRiwj45bgT8k7V" name="Loft insulation.jpg" alt="Loft insulation" src="https://cdn.mos.cms.futurecdn.net/xeD8pEkNPRiwj45bgT8k7V-1920-80.jpg" mos="" align="middle" fullscreen="" width="4492" height="2527" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>If your attic is anything like mine, it's a place where I store the things I don't need all year round, from seasonal clothing and decorations to suitcases and memorabilia. But storing all this up in the attic might actually be causing a problem for your heating.</p><p>All these <a href="https://www.tomsguide.com/home/you-dont-need-another-plastic-box-these-3-reusable-items-are-totally-free-and-ideal-for-storage">storage boxes</a> and/or boards might be impacting the effectiveness of your attic's insulation by compressing it or pushing it to the sides. So, head into your attic with a tape measure and check the depth in areas of high storage against empty spots to assess. You'll need to check the climate zone, but it'll range between 10 and 24 inches.</p><p>Haddock says: "Adding more insulation will not necessarily solve the problem if it is then compressed beneath boxes or loft boards. Raising boarding can provide storage space while allowing the insulation underneath to retain its intended depth."</p><p>He advises: "Damp Insulation, insulation damaged by pests, or covering electrical equipment should not simply be topped up. An experienced installer can assess its condition, ventilation and coverages before recommending the correct improvement."</p><p>And it's also worth checking your attic door while you're up there for any visible signs of gaps, whether that's a noticeable draft, movement, or light shining through.</p><h2 id="3-assess-your-radiators">3. Assess your radiators</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4972px;"><p class="vanilla-image-block" style="padding-top:56.32%;"><img id="PCHPva3JYdytiD8xrHNms8" name="shutterstock_2250293501ex.jpg" alt="Woman placed both hands on a radiator to feel the heat" src="https://cdn.mos.cms.futurecdn.net/PCHPva3JYdytiD8xrHNms8-1920-80.jpg" mos="" align="middle" fullscreen="" width="4972" height="2800" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>You don't have to be a heating engineer to run a quick check on your radiators to see if the heat is being distributed evenly. Instead, do it yourself and then you can identify whether you need to call in an expert. </p><p>Place your hands gently on the radiator (being careful of heat). If you're feeling coolness at the top of a radiator, but heat at the bottom, coolness throughout, or a radiator that heats very slowly compared to others, than you might have a bigger problem. </p><p>Wood explains: "Uneven heat is a symptom rather than a full diagnosis. Turning up the thermostat could make other rooms unnecessarily warm without resolving the original problem. A heating engineer can determine whether the radiator contains trapped air or whether there is a problem elsewhere in the system."</p><h2 id="5-insulate-exposed-pipes">5. Insulate exposed pipes</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4161px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="9FvdzK4eMu8x4u9zdQh5C7" name="Pipes.jpg" alt="Insulated pipes on a valve" src="https://cdn.mos.cms.futurecdn.net/9FvdzK4eMu8x4u9zdQh5C7-1920-80.jpg" mos="" align="middle" fullscreen="" width="4161" height="2341" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>It's worth checking throughout your home and especially in unheated spaces like your loft and garage for pipes that may be exposed as they could be susceptible to freezing or condensation during the colder months.</p><p>Once you've identified these pipes, it's possible to buy pipe insulation and slip over straight pipe runs with self-sealing adhesive, but you may want to call in a plumber to help you identify and treat the pipes, as well as ensuring that valves, controls and components are still exposed for access.</p><p>It's also worth noting that if you identify heating or hot water pipes that these need to be switched off and cooled fully before handling.  </p><div class="product"><a data-dimension112="2a9bcaf6-cb7d-11f1-9f6b-d36b36a2207c" data-action="Deal Block" data-label="6-Pack Foam Pipe Covers" data-dimension48="6-Pack Foam Pipe Covers" data-dimension25="$10.90" href="https://www.amazon.com/Duck-Brand-Insulation-Sealing-Adhesive/dp/B0CJXFLQV5" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="FaVv6wYJu9oiZfgH2xD78n" name="foam_pipes_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/FaVv6wYJu9oiZfgH2xD78n-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Duck-Brand-Insulation-Sealing-Adhesive/dp/B0CJXFLQV5" target="_blank" rel="nofollow" data-dimension112="2a9bcaf6-cb7d-11f1-9f6b-d36b36a2207c" data-action="Deal Block" data-label="6-Pack Foam Pipe Covers" data-dimension48="6-Pack Foam Pipe Covers" data-dimension25="$10.90">6-Pack Foam Pipe Covers: $10.90</a></strong><br />These pipe insulation foam tubes are for both hot and cold water pipes around your home. They're pre-slit and have a self-sealing adhesive edge to make covering up your pipes and securing the heat a whole lot easier. With these pack, you get 6, 12-inch foam pipe sticks.<a class="view-deal button" href="https://www.amazon.com/Duck-Brand-Insulation-Sealing-Adhesive/dp/B0CJXFLQV5" target="_blank" rel="nofollow" data-dimension112="2a9bcaf6-cb7d-11f1-9f6b-d36b36a2207c" data-action="Deal Block" data-label="6-Pack Foam Pipe Covers" data-dimension48="6-Pack Foam Pipe Covers" data-dimension25="$10.90">View Deal</a></p></div><h2 id="5-do-a-full-draft-check">5. Do a full draft check</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4971px;"><p class="vanilla-image-block" style="padding-top:54.56%;"><img id="D2Stv3DBaQxxbaV5LGVBjh" name="shutterstock_1943020753ex.jpg" alt="Painted baseboard and door in sage green" src="https://cdn.mos.cms.futurecdn.net/D2Stv3DBaQxxbaV5LGVBjh-1920-80.jpg" mos="" align="middle" fullscreen="" width="4971" height="2712" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>While checking your windows is the most obvious place for drafts in a property, there's a few other spots you should also be paying attention to. These include floorboards, baseboards, around pipework and fireplaces. </p><p>Small gaps can be treated with the appropriate filler, with research and expert guidance, but if you identify any larger gaps or openings you think shouldn't be there, it's time to call in an expert. Spotting them could be just what you need to reduce those heating bills in the long run.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/5-ways-to-winterize-your-home-and-save-money-on-your-energy-bills">5 ways to winterize your home and save money on your energy bills</a></li><li><a href="https://www.tomsguide.com/home/winter-brings-3-types-of-damp-heres-how-to-spot-and-treat-them-before-they-spread">Winter brings 3 types of damp — here's how to spot and treat them before they spread</a></li><li><a href="https://www.tomsguide.com/how-to/7-ways-to-winterize-your-pipes">7 ways to winterize your pipes and stop them from bursting</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/want-to-lower-your-energy-bills-this-season-a-heating-expert-shares-these-5-checks-you-need-to-do-right-now</link>
                                                                            <description>
                            <![CDATA[ Getting your home ready for winter doesn't have to be complicated. It also doesn't have to be expensive. These five simple steps will ensure your home retains heat rather than losing it. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">3ga7vwGxmaCbQ5b7VMpCb9</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/grAs7q8TzqQzWVX8GwbNPV-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 20 Oct 2026 07:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/grAs7q8TzqQzWVX8GwbNPV-1920-80.jpg">
                                                            <media:credit><![CDATA[Getty Images]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A woman with dark brown hair and wearing a red jumper turns up the heating via her smart thermostat just before going to bed, which is a big nighttime routine mistake]]></media:description>                                                            <media:text><![CDATA[A woman with dark brown hair and wearing a red jumper turns up the heating via her smart thermostat just before going to bed, which is a big nighttime routine mistake]]></media:text>
                                <media:title type="plain"><![CDATA[A woman with dark brown hair and wearing a red jumper turns up the heating via her smart thermostat just before going to bed, which is a big nighttime routine mistake]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/grAs7q8TzqQzWVX8GwbNPV-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As the weather drops, we all start asking ourselves: "Is it time to put the heating on?" And after months of not needing it, it's also when you might realize that your heating isn't doing as efficient a job as it was the year before. </p><p>I should know, my husband's a heating engineer and it's around the same time each year that his phone doesn't stop ringing with people wanting to know why their house isn't warming up like it used to.</p><p>But, before you call in a professional, there's a few things you can do around your home to make sure your property isn't losing heat – and they're pretty simple to do <em>and</em> fairly inexpensive. Add in the fact that you could also be saving yourself money on heating bills in the long term and this should become part of your fall/winter routine.</p><h2 id="1-use-a-sheet-of-paper-to-identify-gaps">1. Use a sheet of paper to identify gaps</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:8081px;"><p class="vanilla-image-block" style="padding-top:54.55%;"><img id="Gbq9N2xmDUaesw2mzacVJ4" name="shutterstock_2219885693ex.jpg" alt="Woman draught proofing a window with plastic sealing strip" src="https://cdn.mos.cms.futurecdn.net/Gbq9N2xmDUaesw2mzacVJ4-1920-80.jpg" mos="" align="middle" fullscreen="" width="8081" height="4408" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>As Kaitlin Wood, Senior Category Manager for Bathrooms, Plumbing, Heating and Renewables at<a href="https://www.travisperkins.co.uk/" target="_blank"> Travis Perkins</a> says: "Homeowners often focus on their boiler or thermostat when preparing for winter, but heat can also escape through small gaps and poorly insulated areas around the property."</p><p>And one really important place to check is your windows. Fortunately, you can do so with just a simple strip of paper. All you have to do is place it between an open window and its frame before closing the window and locking it. If you can remove the paper once it's closed with little resistance, there's clearly an issue with the seal around the window. </p><p>You should check this in several places around the window to ensure <em>where</em> the problem is, and once you've identified the problem, you can use draught-proofing strips around the windows to fix it.</p><p>Though it's important to identify what the issue actually is, too. Whether it's a worn seal, a misaligned window, damaged hinges or a gap around the outer frame. "A joiner or window fitter can establish whether the window needs a replacement seal, an adjustment, or a more substantial repair, helping homeowners avoid applying a product that is unsuitable for the window," advises Rob Haddock, Senior Group Commercial Category Manager at Travis Perkins.</p><h2 id="2-check-your-attic">2. Check your attic</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4492px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="xeD8pEkNPRiwj45bgT8k7V" name="Loft insulation.jpg" alt="Loft insulation" src="https://cdn.mos.cms.futurecdn.net/xeD8pEkNPRiwj45bgT8k7V-1920-80.jpg" mos="" align="middle" fullscreen="" width="4492" height="2527" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>If your attic is anything like mine, it's a place where I store the things I don't need all year round, from seasonal clothing and decorations to suitcases and memorabilia. But storing all this up in the attic might actually be causing a problem for your heating.</p><p>All these <a href="https://www.tomsguide.com/home/you-dont-need-another-plastic-box-these-3-reusable-items-are-totally-free-and-ideal-for-storage">storage boxes</a> and/or boards might be impacting the effectiveness of your attic's insulation by compressing it or pushing it to the sides. So, head into your attic with a tape measure and check the depth in areas of high storage against empty spots to assess. You'll need to check the climate zone, but it'll range between 10 and 24 inches.</p><p>Haddock says: "Adding more insulation will not necessarily solve the problem if it is then compressed beneath boxes or loft boards. Raising boarding can provide storage space while allowing the insulation underneath to retain its intended depth."</p><p>He advises: "Damp Insulation, insulation damaged by pests, or covering electrical equipment should not simply be topped up. An experienced installer can assess its condition, ventilation and coverages before recommending the correct improvement."</p><p>And it's also worth checking your attic door while you're up there for any visible signs of gaps, whether that's a noticeable draft, movement, or light shining through.</p><h2 id="3-assess-your-radiators">3. Assess your radiators</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4972px;"><p class="vanilla-image-block" style="padding-top:56.32%;"><img id="PCHPva3JYdytiD8xrHNms8" name="shutterstock_2250293501ex.jpg" alt="Woman placed both hands on a radiator to feel the heat" src="https://cdn.mos.cms.futurecdn.net/PCHPva3JYdytiD8xrHNms8-1920-80.jpg" mos="" align="middle" fullscreen="" width="4972" height="2800" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>You don't have to be a heating engineer to run a quick check on your radiators to see if the heat is being distributed evenly. Instead, do it yourself and then you can identify whether you need to call in an expert. </p><p>Place your hands gently on the radiator (being careful of heat). If you're feeling coolness at the top of a radiator, but heat at the bottom, coolness throughout, or a radiator that heats very slowly compared to others, than you might have a bigger problem. </p><p>Wood explains: "Uneven heat is a symptom rather than a full diagnosis. Turning up the thermostat could make other rooms unnecessarily warm without resolving the original problem. A heating engineer can determine whether the radiator contains trapped air or whether there is a problem elsewhere in the system."</p><h2 id="5-insulate-exposed-pipes">5. Insulate exposed pipes</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4161px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="9FvdzK4eMu8x4u9zdQh5C7" name="Pipes.jpg" alt="Insulated pipes on a valve" src="https://cdn.mos.cms.futurecdn.net/9FvdzK4eMu8x4u9zdQh5C7-1920-80.jpg" mos="" align="middle" fullscreen="" width="4161" height="2341" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>It's worth checking throughout your home and especially in unheated spaces like your loft and garage for pipes that may be exposed as they could be susceptible to freezing or condensation during the colder months.</p><p>Once you've identified these pipes, it's possible to buy pipe insulation and slip over straight pipe runs with self-sealing adhesive, but you may want to call in a plumber to help you identify and treat the pipes, as well as ensuring that valves, controls and components are still exposed for access.</p><p>It's also worth noting that if you identify heating or hot water pipes that these need to be switched off and cooled fully before handling.  </p><div class="product"><a data-dimension112="2a9bcaf6-cb7d-11f1-9f6b-d36b36a2207c" data-action="Deal Block" data-label="6-Pack Foam Pipe Covers" data-dimension48="6-Pack Foam Pipe Covers" data-dimension25="$10.90" href="https://www.amazon.com/Duck-Brand-Insulation-Sealing-Adhesive/dp/B0CJXFLQV5" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="FaVv6wYJu9oiZfgH2xD78n" name="foam_pipes_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/FaVv6wYJu9oiZfgH2xD78n-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Duck-Brand-Insulation-Sealing-Adhesive/dp/B0CJXFLQV5" target="_blank" rel="nofollow" data-dimension112="2a9bcaf6-cb7d-11f1-9f6b-d36b36a2207c" data-action="Deal Block" data-label="6-Pack Foam Pipe Covers" data-dimension48="6-Pack Foam Pipe Covers" data-dimension25="$10.90">6-Pack Foam Pipe Covers: $10.90</a></strong><br />These pipe insulation foam tubes are for both hot and cold water pipes around your home. They're pre-slit and have a self-sealing adhesive edge to make covering up your pipes and securing the heat a whole lot easier. With these pack, you get 6, 12-inch foam pipe sticks.<a class="view-deal button" href="https://www.amazon.com/Duck-Brand-Insulation-Sealing-Adhesive/dp/B0CJXFLQV5" target="_blank" rel="nofollow" data-dimension112="2a9bcaf6-cb7d-11f1-9f6b-d36b36a2207c" data-action="Deal Block" data-label="6-Pack Foam Pipe Covers" data-dimension48="6-Pack Foam Pipe Covers" data-dimension25="$10.90">View Deal</a></p></div><h2 id="5-do-a-full-draft-check">5. Do a full draft check</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4971px;"><p class="vanilla-image-block" style="padding-top:54.56%;"><img id="D2Stv3DBaQxxbaV5LGVBjh" name="shutterstock_1943020753ex.jpg" alt="Painted baseboard and door in sage green" src="https://cdn.mos.cms.futurecdn.net/D2Stv3DBaQxxbaV5LGVBjh-1920-80.jpg" mos="" align="middle" fullscreen="" width="4971" height="2712" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>While checking your windows is the most obvious place for drafts in a property, there's a few other spots you should also be paying attention to. These include floorboards, baseboards, around pipework and fireplaces. </p><p>Small gaps can be treated with the appropriate filler, with research and expert guidance, but if you identify any larger gaps or openings you think shouldn't be there, it's time to call in an expert. Spotting them could be just what you need to reduce those heating bills in the long run.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/5-ways-to-winterize-your-home-and-save-money-on-your-energy-bills">5 ways to winterize your home and save money on your energy bills</a></li><li><a href="https://www.tomsguide.com/home/winter-brings-3-types-of-damp-heres-how-to-spot-and-treat-them-before-they-spread">Winter brings 3 types of damp — here's how to spot and treat them before they spread</a></li><li><a href="https://www.tomsguide.com/how-to/7-ways-to-winterize-your-pipes">7 ways to winterize your pipes and stop them from bursting</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The 5-minute fall flood check every homeowner needs right now ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Depending on what region you live in, the risk of floods may be a real problem for you, especially in the colder months. Heavy rain can feel like its come out of nowhere, so it's best to be prepared.</p><p>While you can track rain patterns on weather apps and from regional news, it's a much better idea to get ahead of the weather entirely. </p><p>Instead, you should be doing any prep work <em>before</em> you're faced with flood warnings and predictions of heavy rain.</p><p>Fortunately, I've put together a 5-minute fall flood checklist that will help you prepare your home for a flood, hopefully preventing damage that'll take <em>a lot</em> longer to resolve.</p><p>After all, it's better to be ready even if the rain doesn't arrive than be caught out with a flood striking and creating hazards across your home.</p><h2 id="1-clear-gutters-and-downspouts">1. Clear gutters and downspouts</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2505px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WRcThTqD3Ei6LcBLtAT5Af" name="shutterstock_502279153.jpg" alt="Someone unblocking leaves from a gutter while wearing gloves" src="https://cdn.mos.cms.futurecdn.net/WRcThTqD3Ei6LcBLtAT5Af-1920-80.jpg" mos="" align="middle" fullscreen="" width="2505" height="1409" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Fall is the perfect season for your gutters and downspouts to get clogged up. Why? Well, with falling leaves and extra rain, it can concoct the ultimate mulch that will easily block the area. It's also a great breeding ground for moss to gather, too.</p><p>Grab a sturdy ladder with someone spotting you or a stabilizer at the bottom, then using a bucket and gloves, remove all the packed debris, leaves and moss that's blocking up your gutters. You should do this once or twice during the fall, especially around November and December as that's when most trees lose their leaves.</p><h2 id="2-trim-down-nearby-trees-and-shrubs">2. Trim down nearby trees and shrubs</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="AFJpRohosf8wm4w6yKbQ5c" name="shutterstock_2603983387" alt="Shrub wrapped in plant fleece" src="https://cdn.mos.cms.futurecdn.net/AFJpRohosf8wm4w6yKbQ5c-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Around your home, you may have nearby trees and shrubs that are your responsibility to trim down to prevent excessive foliage falling to the ground – and, as already discussed, into your gutters. This can also cause a problem for any exterior drains you have. </p><p>So, you should prune back trees and shrubs to minimize the amounts of leaves and loose branches that pose a risk to your home. If you let everything fall to the ground or into your gutters, you're increasing the chances that rain won't drain properly away from your property.</p><h2 id="3-survey-for-cracks-and-gaps">3. Survey for cracks and gaps</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4520px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="ZdBtSMFjYXo8iVU4LdMJ2b" name="shutterstock_2426483225.jpg" alt="Cracks in the foundations of a house" src="https://cdn.mos.cms.futurecdn.net/ZdBtSMFjYXo8iVU4LdMJ2b-1920-80.jpg" mos="" align="middle" fullscreen="" width="4520" height="2543" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>It won't take you long at all to do a perimeter walk of your home to check for any cracks or gaps in the exterior walls, so make sure you do. If you spot any, grab some waterproof sealants or fillers to close up any gaps and cracks to prevent any water getting through. </p><p>You may need to widen any small gaps to ensure the sealants or fillers hold or call in a professional if you find anything especially bad. Hairline cracks that are less than 1/16 of an inch though are generally considered cosmetic, so you can leave these alone. But, it's important to note down where they are and keep an eye on them incase they get any worse.</p><h2 id="4-test-your-sump-pump">4. Test your sump pump</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3600px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="m3EqjFxJ85h33Q3RdYbrZk" name="shutterstock_2273745883 moving boxes in a wooden hallway" alt="moving boxes in a wooden hallway" src="https://cdn.mos.cms.futurecdn.net/m3EqjFxJ85h33Q3RdYbrZk-1920-80.jpg" mos="" align="middle" fullscreen="" width="3600" height="2025" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Not all homes have sump pumps, but if you have one in your basement, you should incorporate testing it into your 5-minute fall flood home check. Simply pour water (around one or two 5-gallon buckets worth, or run a hose) into the pit to test that the float switch is working and that the pump then activates and drains the water out of the basin. </p><p>Then, confirm that the water level has fully dropped back down to the bottom and that the sump pump has turned off. You'll most likely be able to listen for this as the motor will stop running. </p><p>With your sump pump in order, basement flooding risk can be greatly reduced, and the need for a dehumidifier.</p><div class="product"><a data-dimension112="7310a112-c70e-11f1-8c39-17f1b1ba0648" data-action="Deal Block" data-label="Smart 50-Pint Dehumidifier" data-dimension48="Smart 50-Pint Dehumidifier" data-dimension25="$229" href="https://www.amazon.com/dp/B0BR7RHQB9?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1001px;"><p class="vanilla-image-block" style="padding-top:90.71%;"><img id="6US8NePiDMogTgzAyXZm9F" name="Goveelife" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/6US8NePiDMogTgzAyXZm9F-1920-80.png" mos="" align="middle" fullscreen="" width="1001" height="908" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0BR7RHQB9?" target="_blank" rel="nofollow" data-dimension112="7310a112-c70e-11f1-8c39-17f1b1ba0648" data-action="Deal Block" data-label="Smart 50-Pint Dehumidifier" data-dimension48="Smart 50-Pint Dehumidifier" data-dimension25="$229">Smart 50-Pint Dehumidifier: was $299 now $229</a></strong><br />We gave <a href="https://www.tomsguide.com/home/home-appliances/goveelife-smart-50-pint-dehumidifier-review">GoveeLife's 50-pint dehumidifier</a> a 4-star review, which is why we recommend it as the top product in our <a href="https://www.tomsguide.com/home/home-appliances/best-dehumidifiers">best dehumidifier buying guide</a>. It’s a powerful appliance that can handle large spaces (up to 4,500 square feet), and for ease of use, it can be controlled through an app. <a class="view-deal button" href="https://www.amazon.com/dp/B0BR7RHQB9?" target="_blank" rel="nofollow" data-dimension112="7310a112-c70e-11f1-8c39-17f1b1ba0648" data-action="Deal Block" data-label="Smart 50-Pint Dehumidifier" data-dimension48="Smart 50-Pint Dehumidifier" data-dimension25="$229">View Deal</a></p></div><h2 id="5-move-belongings-to-a-higher-place">5. Move belongings to a higher place</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5175px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="iBBAaFHUBbd77eDj39EggW" name="attic space ctop.jpg" alt="Attic storage" src="https://cdn.mos.cms.futurecdn.net/iBBAaFHUBbd77eDj39EggW-1920-80.jpg" mos="" align="middle" fullscreen="" width="5175" height="2911" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Even after all your home checks, you may still want to protect your valuables from any risk of floods and to do that, you can quickly move anything of value to the highest floor of your home or even the attic. </p><p>Of course, you don't need to live with your valuables up high at all times, but if you receive a warning from the National Weather Service or hear of any extreme weather, you should at least have a plan in place about what you choose to move.</p><p>You might also be interested in <a href="https://www.tomsguide.com/home/gardening/the-gardeners-guide-to-surviving-heavy-storms-and-waterlogged-lawns" target="_blank" rel="nofollow">the gardener’s guide to surviving heavy storms and waterlogged lawns.</a></p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/lawn-care/3-expert-approved-tasks-you-must-do-in-october-to-get-your-yard-ready-for-fall">3 expert-approved tasks you must do in October to get your yard ready for fall</a></li><li><a href="https://www.tomsguide.com/home/ways-to-protect-your-lawn-from-flooding">5 ways to protect your lawn from flooding — tips from garden experts</a></li><li><a href="https://www.tomsguide.com/home/smart-home/7-security-steps-to-prepare-your-home-before-you-leave-your-for-the-holidays">7 security steps to prepare your home before you leave your for the holidays</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/the-5-minute-fall-flood-check-every-homeowner-needs-right-now</link>
                                                                            <description>
                            <![CDATA[ Protecting your home before the bad weather hits is an important task that can often be forgotten about. Fortunately, you only need 5 minutes to work through this simple checklist. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">hFVLa74HA4pwyTysH4QrpC</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/oQCH2KZVo4CU38CUbCftBT-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 19 Oct 2026 07:00:00 +0000</pubDate>                                                                                                                                <updated>Thu, 29 Oct 2026 11:28:33 +0000</updated>
                                                                                                                                            <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/oQCH2KZVo4CU38CUbCftBT-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Heavy rain on leaves]]></media:description>                                                            <media:text><![CDATA[Heavy rain on leaves]]></media:text>
                                <media:title type="plain"><![CDATA[Heavy rain on leaves]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/oQCH2KZVo4CU38CUbCftBT-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Depending on what region you live in, the risk of floods may be a real problem for you, especially in the colder months. Heavy rain can feel like its come out of nowhere, so it's best to be prepared.</p><p>While you can track rain patterns on weather apps and from regional news, it's a much better idea to get ahead of the weather entirely. </p><p>Instead, you should be doing any prep work <em>before</em> you're faced with flood warnings and predictions of heavy rain.</p><p>Fortunately, I've put together a 5-minute fall flood checklist that will help you prepare your home for a flood, hopefully preventing damage that'll take <em>a lot</em> longer to resolve.</p><p>After all, it's better to be ready even if the rain doesn't arrive than be caught out with a flood striking and creating hazards across your home.</p><h2 id="1-clear-gutters-and-downspouts">1. Clear gutters and downspouts</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2505px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WRcThTqD3Ei6LcBLtAT5Af" name="shutterstock_502279153.jpg" alt="Someone unblocking leaves from a gutter while wearing gloves" src="https://cdn.mos.cms.futurecdn.net/WRcThTqD3Ei6LcBLtAT5Af-1920-80.jpg" mos="" align="middle" fullscreen="" width="2505" height="1409" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Fall is the perfect season for your gutters and downspouts to get clogged up. Why? Well, with falling leaves and extra rain, it can concoct the ultimate mulch that will easily block the area. It's also a great breeding ground for moss to gather, too.</p><p>Grab a sturdy ladder with someone spotting you or a stabilizer at the bottom, then using a bucket and gloves, remove all the packed debris, leaves and moss that's blocking up your gutters. You should do this once or twice during the fall, especially around November and December as that's when most trees lose their leaves.</p><h2 id="2-trim-down-nearby-trees-and-shrubs">2. Trim down nearby trees and shrubs</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="AFJpRohosf8wm4w6yKbQ5c" name="shutterstock_2603983387" alt="Shrub wrapped in plant fleece" src="https://cdn.mos.cms.futurecdn.net/AFJpRohosf8wm4w6yKbQ5c-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Around your home, you may have nearby trees and shrubs that are your responsibility to trim down to prevent excessive foliage falling to the ground – and, as already discussed, into your gutters. This can also cause a problem for any exterior drains you have. </p><p>So, you should prune back trees and shrubs to minimize the amounts of leaves and loose branches that pose a risk to your home. If you let everything fall to the ground or into your gutters, you're increasing the chances that rain won't drain properly away from your property.</p><h2 id="3-survey-for-cracks-and-gaps">3. Survey for cracks and gaps</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4520px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="ZdBtSMFjYXo8iVU4LdMJ2b" name="shutterstock_2426483225.jpg" alt="Cracks in the foundations of a house" src="https://cdn.mos.cms.futurecdn.net/ZdBtSMFjYXo8iVU4LdMJ2b-1920-80.jpg" mos="" align="middle" fullscreen="" width="4520" height="2543" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>It won't take you long at all to do a perimeter walk of your home to check for any cracks or gaps in the exterior walls, so make sure you do. If you spot any, grab some waterproof sealants or fillers to close up any gaps and cracks to prevent any water getting through. </p><p>You may need to widen any small gaps to ensure the sealants or fillers hold or call in a professional if you find anything especially bad. Hairline cracks that are less than 1/16 of an inch though are generally considered cosmetic, so you can leave these alone. But, it's important to note down where they are and keep an eye on them incase they get any worse.</p><h2 id="4-test-your-sump-pump">4. Test your sump pump</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3600px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="m3EqjFxJ85h33Q3RdYbrZk" name="shutterstock_2273745883 moving boxes in a wooden hallway" alt="moving boxes in a wooden hallway" src="https://cdn.mos.cms.futurecdn.net/m3EqjFxJ85h33Q3RdYbrZk-1920-80.jpg" mos="" align="middle" fullscreen="" width="3600" height="2025" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Not all homes have sump pumps, but if you have one in your basement, you should incorporate testing it into your 5-minute fall flood home check. Simply pour water (around one or two 5-gallon buckets worth, or run a hose) into the pit to test that the float switch is working and that the pump then activates and drains the water out of the basin. </p><p>Then, confirm that the water level has fully dropped back down to the bottom and that the sump pump has turned off. You'll most likely be able to listen for this as the motor will stop running. </p><p>With your sump pump in order, basement flooding risk can be greatly reduced, and the need for a dehumidifier.</p><div class="product"><a data-dimension112="7310a112-c70e-11f1-8c39-17f1b1ba0648" data-action="Deal Block" data-label="Smart 50-Pint Dehumidifier" data-dimension48="Smart 50-Pint Dehumidifier" data-dimension25="$229" href="https://www.amazon.com/dp/B0BR7RHQB9?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1001px;"><p class="vanilla-image-block" style="padding-top:90.71%;"><img id="6US8NePiDMogTgzAyXZm9F" name="Goveelife" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/6US8NePiDMogTgzAyXZm9F-1920-80.png" mos="" align="middle" fullscreen="" width="1001" height="908" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0BR7RHQB9?" target="_blank" rel="nofollow" data-dimension112="7310a112-c70e-11f1-8c39-17f1b1ba0648" data-action="Deal Block" data-label="Smart 50-Pint Dehumidifier" data-dimension48="Smart 50-Pint Dehumidifier" data-dimension25="$229">Smart 50-Pint Dehumidifier: was $299 now $229</a></strong><br />We gave <a href="https://www.tomsguide.com/home/home-appliances/goveelife-smart-50-pint-dehumidifier-review">GoveeLife's 50-pint dehumidifier</a> a 4-star review, which is why we recommend it as the top product in our <a href="https://www.tomsguide.com/home/home-appliances/best-dehumidifiers">best dehumidifier buying guide</a>. It’s a powerful appliance that can handle large spaces (up to 4,500 square feet), and for ease of use, it can be controlled through an app. <a class="view-deal button" href="https://www.amazon.com/dp/B0BR7RHQB9?" target="_blank" rel="nofollow" data-dimension112="7310a112-c70e-11f1-8c39-17f1b1ba0648" data-action="Deal Block" data-label="Smart 50-Pint Dehumidifier" data-dimension48="Smart 50-Pint Dehumidifier" data-dimension25="$229">View Deal</a></p></div><h2 id="5-move-belongings-to-a-higher-place">5. Move belongings to a higher place</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5175px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="iBBAaFHUBbd77eDj39EggW" name="attic space ctop.jpg" alt="Attic storage" src="https://cdn.mos.cms.futurecdn.net/iBBAaFHUBbd77eDj39EggW-1920-80.jpg" mos="" align="middle" fullscreen="" width="5175" height="2911" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Even after all your home checks, you may still want to protect your valuables from any risk of floods and to do that, you can quickly move anything of value to the highest floor of your home or even the attic. </p><p>Of course, you don't need to live with your valuables up high at all times, but if you receive a warning from the National Weather Service or hear of any extreme weather, you should at least have a plan in place about what you choose to move.</p><p>You might also be interested in <a href="https://www.tomsguide.com/home/gardening/the-gardeners-guide-to-surviving-heavy-storms-and-waterlogged-lawns" target="_blank" rel="nofollow">the gardener’s guide to surviving heavy storms and waterlogged lawns.</a></p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/lawn-care/3-expert-approved-tasks-you-must-do-in-october-to-get-your-yard-ready-for-fall">3 expert-approved tasks you must do in October to get your yard ready for fall</a></li><li><a href="https://www.tomsguide.com/home/ways-to-protect-your-lawn-from-flooding">5 ways to protect your lawn from flooding — tips from garden experts</a></li><li><a href="https://www.tomsguide.com/home/smart-home/7-security-steps-to-prepare-your-home-before-you-leave-your-for-the-holidays">7 security steps to prepare your home before you leave your for the holidays</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Can I aerate a wet lawn? Here’s what a grass expert says ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Fall is here, and it’s already taken its toll on my once-lush,<a href="https://www.tomsguide.com/how-to/how-to-make-grass-greener"> green grass</a>. But before the weather turns too chilly, October provides the perfect opportunity to repair damaged lawns and prepare them for the winter months ahead.</p><p>And one essential task is to aerate your lawn to prevent waterlogging and ensure key nutrients reach the soil. However, with constant drizzles and damp conditions expected throughout the fall season, is it okay to aerate a wet lawn? </p><p>I asked a lawn care expert to find out and get their top tips.</p><h2 id="can-i-aerate-a-wet-lawn">Can I aerate a wet lawn?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:998px;"><p class="vanilla-image-block" style="padding-top:56.21%;"><img id="wwdCGn8dXtKSbRwizsUB2n" name="waterlogged grass.jpg" alt="Waterlogged grass" src="https://cdn.mos.cms.futurecdn.net/wwdCGn8dXtKSbRwizsUB2n-1920-80.jpg" mos="" align="middle" fullscreen="" width="998" height="561" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Waterlogged grass </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Generally, you can aerate a slightly damp lawn but not when it’s saturated with heavy rain — so it’s important to distinguish between the two.</p><p>“A simple rule is that damp is fine, soggy isn’t — if water is standing on the surface or the tines come out coated in sticky mud, wait a few days,” states Jonathan Davis, lawn care expert at<a href="https://www.lawnsmith.co.uk/" target="_blank"> <u>Lawnsmith</u></a>.</p><p>“Spring and fall are the best times to aerate partly because the soil is moist, which makes it easier to get the tines in, and showers can soak straight into the freshly aerated soil. What you don’t want is soil that’s so wet it smears. Then you’re not opening up the soil; you’re sealing it, and you still want air reaching the roots.”</p><h3 class="article-body__section" id="section-top-tips-for-aerating-a-damp-lawn"><span>Top tips for aerating a damp lawn</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5972px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Dzg3UWE9aBJfJQ7KEfxNUW" name="Aerate.jpg" alt="A core aerator being used to aerate a lawn" src="https://cdn.mos.cms.futurecdn.net/Dzg3UWE9aBJfJQ7KEfxNUW-1920-80.jpg" mos="" align="middle" fullscreen="" width="5972" height="3359" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">A core aerator being used to aerate a lawn </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>What's the best way to aerate a damp lawn in fall? While there are several ways to aerate your lawn, it’s important to choose the right tool in fall.  </p><p>Typically, there are two types of aerators – spike and core aerators. Spike aerators literally have long spikes that puncture the ground as you pass over it, while core aerators pull up ‘cores’ of soil as they work, leaving them on the surface.  </p><p>“If the ground is on the damp side, solid-tine spiking is the gentlest approach, and you can do it any time from March to November, but avoid very wet soil that smears,” advises Davis.</p><p>You’ll also need to know the right time to aerate your lawn and best practices. “Fall, from the end of September to mid-November, is ideal as the weather is getting wetter rather than drier,” suggests Davis. “If you’re using a hollow tine aerator, mow the lawn close beforehand as it makes the cores much easier to deal with. </p><p>“Cores should be left to dry in place. Then go over them with the mower with the box off, if the instructions allow. It puts the soil and nutrients back into the lawn and helps break down thatch. If you can’t do that, rake them up with the back of a flat rake, use them as top dressing, or add them to the compost heap.</p><p>Finally, finish with a good soak on compacted areas. After spiking or hollow tining a heavily compacted patch, run the sprinkler for 30 minutes, then leave it off for a day or two.</p><p>Also, look for <a href="https://www.tomsguide.com/how-to/7-signs-your-lawn-needs-aerating">telltale signs your lawn needs aerating</a>, including patchy, yellow grass or water sitting on the surface after rainfall.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OKyEoe"></div>                            </div>                            <script src="https://kwizly.com/embed/OKyEoe.js" async=""></script><h3 class="article-body__section" id="section-when-not-to-aerate-a-wet-lawn"><span>When not to aerate a wet lawn </span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3961px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WkN4ijGVZoAgGY8zPSTyQG" name="Blades of grass - crop.jpg" alt="Frost on grass blades" src="https://cdn.mos.cms.futurecdn.net/WkN4ijGVZoAgGY8zPSTyQG-1920-80.jpg" mos="" align="middle" fullscreen="" width="3961" height="2228" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Frost on grass blades </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Besides knowing when it's the right time to aerate wet soil, you should also know when to avoid it. This includes before incoming frost, which can freeze the aeration holes and harm the lawn.</p><p>“Don’t aerate very wet soil that smears, and don’t do it if frost is imminent because freezing soon after hollow tining will make the lawn heave up,” adds Davis. </p><p>“Don’t leave the cores on the lawn to disappear, as they won’t break down fully and you’ll end up with a bumpy surface. Finally, don’t expect aeration to fix everything. If your lawn is 20 years old or more and badly compacted, you may need to dig it over to at least 15cm and start again.”</p><p>For more top tips, check out<a href="https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best"> how often you should aerate your lawn and how many passes are best</a>.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-common-lawn-care-mistakes-you-are-probably-making-right-now">7 common lawn care mistakes you’re probably making right now</a></li><li><a href="https://www.tomsguide.com/how-to/9-ways-to-get-the-most-out-of-your-lawn-mower">9 ways to get the most out of your lawn mower</a></li><li><a href="https://www.tomsguide.com/how-to/5-plants-that-will-keep-wasps-out-of-your-yard">5 plants that will keep wasps out of your yard</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/lawn-care/can-i-aerate-a-wet-lawn-heres-what-a-grass-expert-says</link>
                                                                            <description>
                            <![CDATA[ Is it ever okay to aerate a wet lawn? I asked an expert what would happen and how to go about it the right way. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">ZjHfn6ieMTsNEsB7xJCTx5</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/m6YJdU6WSFb29KW7g9c5jS-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 18 Oct 2026 06:30:00 +0000</pubDate>                                                                                                                                <updated>Sun, 18 Oct 2026 12:34:42 +0000</updated>
                                                                                                                                            <category><![CDATA[Lawn Care]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                                    <dc:creator><![CDATA[ Cynthia Lawrence ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/4hFvAy3JvgCJamhKf5KoPU-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/m6YJdU6WSFb29KW7g9c5jS-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Someone aerating a lawn with a roller]]></media:description>                                                            <media:text><![CDATA[Someone aerating a lawn with a roller]]></media:text>
                                <media:title type="plain"><![CDATA[Someone aerating a lawn with a roller]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/m6YJdU6WSFb29KW7g9c5jS-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Fall is here, and it’s already taken its toll on my once-lush,<a href="https://www.tomsguide.com/how-to/how-to-make-grass-greener"> green grass</a>. But before the weather turns too chilly, October provides the perfect opportunity to repair damaged lawns and prepare them for the winter months ahead.</p><p>And one essential task is to aerate your lawn to prevent waterlogging and ensure key nutrients reach the soil. However, with constant drizzles and damp conditions expected throughout the fall season, is it okay to aerate a wet lawn? </p><p>I asked a lawn care expert to find out and get their top tips.</p><h2 id="can-i-aerate-a-wet-lawn">Can I aerate a wet lawn?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:998px;"><p class="vanilla-image-block" style="padding-top:56.21%;"><img id="wwdCGn8dXtKSbRwizsUB2n" name="waterlogged grass.jpg" alt="Waterlogged grass" src="https://cdn.mos.cms.futurecdn.net/wwdCGn8dXtKSbRwizsUB2n-1920-80.jpg" mos="" align="middle" fullscreen="" width="998" height="561" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Waterlogged grass </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Generally, you can aerate a slightly damp lawn but not when it’s saturated with heavy rain — so it’s important to distinguish between the two.</p><p>“A simple rule is that damp is fine, soggy isn’t — if water is standing on the surface or the tines come out coated in sticky mud, wait a few days,” states Jonathan Davis, lawn care expert at<a href="https://www.lawnsmith.co.uk/" target="_blank"> <u>Lawnsmith</u></a>.</p><p>“Spring and fall are the best times to aerate partly because the soil is moist, which makes it easier to get the tines in, and showers can soak straight into the freshly aerated soil. What you don’t want is soil that’s so wet it smears. Then you’re not opening up the soil; you’re sealing it, and you still want air reaching the roots.”</p><h3 class="article-body__section" id="section-top-tips-for-aerating-a-damp-lawn"><span>Top tips for aerating a damp lawn</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5972px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Dzg3UWE9aBJfJQ7KEfxNUW" name="Aerate.jpg" alt="A core aerator being used to aerate a lawn" src="https://cdn.mos.cms.futurecdn.net/Dzg3UWE9aBJfJQ7KEfxNUW-1920-80.jpg" mos="" align="middle" fullscreen="" width="5972" height="3359" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">A core aerator being used to aerate a lawn </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>What's the best way to aerate a damp lawn in fall? While there are several ways to aerate your lawn, it’s important to choose the right tool in fall.  </p><p>Typically, there are two types of aerators – spike and core aerators. Spike aerators literally have long spikes that puncture the ground as you pass over it, while core aerators pull up ‘cores’ of soil as they work, leaving them on the surface.  </p><p>“If the ground is on the damp side, solid-tine spiking is the gentlest approach, and you can do it any time from March to November, but avoid very wet soil that smears,” advises Davis.</p><p>You’ll also need to know the right time to aerate your lawn and best practices. “Fall, from the end of September to mid-November, is ideal as the weather is getting wetter rather than drier,” suggests Davis. “If you’re using a hollow tine aerator, mow the lawn close beforehand as it makes the cores much easier to deal with. </p><p>“Cores should be left to dry in place. Then go over them with the mower with the box off, if the instructions allow. It puts the soil and nutrients back into the lawn and helps break down thatch. If you can’t do that, rake them up with the back of a flat rake, use them as top dressing, or add them to the compost heap.</p><p>Finally, finish with a good soak on compacted areas. After spiking or hollow tining a heavily compacted patch, run the sprinkler for 30 minutes, then leave it off for a day or two.</p><p>Also, look for <a href="https://www.tomsguide.com/how-to/7-signs-your-lawn-needs-aerating">telltale signs your lawn needs aerating</a>, including patchy, yellow grass or water sitting on the surface after rainfall.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OKyEoe"></div>                            </div>                            <script src="https://kwizly.com/embed/OKyEoe.js" async=""></script><h3 class="article-body__section" id="section-when-not-to-aerate-a-wet-lawn"><span>When not to aerate a wet lawn </span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3961px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WkN4ijGVZoAgGY8zPSTyQG" name="Blades of grass - crop.jpg" alt="Frost on grass blades" src="https://cdn.mos.cms.futurecdn.net/WkN4ijGVZoAgGY8zPSTyQG-1920-80.jpg" mos="" align="middle" fullscreen="" width="3961" height="2228" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Frost on grass blades </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Besides knowing when it's the right time to aerate wet soil, you should also know when to avoid it. This includes before incoming frost, which can freeze the aeration holes and harm the lawn.</p><p>“Don’t aerate very wet soil that smears, and don’t do it if frost is imminent because freezing soon after hollow tining will make the lawn heave up,” adds Davis. </p><p>“Don’t leave the cores on the lawn to disappear, as they won’t break down fully and you’ll end up with a bumpy surface. Finally, don’t expect aeration to fix everything. If your lawn is 20 years old or more and badly compacted, you may need to dig it over to at least 15cm and start again.”</p><p>For more top tips, check out<a href="https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best"> how often you should aerate your lawn and how many passes are best</a>.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-common-lawn-care-mistakes-you-are-probably-making-right-now">7 common lawn care mistakes you’re probably making right now</a></li><li><a href="https://www.tomsguide.com/how-to/9-ways-to-get-the-most-out-of-your-lawn-mower">9 ways to get the most out of your lawn mower</a></li><li><a href="https://www.tomsguide.com/how-to/5-plants-that-will-keep-wasps-out-of-your-yard">5 plants that will keep wasps out of your yard</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Lawn expert urges gardeners to keep mowing this October — here's why ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Fall has arrived, but cooler temperatures don’t mean you should put away your garden tools just yet. You still have essential tasks to complete to <a href="https://www.tomsguide.com/home/lawn-care/3-expert-approved-tasks-you-must-do-in-october-to-get-your-yard-ready-for-fall">prepare your yard for the winter ahead</a>. And just when you thought it was time to pack away your lawn mower until spring, you may want to think again. </p><p>According to a lawn expert, gardeners need to continue mowing through October  — because mild fall temperatures allow grass to keep growing.</p><p>Not only can this simple task promote a healthy, green <a href="https://www.tomsguide.com/features/the-ultimate-lawn-care-guide-essential-tips-and-tricks-for-getting-the-perfect-lawn">lawn</a>, but long grass can actually do more harm than good. </p><p>“Long grass holds on to moisture, especially with the damp mornings and heavy dew we get in fall,” says Jonathan Davis, a lawn expert at <a href="https://www.lawnsmith.co.uk/" target="_blank">Lawnsmith</a>. </p><p>“That creates the perfect conditions for fungal diseases like red thread and fusarium patch to take hold. Once they get a grip, they can leave your lawn looking patchy and sorry for itself by spring.” </p><p>What’s more, <a href="https://www.tomsguide.com/how-to/5-ways-to-get-rid-of-moss">moss </a>is one of the most common lawn weeds, known as a ‘silent grass killer’, that appears in the form of green, sponge-like patches between the blades of grass. </p><p>“Moss loves damp, shady spots, and at this time of year there's plenty of both. If your grass is long and thick, the light can't reach the base of it, meaning your lawn will struggle.” </p><p>So if you want to get your lawn in top shape for spring, here are some top tips for mowing your lawn in October. </p><h2 id="how-to-cut-your-lawn-in-fall">How to cut your lawn in fall</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="sPsWcpJfaGgXoakPEySmPM" name="shutterstock_1585509538" alt="Lawn mower mulching fall leaves" src="https://cdn.mos.cms.futurecdn.net/sPsWcpJfaGgXoakPEySmPM-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">A man mowing the lawn  </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Avoid cutting your grass too short; the ‘golden rule’ is to never trim more than a third of its height. This is because mowing too close to the ground exposes the lawn to root diseases and encourages weed growth.</p><p>“Never cut more than a third off the height of the grass in one go,” he said. “Think of grass like an iceberg: a fifth above ground and four fifths below,” adds Davis.</p><p>“Take too much off, and you reduce the roots, leaving the plant weak and more vulnerable to disease and weeds.” </p><p>In any case, if you are battling weeds,<a href="https://www.tomsguide.com/home/gardening/i-asked-professional-gardeners-how-to-get-rid-of-weeds-from-my-lawn-permanently-and-they-all-say-this-one-thing"> I asked professional gardeners how to get rid of weeds from my lawn permanently — and they all say this one thing.</a></p><p>In addition, Davis advises gradually changing your mower's height for a couple of cuts before making the final adjustment. And don't lower the blades if the grass is very long, as it'll put strain on the mower. Ideally, cut on your current setting first, then go lower a day or two later.</p><p>Also, it’s best to get the timing right — choose a dry afternoon for mowing and avoid cutting when the grass is wet or frosty. “Wait for a dry spell and go over it when growth slows right down. A little effort now means a much healthier, greener lawn when spring comes round.”</p><h3 class="article-body__section" id="section-when-is-the-final-cut-of-the-year"><span>When is the final cut of the year?</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3881px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Z6e7zssSp9CSJ5vWZnm3Kb" name="shutterstock_1311895748.jpg" alt="Lawnmower cutting grass" src="https://cdn.mos.cms.futurecdn.net/Z6e7zssSp9CSJ5vWZnm3Kb-1920-80.jpg" mos="" align="middle" fullscreen="" width="3881" height="2183" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Lawnmower cutting grass </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>So when is it finally time to put away your lawn mower this season? Experts agree that around mid-November, you should leave the grass at around 5cm.</p><p>“That's the sweet spot for winter,” adds Davis. “It's long enough to protect the roots from frost and keep the crown healthy, but short enough that it won't become a soggy, matted mess over the colder months.”</p><p>So before you put your mower to rest, give your grass that essential trim this October, and your lawn will thank you for it come spring.</p><p>For more top tips, check out <a href="https://www.tomsguide.com/home/lawn-care/revive-your-lawn-this-fall-when-to-overseed-for-a-lush-green-yard">how to overseed your lawn in fall</a>.  </p><div class="product"><a data-dimension112="9fee9d68-c882-11f1-ab74-39fa526b2c73" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31" href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2424px;"><p class="vanilla-image-block" style="padding-top:55.45%;"><img id="T2WUaZHkFF36kQyUDUWTTS" name="My Soil soil test kit" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/T2WUaZHkFF36kQyUDUWTTS-1920-80.png" mos="" align="middle" fullscreen="" width="2424" height="1344" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow" data-dimension112="9fee9d68-c882-11f1-ab74-39fa526b2c73" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31">Soil Tests Kit: $31</a></strong><br />Know your soil before overseeding. This professional test measures 13 nutrient levels, including nitrogen and pH, to reveal exactly what your lawn needs. Results in 6 to 8 days help you apply the right products for stronger germination and healthier, sustainable grass growth.<a class="view-deal button" href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow" data-dimension112="9fee9d68-c882-11f1-ab74-39fa526b2c73" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31">View Deal</a></p></div><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-common-lawn-care-mistakes-you-are-probably-making-right-now">7 common lawn care mistakes you’re probably making right now</a></li><li><a href="https://www.tomsguide.com/how-to/9-ways-to-get-the-most-out-of-your-lawn-mower">9 ways to get the most out of your lawn mower</a></li><li><a href="https://www.tomsguide.com/how-to/5-plants-that-will-keep-wasps-out-of-your-yard">5 plants that will keep wasps out of your yard</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/lawn-care/lawn-expert-urges-gardeners-to-keep-mowing-this-october-heres-why</link>
                                                                            <description>
                            <![CDATA[ Lawn expert reveals why gardeners should keep mowing in October as warm grass keeps growing this fall. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">dpvSK9QpH6mHcFHSayNBUW</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/qzLgvGqYc85kPdQkdLKyjW-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 15 Oct 2026 10:50:43 +0000</pubDate>                                                                                                                                <updated>Thu, 15 Oct 2026 10:50:47 +0000</updated>
                                                                                                                                            <category><![CDATA[Lawn Care]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                                    <dc:creator><![CDATA[ Cynthia Lawrence ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/4hFvAy3JvgCJamhKf5KoPU-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/qzLgvGqYc85kPdQkdLKyjW-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Mowing lawn in fall]]></media:description>                                                            <media:text><![CDATA[Mowing lawn in fall]]></media:text>
                                <media:title type="plain"><![CDATA[Mowing lawn in fall]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/qzLgvGqYc85kPdQkdLKyjW-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Fall has arrived, but cooler temperatures don’t mean you should put away your garden tools just yet. You still have essential tasks to complete to <a href="https://www.tomsguide.com/home/lawn-care/3-expert-approved-tasks-you-must-do-in-october-to-get-your-yard-ready-for-fall">prepare your yard for the winter ahead</a>. And just when you thought it was time to pack away your lawn mower until spring, you may want to think again. </p><p>According to a lawn expert, gardeners need to continue mowing through October  — because mild fall temperatures allow grass to keep growing.</p><p>Not only can this simple task promote a healthy, green <a href="https://www.tomsguide.com/features/the-ultimate-lawn-care-guide-essential-tips-and-tricks-for-getting-the-perfect-lawn">lawn</a>, but long grass can actually do more harm than good. </p><p>“Long grass holds on to moisture, especially with the damp mornings and heavy dew we get in fall,” says Jonathan Davis, a lawn expert at <a href="https://www.lawnsmith.co.uk/" target="_blank">Lawnsmith</a>. </p><p>“That creates the perfect conditions for fungal diseases like red thread and fusarium patch to take hold. Once they get a grip, they can leave your lawn looking patchy and sorry for itself by spring.” </p><p>What’s more, <a href="https://www.tomsguide.com/how-to/5-ways-to-get-rid-of-moss">moss </a>is one of the most common lawn weeds, known as a ‘silent grass killer’, that appears in the form of green, sponge-like patches between the blades of grass. </p><p>“Moss loves damp, shady spots, and at this time of year there's plenty of both. If your grass is long and thick, the light can't reach the base of it, meaning your lawn will struggle.” </p><p>So if you want to get your lawn in top shape for spring, here are some top tips for mowing your lawn in October. </p><h2 id="how-to-cut-your-lawn-in-fall">How to cut your lawn in fall</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="sPsWcpJfaGgXoakPEySmPM" name="shutterstock_1585509538" alt="Lawn mower mulching fall leaves" src="https://cdn.mos.cms.futurecdn.net/sPsWcpJfaGgXoakPEySmPM-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">A man mowing the lawn  </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Avoid cutting your grass too short; the ‘golden rule’ is to never trim more than a third of its height. This is because mowing too close to the ground exposes the lawn to root diseases and encourages weed growth.</p><p>“Never cut more than a third off the height of the grass in one go,” he said. “Think of grass like an iceberg: a fifth above ground and four fifths below,” adds Davis.</p><p>“Take too much off, and you reduce the roots, leaving the plant weak and more vulnerable to disease and weeds.” </p><p>In any case, if you are battling weeds,<a href="https://www.tomsguide.com/home/gardening/i-asked-professional-gardeners-how-to-get-rid-of-weeds-from-my-lawn-permanently-and-they-all-say-this-one-thing"> I asked professional gardeners how to get rid of weeds from my lawn permanently — and they all say this one thing.</a></p><p>In addition, Davis advises gradually changing your mower's height for a couple of cuts before making the final adjustment. And don't lower the blades if the grass is very long, as it'll put strain on the mower. Ideally, cut on your current setting first, then go lower a day or two later.</p><p>Also, it’s best to get the timing right — choose a dry afternoon for mowing and avoid cutting when the grass is wet or frosty. “Wait for a dry spell and go over it when growth slows right down. A little effort now means a much healthier, greener lawn when spring comes round.”</p><h3 class="article-body__section" id="section-when-is-the-final-cut-of-the-year"><span>When is the final cut of the year?</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3881px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Z6e7zssSp9CSJ5vWZnm3Kb" name="shutterstock_1311895748.jpg" alt="Lawnmower cutting grass" src="https://cdn.mos.cms.futurecdn.net/Z6e7zssSp9CSJ5vWZnm3Kb-1920-80.jpg" mos="" align="middle" fullscreen="" width="3881" height="2183" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Lawnmower cutting grass </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>So when is it finally time to put away your lawn mower this season? Experts agree that around mid-November, you should leave the grass at around 5cm.</p><p>“That's the sweet spot for winter,” adds Davis. “It's long enough to protect the roots from frost and keep the crown healthy, but short enough that it won't become a soggy, matted mess over the colder months.”</p><p>So before you put your mower to rest, give your grass that essential trim this October, and your lawn will thank you for it come spring.</p><p>For more top tips, check out <a href="https://www.tomsguide.com/home/lawn-care/revive-your-lawn-this-fall-when-to-overseed-for-a-lush-green-yard">how to overseed your lawn in fall</a>.  </p><div class="product"><a data-dimension112="9fee9d68-c882-11f1-ab74-39fa526b2c73" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31" href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2424px;"><p class="vanilla-image-block" style="padding-top:55.45%;"><img id="T2WUaZHkFF36kQyUDUWTTS" name="My Soil soil test kit" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/T2WUaZHkFF36kQyUDUWTTS-1920-80.png" mos="" align="middle" fullscreen="" width="2424" height="1344" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow" data-dimension112="9fee9d68-c882-11f1-ab74-39fa526b2c73" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31">Soil Tests Kit: $31</a></strong><br />Know your soil before overseeding. This professional test measures 13 nutrient levels, including nitrogen and pH, to reveal exactly what your lawn needs. Results in 6 to 8 days help you apply the right products for stronger germination and healthier, sustainable grass growth.<a class="view-deal button" href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow" data-dimension112="9fee9d68-c882-11f1-ab74-39fa526b2c73" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31">View Deal</a></p></div><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-common-lawn-care-mistakes-you-are-probably-making-right-now">7 common lawn care mistakes you’re probably making right now</a></li><li><a href="https://www.tomsguide.com/how-to/9-ways-to-get-the-most-out-of-your-lawn-mower">9 ways to get the most out of your lawn mower</a></li><li><a href="https://www.tomsguide.com/how-to/5-plants-that-will-keep-wasps-out-of-your-yard">5 plants that will keep wasps out of your yard</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Black Friday isn’t here yet — but Amazon is already offering up to 55% off these 21 home and kitchen appliances ]]></title>
                                                                                                <dc:content><![CDATA[ <p>October Prime Day is behind us, and Black Friday is still weeks away — but that doesn’t mean the deals have dried up. There are still plenty of worthwhile savings to score between the major shopping events, and one of the most impressive sales I’ve spotted so far is on kitchen and home appliances.</p><p>In fact, <a href="https://www.amazon.com/deals?bubble-id=kitchen" target="_blank" rel="nofollow">Amazon is currently knocking up to 55% off everything from toaster ovens and blenders to air purifiers and vacuums</a>. Many of the deals come courtesy of our favorite brands that we've personally tested — Ninja, Shark, KitchenAid, Dyson and more, to name a few prominent players.</p><p>If you're ready to upgrade your home appliances, I've rounded up the best deals from Amazon that you can shop right now. Plus, don't miss our <a href="https://www.tomsguide.com/coupons/amazon.com">Amazon promo codes</a> page for more ways to save.</p><h3 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h3><ul><li><a href="https://www.amazon.com/deals?bubble-id=kitchen" target="_blank" rel="nofollow"><strong>shop all Amazon kitchen appliance deals</strong></a></li><li><strong>Crock-Pot 7-Quart Slow Cooker: </strong><a href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow"><strong>was $59 now $35</strong></a></li><li><strong>Ninja Blast Max: </strong><a href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow"><strong>was $99 now $69</strong></a></li><li><strong>Keurig K-Express: </strong><a href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow"><strong>was $89 now $69</strong></a></li><li><strong>Shark Never Change Air Purifier: </strong><a href="https://www.amazon.com/dp/B0F1GGDG94?" target="_blank" rel="nofollow"><strong>was $179 now $129</strong></a></li><li><strong>Dreame D20 Air Plus Robot Vacuum: </strong><a href="https://www.amazon.com/dp/B0G5XVMVJN" target="_blank" rel="nofollow"><strong>was $349 now $269</strong></a></li><li><strong>KitchenAid Artisan Series 5 Quart: </strong><a href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow"><strong>was $499 now $379</strong></a></li><li><strong>Breville Barista Express: </strong><a href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow"><strong>was $689 now $499</strong></a></li></ul><h3 class="article-body__section" id="section-best-kitchen-appliance-deals"><span>Best Kitchen Appliance Deals</span></h3><div class="product"><a data-dimension112="0f26c77c-c717-11f1-aa00-5b1f6e05ec2a" data-action="Deal Block" data-label="7-Quart Slow Cooker" data-dimension48="7-Quart Slow Cooker" data-dimension25="$35" href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1080px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="xxEFYRjw4hJpt8rETUuaiH" name="Crock-Pot 7-Quart Slow Cooker" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xxEFYRjw4hJpt8rETUuaiH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>This 7-quart slow cooker is the perfect size to house a big batch of chili or queso to snack on all day. Or you can plan ahead and slow cook a melt-in-your-mouth roast with some carrots and potatoes for an easy dinner.<a class="view-deal button" href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow" data-dimension112="0f26c77c-c717-11f1-aa00-5b1f6e05ec2a" data-action="Deal Block" data-label="7-Quart Slow Cooker" data-dimension48="7-Quart Slow Cooker" data-dimension25="$35">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c7fe-c717-11f1-bfd2-0bf8059f1e58" data-action="Deal Block" data-label="Blast Max" data-dimension48="Blast Max" data-dimension25="$69" href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1216px;"><p class="vanilla-image-block" style="padding-top:123.36%;"><img id="9Q4QY399FaozAFUt4j8dTW" name="ninja-blast-max-portable-blender--twist--bb517479-54ce-4a77-974c-58e2f44dde33.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/9Q4QY399FaozAFUt4j8dTW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1216" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Ninja Blast Max is capable of taking on any challenge you throw at it, including crushing ice and blitzing berries to make yummy smoothies. It comes with multiple blend settings to make sure your blender is using the right level of power for the task at hand, and the compact size means it’s a great option for anyone with a small kitchen. <a class="view-deal button" href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow" data-dimension112="0f26c7fe-c717-11f1-bfd2-0bf8059f1e58" data-action="Deal Block" data-label="Blast Max" data-dimension48="Blast Max" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c862-c717-11f1-92f4-dbbba92440d2" data-action="Deal Block" data-label="Cordless Citrus Juicer" data-dimension48="Cordless Citrus Juicer" data-dimension25="$79" href="https://www.amazon.com/KitchenAid-Cordless-Citrus-Juicer-separately/dp/B0DN6RX5Q3" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:964px;"><p class="vanilla-image-block" style="padding-top:155.60%;"><img id="HmFhrr2KfXYEaCMCSBwkhL" name="KitchenAid Go Cordless Citrus Juicer" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HmFhrr2KfXYEaCMCSBwkhL-1920-80.jpg" mos="" align="middle" fullscreen="" width="964" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The KitchenAid Go Cordless Citrus Juicer makes it so simple to have fresh juice every morning with minimal mess. If you hate pulp in your juice, this won’t be for you. But if you’re looking for the fastest way to juice your citrus, this is the answer. It’s simple to clean too, since the top half of the appliance is dishwasher-friendly.<a class="view-deal button" href="https://www.amazon.com/KitchenAid-Cordless-Citrus-Juicer-separately/dp/B0DN6RX5Q3" target="_blank" rel="nofollow" data-dimension112="0f26c862-c717-11f1-92f4-dbbba92440d2" data-action="Deal Block" data-label="Cordless Citrus Juicer" data-dimension48="Cordless Citrus Juicer" data-dimension25="$79">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c8d0-c717-11f1-a8e1-93a83928f07c" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$89" href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="EBqQHURi67ApM2ai2joGg6" name="_0007_CHEFMAN Multifunctional Digital Air Fryer+" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/EBqQHURi67ApM2ai2joGg6-1920-80.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow" data-dimension112="0f26c8d0-c717-11f1-a8e1-93a83928f07c" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$89">Multifunctional Digital Air Fryer: was $139 now $89</a></strong><br />An extra large digital air fryer, this CHEFMAN model has 17 presets and an easy-to-use touch screen so you can get cooking immediately. It's big enough for family-sized meals, party-sized appetizers and has a window so you can check your cooking without opening it.<a class="view-deal button" href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow" data-dimension112="0f26c8d0-c717-11f1-a8e1-93a83928f07c" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c934-c717-11f1-a3a0-c73f0e1578db" data-action="Deal Block" data-label="Air Fryer XL" data-dimension48="Air Fryer XL" data-dimension25="$119" href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B0CS3V8M9H?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1367px;"><p class="vanilla-image-block" style="padding-top:109.73%;"><img id="MvRPAsDrHySaXiXmcEDdLn" name="Ninja Air Fryer XL" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/MvRPAsDrHySaXiXmcEDdLn-1920-80.jpg" mos="" align="middle" fullscreen="" width="1367" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B0CS3V8M9H?" target="_blank" rel="nofollow" data-dimension112="0f26c934-c717-11f1-a3a0-c73f0e1578db" data-action="Deal Block" data-label="Air Fryer XL" data-dimension48="Air Fryer XL" data-dimension25="$119">Air Fryer XL: was $179 now $119</a></strong><br />The Ninja Pro XL 6-in-1 air fryer does everything you need an air fryer to. It cooks, it crisps, it bakes. It's the ideal first air fryer because it does utterly everything you could want. As someone who's used a lot of Ninja tech, I can also say with confidence that it's intuitive and easy to use. Ninja never lets you down.<a class="view-deal button" href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B0CS3V8M9H?" target="_blank" rel="nofollow" data-dimension112="0f26c934-c717-11f1-a3a0-c73f0e1578db" data-action="Deal Block" data-label="Air Fryer XL" data-dimension48="Air Fryer XL" data-dimension25="$119">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c9c0-c717-11f1-a952-eb018f8e28f1" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$69" href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:230.93%;"><img id="SNGj6WoG25u9rj7PA3Zhre" name="Keurig K Express" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SNGj6WoG25u9rj7PA3Zhre-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="1568" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow" data-dimension112="0f26c9c0-c717-11f1-a952-eb018f8e28f1" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$69">K-Express: was $89 now $69</a></strong><br />The Keurig Express offers three cup sizes — 8, 10 and 12 oz and has a 42 oz detachable water reservoir, making it easy to remove, fill or clean. By removing the drip tray you can position a travel mug up to 7.4 inches tall under the brew stream. <a class="view-deal button" href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow" data-dimension112="0f26c9c0-c717-11f1-a952-eb018f8e28f1" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="0f26ca24-c717-11f1-8a2f-a332ea1e9bd7" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99" href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:99.56%;"><img id="4uiaRXRKY8Go6F4ZpM7UdA" name="Ninja coffee" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4uiaRXRKY8Go6F4ZpM7UdA-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="676" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow" data-dimension112="0f26ca24-c717-11f1-8a2f-a332ea1e9bd7" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99">Single Serve Coffee Maker with Pods and Grounds: was $129 now $99</a></strong><br />This stylish Ninja coffee maker comes in a gorgeous choice of colorways, including Sage Green, and is now on sale for $30 off. Whether you prefer pods or grounds, this device makes tasty brews in 7 sizes (6-oz. to 24-oz) and has a built-in, fold-away milk frother! The only problem you'll have is deciding which color to choose.<a class="view-deal button" href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow" data-dimension112="0f26ca24-c717-11f1-8a2f-a332ea1e9bd7" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="0f26ca88-c717-11f1-9d0c-a7ed1a74c9b4" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89" href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:717px;"><p class="vanilla-image-block" style="padding-top:163.18%;"><img id="LpQPvQCcU8GNALWdf2GLs4" name="51EcND+lspL._AC_SL1173_.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/LpQPvQCcU8GNALWdf2GLs4-1920-80.jpg" mos="" align="middle" fullscreen="" width="717" height="1170" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow" data-dimension112="0f26ca88-c717-11f1-9d0c-a7ed1a74c9b4" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89">PerfecTemp Cordless Electric Kettle: was $129 now $89</a></strong><br />This sleek electric Kettle heats and boils your brews quickly. With six preset heating profiles to choose from, it can extract the most flavor out of your tea or morning coffee. We rank it as one of the <a href="https://www.tomsguide.com/best-picks/the-best-electric-kettles">best electric kettles</a>.<a class="view-deal button" href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow" data-dimension112="0f26ca88-c717-11f1-9d0c-a7ed1a74c9b4" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cb32-c717-11f1-86a1-4563d8f6d155" data-action="Deal Block" data-label="NeverClog Cold Press Juicer" data-dimension48="NeverClog Cold Press Juicer" data-dimension25="$129" href="https://www.amazon.com/dp/B0BR8HZL9V?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1499px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="2WLwjdnMeBZu5mrkYrS2jH" name="Ninja NeverClog Cold Press Juicer" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/2WLwjdnMeBZu5mrkYrS2jH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1499" height="1499" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>Ninja's NeverClog Cold Press Juicer removes the hassle of juicing fruits and vegetables. The special filter pushes pulp through without clogging and lets you customize the amount of pulp in your juice with two interchangeable pulp filters. It comes with a 24-oz juice jug and a 36-oz pulp container, allowing you to make large batches of juice, rather than single servings.<a class="view-deal button" href="https://www.amazon.com/dp/B0BR8HZL9V?" target="_blank" rel="nofollow" data-dimension112="0f26cb32-c717-11f1-86a1-4563d8f6d155" data-action="Deal Block" data-label="NeverClog Cold Press Juicer" data-dimension48="NeverClog Cold Press Juicer" data-dimension25="$129">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cb96-c717-11f1-86ff-2918f2e4cacd" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149" href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1676px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="sWibiMn9jcqpLxyQRazy6f" name="Ninja Amazon 2.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/sWibiMn9jcqpLxyQRazy6f-1920-80.jpg" mos="" align="middle" fullscreen="" width="1676" height="1676" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow" data-dimension112="0f26cb96-c717-11f1-86ff-2918f2e4cacd" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149">Mega Kitchen System: was $219 now $149</a></strong><br />Leave all the multi-tasking in the kitchen to one appliance with this Ninja blender. With four functions for smoothies, processing, dough, drinks and more it will quickly become your go-to kitchen appliance. With this ultimate appliance, you’ll be enjoying fresh, healthy drinks, homemade bread and sweet bakes.<a class="view-deal button" href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow" data-dimension112="0f26cb96-c717-11f1-86ff-2918f2e4cacd" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cbfa-c717-11f1-bd56-e95c2b871575" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379" href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:91.20%;"><img id="HPfDur99xHfhfWNbGej8ZE" name="KitchenAid Artisan Mixer.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HPfDur99xHfhfWNbGej8ZE-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1368" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow" data-dimension112="0f26cbfa-c717-11f1-bd56-e95c2b871575" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379">Artisan Series 5 Quart: was $499 now $379</a></strong><br />A Tom's Guide favorite, in our <a href="https://www.tomsguide.com/opinion/the-kitchenaid-artisan-stand-mixer-is-my-best-kitchen-purchase-ever-heres-why">KitchenAid Artisan 5-Quart stand mixer review</a>, we dubbed it the "best kitchen purchase" you can ever make. It beats, whisks, and kneads at 10 different speeds, so you don't have to, reducing recipe times. The bowl is big enough to support 9 dozen cookies or 4 loaves of bread at a time. This machine also boasts a 59-point planetary mixing action — fancy words that translate into incredibly mixed ingredients. Plus, it ships with a flat beater, coated dough hook, 6-wire whip, and 1-piece pouring shield. <a class="view-deal button" href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow" data-dimension112="0f26cbfa-c717-11f1-bd56-e95c2b871575" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cc5e-c717-11f1-88a9-a9441d0fac87" data-action="Deal Block" data-label="Barista Express" data-dimension48="Barista Express" data-dimension25="$499" href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1306px;"><p class="vanilla-image-block" style="padding-top:114.85%;"><img id="xqb7yApNa26xAkZLUbt3tW" name="breville barista express.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xqb7yApNa26xAkZLUbt3tW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1306" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Breville Barista Express is one of the most iconic and respected bean-to-cup espresso machines ever made. Although it's been out for around 6 years at this point, the Barista Express shows no signs of slowing down. Right now it's just $499, which is the same price as Breville's compact Bambino Plus. You basically get a free grinder.<a class="view-deal button" href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow" data-dimension112="0f26cc5e-c717-11f1-88a9-a9441d0fac87" data-action="Deal Block" data-label="Barista Express" data-dimension48="Barista Express" data-dimension25="$499">View Deal</a></p></div><h3 class="article-body__section" id="section-best-home-appliance-deals"><span>Best Home Appliance Deals</span></h3><div class="product"><a data-dimension112="0f26cd26-c717-11f1-85c9-771a37eb4a98" data-action="Deal Block" data-label="Core Smart Air Purifier 200S-P" data-dimension48="Core Smart Air Purifier 200S-P" data-dimension25="$74" href="https://www.amazon.com/LEVOIT-Purifier-Allergies-Core-200S/dp/B08FJ678YK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1290px;"><p class="vanilla-image-block" style="padding-top:116.28%;"><img id="MUF285tRsNNeQZcGQueo6f" name="LEVOIT Air Purifier" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/MUF285tRsNNeQZcGQueo6f-1920-80.jpg" mos="" align="middle" fullscreen="" width="1290" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/LEVOIT-Purifier-Allergies-Core-200S/dp/B08FJ678YK" target="_blank" rel="nofollow" data-dimension112="0f26cd26-c717-11f1-85c9-771a37eb4a98" data-action="Deal Block" data-label="Core Smart Air Purifier 200S-P" data-dimension48="Core Smart Air Purifier 200S-P" data-dimension25="$74">Core Smart Air Purifier 200S-P: was $89 now $74</a></strong><br />If you’re after a small yet powerful purifier that can handle mid-large spaces, this Levoit Core smart model is ideal. It comes with a three-stage filtration, and has an auto feature that scans the air for particles and adjusts the fan speed accordingly. Plus, it sends back real-time reports to your phone, for added convenience.<a class="view-deal button" href="https://www.amazon.com/LEVOIT-Purifier-Allergies-Core-200S/dp/B08FJ678YK" target="_blank" rel="nofollow" data-dimension112="0f26cd26-c717-11f1-85c9-771a37eb4a98" data-action="Deal Block" data-label="Core Smart Air Purifier 200S-P" data-dimension48="Core Smart Air Purifier 200S-P" data-dimension25="$74">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cd8a-c717-11f1-b02a-4386a5dfc249" data-action="Deal Block" data-label="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension48="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension25="$86" href="https://www.amazon.com/BISSELL-Upholstery-HydroRinse-Self-Cleaning-4075/dp/B0DJMP6T3N" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:99.85%;"><img id="cbDzFRwy4MhLMix2v6GC7D" name="Little green mini" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/cbDzFRwy4MhLMix2v6GC7D-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="678" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/BISSELL-Upholstery-HydroRinse-Self-Cleaning-4075/dp/B0DJMP6T3N" target="_blank" rel="nofollow" data-dimension112="0f26cd8a-c717-11f1-b02a-4386a5dfc249" data-action="Deal Block" data-label="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension48="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension25="$86">Little Green Mini Portable Carpet and Upholstery Deep Cleaner: was $99 now $86</a></strong><br />This is a great discount for the mini version of the portable stain removing vacuum that can be used to remove spills and messes created by the whole family, including pets. The clean water tank has a 16 oz capacity, giving you more time between emptying and refilling. Plus, it comes with a 4-inch tough stain tool, HydroRinse self-cleaning hose tool, and trial size cleaning solution.<a class="view-deal button" href="https://www.amazon.com/BISSELL-Upholstery-HydroRinse-Self-Cleaning-4075/dp/B0DJMP6T3N" target="_blank" rel="nofollow" data-dimension112="0f26cd8a-c717-11f1-b02a-4386a5dfc249" data-action="Deal Block" data-label="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension48="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension25="$86">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cdee-c717-11f1-b23a-751d1a137976" data-action="Deal Block" data-label="Never Change Air Purifier" data-dimension48="Never Change Air Purifier" data-dimension25="$129" href="https://www.amazon.com/dp/B0F1GGDG94?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1006px;"><p class="vanilla-image-block" style="padding-top:149.11%;"><img id="oTnJrM8YckF83ojojweeS6" name="Shark NeverChange Compact" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/oTnJrM8YckF83ojojweeS6-1920-80.jpg" mos="" align="middle" fullscreen="" width="1006" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0F1GGDG94?" target="_blank" rel="nofollow" data-dimension112="0f26cdee-c717-11f1-b23a-751d1a137976" data-action="Deal Block" data-label="Never Change Air Purifier" data-dimension48="Never Change Air Purifier" data-dimension25="$129">Never Change Air Purifier: was $179 now $129</a></strong><br />Named the <a href="https://www.tomsguide.com/best-picks/best-air-purifier">best air purifier</a> for small spaces in our guide, this Shark air purifier suits rooms up to 250 sq ft, although this is based on one change of air over an hour. With an auto mode, it adjusts the fan speed based on the quality of the air and displays the corresponding data on the panel. It also has Odor Neutralizer Technology, that releases a fresh scent in the air.<a class="view-deal button" href="https://www.amazon.com/dp/B0F1GGDG94?" target="_blank" rel="nofollow" data-dimension112="0f26cdee-c717-11f1-b23a-751d1a137976" data-action="Deal Block" data-label="Never Change Air Purifier" data-dimension48="Never Change Air Purifier" data-dimension25="$129">View Deal</a></p></div><div class="product"><a data-dimension112="0f26ce52-c717-11f1-ba27-8bbc73b60570" data-action="Deal Block" data-label="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension48="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension25="$179" href="https://www.amazon.com/Shark-IZ662H-Lightweight-Multi-Tool-Anti-Allergen/dp/B0GZSST8ZT?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:863px;"><p class="vanilla-image-block" style="padding-top:173.81%;"><img id="QQQeiV62353jSCQyEPosXQ" name="Shark Cordless Pet" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/QQQeiV62353jSCQyEPosXQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="863" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Shark-IZ662H-Lightweight-Multi-Tool-Anti-Allergen/dp/B0GZSST8ZT?" target="_blank" rel="nofollow" data-dimension112="0f26ce52-c717-11f1-ba27-8bbc73b60570" data-action="Deal Block" data-label="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension48="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension25="$179">Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red): was $299 now $179</a></strong><br />This lightweight cordless vacuum cleaner can handle just about any task. Equipped with powerful suction, it comes with a multiflex wand that can tackle hard-to-reach places, DuoClean PowerFins, and a self-cleaning brushroll (great for pet hair). It also has a 40-minute runtime on a single charge.<a class="view-deal button" href="https://www.amazon.com/Shark-IZ662H-Lightweight-Multi-Tool-Anti-Allergen/dp/B0GZSST8ZT?" target="_blank" rel="nofollow" data-dimension112="0f26ce52-c717-11f1-ba27-8bbc73b60570" data-action="Deal Block" data-label="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension48="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension25="$179">View Deal</a></p></div><div class="product"><a data-dimension112="0f26ceb6-c717-11f1-942d-5d7dbb5f4bbf" data-action="Deal Block" data-label="HydroVac MessMaster wet and dry vacuum" data-dimension48="HydroVac MessMaster wet and dry vacuum" data-dimension25="$199" href="https://www.amazon.com/Shark-Multi-Surface-Self-Cleaning-Lightweight-WD261/dp/B0CZSBYB5V/ref" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="oDxSkPexrniGToXj2psqek" name="shark messmaster deal block" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/oDxSkPexrniGToXj2psqek-1920-80.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Shark-Multi-Surface-Self-Cleaning-Lightweight-WD261/dp/B0CZSBYB5V/ref" target="_blank" rel="nofollow" data-dimension112="0f26ceb6-c717-11f1-942d-5d7dbb5f4bbf" data-action="Deal Block" data-label="HydroVac MessMaster wet and dry vacuum" data-dimension48="HydroVac MessMaster wet and dry vacuum" data-dimension25="$199">HydroVac MessMaster wet and dry vacuum: was $299 now $199</a></strong><br />The Shark HydroVac MessMaster is one of the easiest wet and dry vacuums to use. It's so much lighter and easier than lugging around a mop, and the self-cleaning roller means it won't dispense mess back onto your floors. <a class="view-deal button" href="https://www.amazon.com/Shark-Multi-Surface-Self-Cleaning-Lightweight-WD261/dp/B0CZSBYB5V/ref" target="_blank" rel="nofollow" data-dimension112="0f26ceb6-c717-11f1-942d-5d7dbb5f4bbf" data-action="Deal Block" data-label="HydroVac MessMaster wet and dry vacuum" data-dimension48="HydroVac MessMaster wet and dry vacuum" data-dimension25="$199">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cf24-c717-11f1-a1a4-8bc1f1ae6688" data-action="Deal Block" data-label="Braava Jet M6" data-dimension48="Braava Jet M6" data-dimension25="$199" href="https://www.amazon.com/iRobot-Ultimate-Connected-Precision-Recharges/dp/B07QNM91NQ" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="bCAuL9bEPqJMBC5VpP4ji9" name="Braava jet m6.jpeg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/bCAuL9bEPqJMBC5VpP4ji9-1920-80.jpeg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/iRobot-Ultimate-Connected-Precision-Recharges/dp/B07QNM91NQ" target="_blank" rel="nofollow" data-dimension112="0f26cf24-c717-11f1-a1a4-8bc1f1ae6688" data-action="Deal Block" data-label="Braava Jet M6" data-dimension48="Braava Jet M6" data-dimension25="$199">Braava Jet M6: was $449 now $199</a></strong><br />Voted our <a href="https://www.tomsguide.com/best-picks/best-robot-mops">best robot mop,</a> this model provides a thorough cleaning performance that dries quickly. The accurate navigation and tight controls are impressive, with the ability to clean specific rooms on the map. It also link up to work together with compatible Roombas to boot.<a class="view-deal button" href="https://www.amazon.com/iRobot-Ultimate-Connected-Precision-Recharges/dp/B07QNM91NQ" target="_blank" rel="nofollow" data-dimension112="0f26cf24-c717-11f1-a1a4-8bc1f1ae6688" data-action="Deal Block" data-label="Braava Jet M6" data-dimension48="Braava Jet M6" data-dimension25="$199">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cf7e-c717-11f1-8deb-71f932728829" data-action="Deal Block" data-label="D20 Air Plus Robot Vacuum" data-dimension48="D20 Air Plus Robot Vacuum" data-dimension25="$269" href="https://www.amazon.com/dp/B0G5XVMVJN" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:82.60%;"><img id="tL9ig3M9LUrD4yX7axWboE" name="Dreame D20 Air Plus Robot Vacuum" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/tL9ig3M9LUrD4yX7axWboE-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1239" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0G5XVMVJN" target="_blank" rel="nofollow" data-dimension112="0f26cf7e-c717-11f1-8deb-71f932728829" data-action="Deal Block" data-label="D20 Air Plus Robot Vacuum" data-dimension48="D20 Air Plus Robot Vacuum" data-dimension25="$269">D20 Air Plus Robot Vacuum: was $349 now $269</a></strong><br />The Dreame D20 Air Plus can clean and mop your floors. It features 20,000Pa suction power for cleaning and a built-in electronic water tank for mopping. It uses LiDAR technology to navigate through your home and it automatically docks when it's time to empty out its bin. We also appreciate its 4L sealed dust bag that traps up to 120 days worth of dust, pet hair, and debris. <a class="view-deal button" href="https://www.amazon.com/dp/B0G5XVMVJN" target="_blank" rel="nofollow" data-dimension112="0f26cf7e-c717-11f1-8deb-71f932728829" data-action="Deal Block" data-label="D20 Air Plus Robot Vacuum" data-dimension48="D20 Air Plus Robot Vacuum" data-dimension25="$269">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cfe2-c717-11f1-8557-916e8f29abce" data-action="Deal Block" data-label="V8 Cordless" data-dimension48="V8 Cordless" data-dimension25="$269" href="https://www.amazon.com/Dyson-626423-01-V8TM-Cordless-Vacuum/dp/B0GT2DG9SK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="3sSBPzCpGfLBqHoGiHApw4" name="Dyson V8 Absolute" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/3sSBPzCpGfLBqHoGiHApw4-1920-80.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Dyson-626423-01-V8TM-Cordless-Vacuum/dp/B0GT2DG9SK" target="_blank" rel="nofollow" data-dimension112="0f26cfe2-c717-11f1-8557-916e8f29abce" data-action="Deal Block" data-label="V8 Cordless" data-dimension48="V8 Cordless" data-dimension25="$269">V8 Cordless: was $389 now $269</a></strong><br />The Dyson V8 gets you up to 40 minutes of fade-free power. It also comes with two cleaning heads, the Hair Screw Tool (to pick up long hair without tangles), and two additional attachments. We also like that it features HEPA filtration and an additional cleaner head for hard floors​.<a class="view-deal button" href="https://www.amazon.com/Dyson-626423-01-V8TM-Cordless-Vacuum/dp/B0GT2DG9SK" target="_blank" rel="nofollow" data-dimension112="0f26cfe2-c717-11f1-8557-916e8f29abce" data-action="Deal Block" data-label="V8 Cordless" data-dimension48="V8 Cordless" data-dimension25="$269">View Deal</a></p></div><div class="product"><a data-dimension112="0f26d046-c717-11f1-8fb5-55e98d2348d8" data-action="Deal Block" data-label="AI Ultra Voice Control Robot Vacuum" data-dimension48="AI Ultra Voice Control Robot Vacuum" data-dimension25="$269" href="https://www.amazon.com/Shark-AV2511AE-Self-Empty-Capacity-Navigation/dp/B09T4YZGQR" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1438px;"><p class="vanilla-image-block" style="padding-top:93.05%;"><img id="BbfJrbM56fV2krqdoLohGm" name="Shark Robot Vac" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/BbfJrbM56fV2krqdoLohGm-1920-80.png" mos="" align="middle" fullscreen="" width="1438" height="1338" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Shark-AV2511AE-Self-Empty-Capacity-Navigation/dp/B09T4YZGQR" target="_blank" rel="nofollow" data-dimension112="0f26d046-c717-11f1-8fb5-55e98d2348d8" data-action="Deal Block" data-label="AI Ultra Voice Control Robot Vacuum" data-dimension48="AI Ultra Voice Control Robot Vacuum" data-dimension25="$269">AI Ultra Voice Control Robot Vacuum: was $599 now $269</a></strong><br />With a 55% discount, this makes this Shark robot vacuum a steal. With impressive suction power, this can easily pick up dirt, debris and pet hair on all floor types. It also has tons of features like Matrix Clean, precision mapping, AI voice control and a 60-day self-emptying capacity.  <a class="view-deal button" href="https://www.amazon.com/Shark-AV2511AE-Self-Empty-Capacity-Navigation/dp/B09T4YZGQR" target="_blank" rel="nofollow" data-dimension112="0f26d046-c717-11f1-8fb5-55e98d2348d8" data-action="Deal Block" data-label="AI Ultra Voice Control Robot Vacuum" data-dimension48="AI Ultra Voice Control Robot Vacuum" data-dimension25="$269">View Deal</a></p></div><h3 class="article-body__section" id="section-shop-more-deals"><span>Shop more deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=Everything&amp;retailer=Amazon&amp;rows=8&amp;view_mode=savings_squad&amp;widget_title=Top+Amazon+Deals+Handpicked+by+Our+Editors&amp;widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&amp;bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function getTimeAgo(dateString) {        if (!dateString) return '';        const date = new Date(dateString);        const now = new Date();        const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);        if (diffInSeconds < 60) return 'Just now';        const diffInMinutes = Math.floor(diffInSeconds / 60);        if (diffInMinutes < 60) return `${diffInMinutes} min${diffInMinutes > 1 ? 's' : ''} ago`;        const diffInHours = Math.floor(diffInMinutes / 60);        if (diffInHours < 24) return `${diffInHours} hr${diffInHours > 1 ? 's' : ''} ago`;        const diffInDays = Math.floor(diffInHours / 24);        if (diffInDays < 30) return `${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`;        const diffInMonths = Math.floor(diffInDays / 30);        if (diffInMonths < 12) return `${diffInMonths} mo${diffInMonths > 1 ? 's' : ''} ago`;        const diffInYears = Math.floor(diffInDays / 365);        return `${diffInYears} yr${diffInYears > 1 ? 's' : ''} ago`;      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;      position: relative;      z-index: 20;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      margin: 0 auto;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {      display: grid;      width: 100%;      grid-template-columns: repeat(4, 1fr);      gap: 12px;      margin: 0 auto;      max-width: 800px;    }                 .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;      width: 100%;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      width: 100%;      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }    @container tg-df (max-width: 768px) {      .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {        width: 100%;        margin: 0;        margin-bottom: -320px;        padding: 0 16px 320px 16px;        display: flex;        flex-wrap: nowrap;        gap: 8px;        overflow-x: auto;        overflow-y: hidden;        pointer-events: none;        scrollbar-width: none;        -webkit-overflow-scrolling: touch;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }      .tg-df-sort-wrapper {        pointer-events: auto;        flex: 0 0 auto;        width: 175px;        min-width: 175px;      }    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 120px;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 16px 16px 8px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }                  .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;        width: auto;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;      width: 100vw;      max-width: 1200px;      position: relative;      left: 50%;      transform: translateX(-50%);    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 14px;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    .tg-df-grid-wrapper { position: relative; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn {      display: inline-flex;      align-items: center;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.40);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #1f69ff; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #0056e0; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }    .tg-df-savings-squad-header { margin-bottom: 24px; text-align: center; display: none; }    .tg-df-banner-img-desktop { display: block; width: 100%; height: auto; margin-bottom: 32px; }    .tg-df-banner-img-mobile { display: none; width: 100%; height: auto; margin-bottom: 32px; }    @container tg-df (max-width: 600px) {      .tg-df-banner-img-desktop { display: none; }      .tg-df-banner-img-mobile { display: block; }    }    .tg-df-header-title { font-size: 28px; font-weight: 700; color: var(--tg-df-text); margin: 32px 0 12px 0; line-height: 1.3; }    .tg-df-header-subtitle { font-size: 16px; color: var(--tg-df-text-muted); margin: 0 0 32px 0; line-height: 1.5; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3Cdiv class="tg-df-savings-squad-header" id="tg-df-savings-squad-header">      \x3Cpicture>        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/xkh2og7m3d1778189998.png" alt="Deals Banner" class="tg-df-banner-img-desktop" />        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/gmak6rtdf41778245089.png" alt="Deals Banner Mobile" class="tg-df-banner-img-mobile" />      \x3C/picture>      \x3Cdiv class="tg-df-header-text">        \x3Ch2 class="tg-df-header-title" id="tg-df-header-title">Editor's Choice Deals\x3C/h2>        \x3Cp class="tg-df-header-subtitle" id="tg-df-header-subtitle">Discover the best discounts currently available, curated daily by the Tom's Guide Savings Squad.\x3C/p>      \x3C/div>    \x3C/div>    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Televisions" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/wcMxTsHgqu3roMbAx7RLnT-132-100.png" alt="TVs" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">TVs\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Phones" data-pr="over50">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/G3KGaRGzj24F6PUsw4bWpT-132-100.png" alt="Phones" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Phones\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Computing" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/znNvsLzx8NEgNkD9HSFSnT-132-100.png" alt="Computing" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Computing\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Gaming" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/Pgew8yaRQeZFHqHjTzvBnT-132-100.png" alt="Gaming" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Gaming\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Mattresses" data-pr="over500">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/cW7xsaLyesxkHFVSiC4kmT-132-100.png" alt="Mattresses" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Mattresses\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Audio" data-pr="over30">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/pCvBVHuhaQVjKt3VgCjbqT-132-100.png" alt="Audio" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Audio\x3C/span>            \x3C/div>                  \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E      \x3Cdiv class="tg-df-top-bar" id="tg-df-top-bar" style="position: relative; z-index: 100; margin: 0 auto 20px;">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>      \x3C/div>    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">              \x3Cdiv class="tg-df-filters-container" style="position: relative; width: 100%; max-width: 800px; margin: 0 auto;">          \x3Cbutton class="tg-df-scroll-btn left" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: -200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M15 18l-6-6 6-6"/>\x3C/svg>          \x3C/button>          \x3Cbutton class="tg-df-scroll-btn right" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: 200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M9 18l6-6-6-6"/>\x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-filters">          \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>          \x3C/div>        \x3C/div>        \x3C/div>      \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();        }        getViewMode() {          console.log("DEBUG getViewMode -> override:", this.viewModeOverride, "editorMode:", this.editorMode);          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          console.log("[DEBUG] applyLayoutMode CALLED! mode=", mode);          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          const showHeaderDetails = params.get('show_header_details') !== 'false';          const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          const topBarDiv = this.root.querySelector('#tg-df-top-bar');          const headerElement = this.root.querySelector('#tg-df-savings-squad-header');          if (headerElement) {             headerElement.style.display = (mode === 'savings_squad' && showHeaderDetails) ? 'block' : 'none';          }          if (mode === 'carousel') {             this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (topBarDiv) topBarDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.add('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (topBarDiv) topBarDiv.style.display = 'block';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!this.viewModeOverride && initialViewMode) {            this.viewModeOverride = initialViewMode;          }          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Gaming laptops';          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button, .tg-df-container .tg-df-card-cta { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover, .tg-df-container .tg-df-card-cta:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (this.viewModeSelect && params.has('view_mode')) {            this.viewModeSelect.value = params.get('view_mode');          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'date_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }          const headerTitleEl = this.root.querySelector('#tg-df-header-title');          const headerSubtitleEl = this.root.querySelector('#tg-df-header-subtitle');          if (params.has('widget_title') && headerTitleEl) {             headerTitleEl.textContent = params.get('widget_title');          }          if (params.has('widget_subtitle') && headerSubtitleEl) {             headerSubtitleEl.textContent = params.get('widget_subtitle');          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            if (this.getViewMode() === 'savings_squad') {              this.searchInput.value = '';            } else {              this.searchInput.value = this.currentQuery;            }          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'date_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const handleFiltersScroll = () => {            const filters = this.root.querySelector('.tg-df-filters');            const leftBtn = this.root.querySelector('.tg-df-scroll-btn.left');            const rightBtn = this.root.querySelector('.tg-df-scroll-btn.right');            if (filters && leftBtn && rightBtn) {              const { scrollLeft, scrollWidth, clientWidth } = filters;              leftBtn.style.display = scrollLeft > 0 ? 'flex' : 'none';              rightBtn.style.display = Math.ceil(scrollLeft + clientWidth) < scrollWidth - 5 ? 'flex' : 'none';            }          };          const filters = this.root.querySelector('.tg-df-filters');          if (filters) {            filters.addEventListener('scroll', handleFiltersScroll);            window.addEventListener('resize', handleFiltersScroll);            setTimeout(handleFiltersScroll, 100);                        // Also call after rendering dropdowns            const origRenderCategories = this.renderCategories;            if (origRenderCategories) {               this.renderCategories = (...args) => {                 origRenderCategories.apply(this, args);                 setTimeout(handleFiltersScroll, 50);               };            }          }                const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          const showAutocomplete = () => {             if (this.getViewMode() !== 'savings_squad' || !this.autocompleteDropdown || !this.airedaleTags) return;                          let terms = this.airedaleTags;             if (this.airedaleBrands) {                terms = terms.concat(this.airedaleBrands.map(b => b.formatted_value));             }             terms = [...new Set(terms)];                          const query = this.searchInput.value.trim();             let matches = [];             if (query.length > 0) {                 matches = terms.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase());             } else {                 matches = terms;             }                          if (matches.length > 0) {                 this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                 this.autocompleteDropdown.classList.add('active');             } else {                 this.autocompleteDropdown.classList.remove('active');             }          };          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('focus', showAutocomplete);            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              showAutocomplete();              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  if (this.getViewMode() === 'savings_squad') {                    this.activeDealTag = null;                    this.currentQuery = '';                    if (this.categoryFilter) this.categoryFilter.value = 'all';                    this.fetchDeals('');                  } else {                    this.deals = [];                    this.render();                  }                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                                let isTag = false;                if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;                if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;                this.activeDealTag = isTag ? query : null;                                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   if (query.length === 0 && this.getViewMode() === 'savings_squad') {                       if (this.categoryFilter) this.categoryFilter.value = 'all';                   }                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   if (this.categoryFilter && this.airedaleTags.includes(tag)) {                       this.categoryFilter.value = tag;                   }                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                            let isTag = false;              if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;              if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;              this.activeDealTag = isTag ? query : null;                            this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 if (query.length === 0 && this.getViewMode() === 'savings_squad') {                     if (this.categoryFilter) this.categoryFilter.value = 'all';                 }                 this.fetchDeals(query);              }            });          }          if(this.sortSelect && this.sortSelect.querySelector('option[value="date_desc"]') === null) {              const option = document.createElement('option');              option.value = "date_desc";              option.text = "Newest First";              this.sortSelect.insertBefore(option, this.sortSelect.firstChild);          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               if (val) {                 this.currentQuery = val;               } else {                 if (this.searchInput && this.currentQuery === document.querySelector('#tg-df-brand-trigger')?.getAttribute('data-active-brand')) {                     // don't clear current query if a brand is selected                 } else if (this.searchInput) {                     this.currentQuery = '';                     this.searchInput.value = '';                 }               }               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = 'date_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const finalHref = cardLink.href || cardLink.getAttribute('href') || '';                let actualRevenueId = cardLink.getAttribute('data-revenue-id');                const revMatch = finalHref.match(/(?:subId1|xcust|clickref|ascsubtag)=[^&]*?(\d{18,20})(?:&|$)/i);                if (revMatch && revMatch[1]) {                  actualRevenueId = revMatch[1];                }                const rewrittenLink = finalHref;                const revenueId = actualRevenueId;                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getRowsLimit() {          if (this.rowsSelect && this.rowsSelect.value) return parseInt(this.rowsSelect.value, 10);          let configSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {             configSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {             configSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(configSource);          if (params.has('rows')) return parseInt(params.get('rows'), 10) || 12;          return 12;        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }        async fetchDeals(query) {          this.showLoading();          this.deals = [];          this.displayLimit = this.getRowsLimit();                    try {            console.log("getViewMode returns:", this.getViewMode());            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad();            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query);               } else {                 await this.fetchHawkDeals(query);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const siteParam = this.website || 'tomsguide';            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=${siteParam}&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (!this.activeDealTag && this.currentQuery) {             const tagMatch = this.airedaleTags.find(t => t.toLowerCase() === this.currentQuery.toLowerCase());             if (tagMatch) {                this.activeDealTag = tagMatch;             }          }          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const siteParam = this.website || 'tomsguide';             const url = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let seenUrls = new Set();                    let overallBrandsCounts = {};                    // First pass: extract ALL brands from topArticles so the dropdown has all options          topArticles.forEach((article) => {             if (!article.articlepage) return;             let pageData = [];             try { pageData = JSON.parse(article.articlepage[0]); } catch(e){ console.warn(e); }             const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');             savingsSquad.forEach((block) => {                const data = block.data || {};                if (data.brand) {                   const cleanBrand = data.brand.replace(/^\d+\.\s*/, '').trim();                   overallBrandsCounts[cleanBrand] = (overallBrandsCounts[cleanBrand] || 0) + 1;                }             });          });          targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = this.decodeHTML(description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim());                summaryTitle = this.decodeHTML(summaryTitle);                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                if (externalUrl) {                   if (seenUrls.has(externalUrl)) return;                  seenUrls.add(externalUrl);                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || '',                   authorName: article.articleauthortext ? article.articleauthortext[0] : (article.articleauthor ? article.articleauthor[0] : ''),                   authorRole: article.articleauthorrole ? article.articleauthorrole[0] : '',                   authorImage: article.articleauthormedia ? article.articleauthormedia[0] : '',                   documentUrl: article.documenturl ? article.documenturl[0] : '',                   modifiedDate: article.contentmodifieddate || article.modifieddate || ''                });             });          });                    const airedaleBrandsList = Object.keys(overallBrandsCounts).map(b => ({              formatted_value: b,              count: overallBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    url.searchParams.append('rows', this.getRowsLimit().toString());          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = this.getRowsLimit();          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: this.decodeHTML(item.name || item.title || item.model_name || item.product_name || 'Unknown Product'),            brand: this.decodeHTML(item.brand || ''),            productName: this.decodeHTML(item.model_name || item.product_name || item.name || ''),            merchant: this.decodeHTML(item.merchant_name || item.merchant || item.retailer || 'Retailer'),            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : 'date_desc';          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                ${_div}              ${_div}              \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin:0; border-radius:0;">${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const finalHref = btn.href || btn.getAttribute('href') || '';                let actualRevenueId = btn.getAttribute('data-revenue-id');                const revMatch = finalHref.match(/(?:subId1|xcust|clickref|ascsubtag)=[^&]*?(\d{18,20})(?:&|$)/i);                if (revMatch && revMatch[1]) {                  actualRevenueId = revMatch[1];                }                const rewrittenLink = finalHref;                const revenueId = actualRevenueId;                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)}${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = 'View Deal';              if (isSavingsSquadMode) {                priceGroupHtml = ``;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = isSavingsSquadMode ? `` : `                \x3Cdiv class="tg-df-card-price-group">                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                          \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                          \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                            var c = this.parentNode;                            if (this.dataset.expanded === 'true') {                              var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                              if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                              pd.style.display = '-webkit-box';                              pd.style.webkitLineClamp = '3';                              this.textContent = 'READ MORE';                              this.style.position = 'absolute';                              this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                              this.style.paddingLeft = '16px';                              this.dataset.expanded = 'false';                            } else {                              var pd = this.previousElementSibling;                              pd.style.display = 'inline';                              pd.style.webkitLineClamp = 'unset';                              this.textContent = 'READ LESS';                              this.style.position = 'static';                              this.style.background = 'transparent';                              this.style.paddingLeft = '4px';                              this.dataset.expanded = 'true';                              pd.appendChild(this);                            }                          ">READ MORE${_button}                        \x3C/div>` : ''}                      ${_div}                    ${_div}                    ${deal.authorName ? `                      \x3Cdiv class="tg-df-author-line-mobile" style="padding: 0 0 12px 0; background: transparent;">                         \x3Cdiv style="display: flex; align-items: center; gap: 12px;">                            ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="40" height="40" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 40px; min-height: 40px;">` : ''}                            \x3Cdiv style="display: flex; flex-direction: column;">                               \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">\x3Cspan style="color: #FF6600;">${this.escapeHTML(deal.merchant)}${_span} deal recommended by:${_div}                               \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.3;">                                  \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                  ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                  ${deal.modifiedDate ? `\x3Cdiv style="color: var(--tg-df-text-muted); margin-top: 2px;">${getTimeAgo(deal.modifiedDate)}${_div}` : ''}                               ${_div}                            ${_div}                         ${_div}                      ${_div}                    ` : ''}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>View Deal${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                  \x3Cdiv class="tg-df-card-merchant-wrapper" style="position: absolute; bottom: 0; right: 0; background: transparent; padding: 8px 12px; z-index: 10;">                     \x3Cspan class="tg-df-card-merchant-pill" style="text-align: right; margin-bottom: 0;" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cdiv class="tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                    \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                    \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                      var c = this.parentNode;                      if (this.dataset.expanded === 'true') {                        var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                        if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                        pd.style.display = '-webkit-box';                        pd.style.webkitLineClamp = '3';                        this.textContent = 'READ MORE';                        this.style.position = 'absolute';                        this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                        this.style.paddingLeft = '16px';                        this.dataset.expanded = 'false';                      } else {                        var pd = this.previousElementSibling;                        pd.style.display = 'inline';                        pd.style.webkitLineClamp = 'unset';                        this.textContent = 'READ LESS';                        this.style.position = 'static';                        this.style.background = 'transparent';                        this.style.paddingLeft = '4px';                        this.dataset.expanded = 'true';                        pd.appendChild(this);                      }                    ">READ MORE${_button}                  \x3C/div>` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${deal.authorName ? `                    \x3Cdiv class="tg-df-author-line-desktop" style="padding: 0 0 ${isSavingsSquadMode ? 0 : 12}px 0;">                       \x3Cdiv style="display: flex; align-items: center; gap: 10px;">                          ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="36" height="36" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 36px; min-height: 36px;">` : ''}                          \x3Cdiv style="display: flex; flex-direction: column;">                             \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">Recommended by:${_div}                             \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.2;">                                \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                ${deal.modifiedDate ? `\x3Cspan style="color: var(--tg-df-text-muted);"> • ${getTimeAgo(deal.modifiedDate)}${_span}` : ''}                             ${_div}                          ${_div}                       ${_div}                    ${_div}                    ` : ''}                    ${priceGroupHtml}                  ${_div}                ${_div}                \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta" style="text-decoration: none; border-radius: 0;">${ctaText}${_a}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit) {            dealsHtml += `              \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer;">Load More${_button}              ${_div}            `;          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }          setTimeout(() => {            const contents = this.root.querySelectorAll('.tg-df-card-desc-content');            contents.forEach(p => {              if (p.scrollHeight > p.clientHeight || p.scrollHeight > 60) {                if (p.nextElementSibling) {                  p.nextElementSibling.style.display = 'block';                }              }            });                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));          }, 50);          const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              this.displayLimit += this.getRowsLimit();              this.render();            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/sales-events/black-friday-isnt-here-yet-but-amazon-is-already-offering-up-to-55-percent-off-these-21-home-and-kitchen-appliances</link>
                                                                            <description>
                            <![CDATA[ Amazon is knocking up to 55% off top-rated home and kitchen appliances. Here are my favorite deals to shop now. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">ojyYnqNS2KXrdkRtfpm3i4</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/XjSYKix9eNbH2puRMSG598-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 13 Oct 2026 15:25:23 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Sales Events]]></category>
                                                                                                                    <dc:creator><![CDATA[ Olivia Halevy ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/YAg7Fmh9dGKbg3hULBMWiU-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Olivia is a Deals Writer at Tom’s Guide. She loves all things lifestyle, shopping and sourcing the best deals from some of the top brands, retailers and websites around. From fashion and beauty to smart home and tech, she has an eye for finding practical, stylish, and reasonably-priced items that help make life simpler (and a little more aesthetically-pleasing).&amp;nbsp;Olivia has over five years of experience writing lifestyle, commerce, and branded content for &lt;a href=&quot;http://patch.com/&quot;&gt;Patch.com&lt;/a&gt;. She&#039;s covered major shopping holidays like Amazon Prime Day, Black Friday and Cyber Monday. In her free time, she enjoys trying out new exercise classes, binge-watching the latest viral TV shows, cooking, spending time with family and taking long walks with her dog, Gus.&amp;nbsp;&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/XjSYKix9eNbH2puRMSG598-1920-80.jpg">
                                                            <media:credit><![CDATA[Amazon / edited by Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[appliance deals]]></media:description>                                                            <media:text><![CDATA[appliance deals]]></media:text>
                                <media:title type="plain"><![CDATA[appliance deals]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/XjSYKix9eNbH2puRMSG598-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>October Prime Day is behind us, and Black Friday is still weeks away — but that doesn’t mean the deals have dried up. There are still plenty of worthwhile savings to score between the major shopping events, and one of the most impressive sales I’ve spotted so far is on kitchen and home appliances.</p><p>In fact, <a href="https://www.amazon.com/deals?bubble-id=kitchen" target="_blank" rel="nofollow">Amazon is currently knocking up to 55% off everything from toaster ovens and blenders to air purifiers and vacuums</a>. Many of the deals come courtesy of our favorite brands that we've personally tested — Ninja, Shark, KitchenAid, Dyson and more, to name a few prominent players.</p><p>If you're ready to upgrade your home appliances, I've rounded up the best deals from Amazon that you can shop right now. Plus, don't miss our <a href="https://www.tomsguide.com/coupons/amazon.com">Amazon promo codes</a> page for more ways to save.</p><h3 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h3><ul><li><a href="https://www.amazon.com/deals?bubble-id=kitchen" target="_blank" rel="nofollow"><strong>shop all Amazon kitchen appliance deals</strong></a></li><li><strong>Crock-Pot 7-Quart Slow Cooker: </strong><a href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow"><strong>was $59 now $35</strong></a></li><li><strong>Ninja Blast Max: </strong><a href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow"><strong>was $99 now $69</strong></a></li><li><strong>Keurig K-Express: </strong><a href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow"><strong>was $89 now $69</strong></a></li><li><strong>Shark Never Change Air Purifier: </strong><a href="https://www.amazon.com/dp/B0F1GGDG94?" target="_blank" rel="nofollow"><strong>was $179 now $129</strong></a></li><li><strong>Dreame D20 Air Plus Robot Vacuum: </strong><a href="https://www.amazon.com/dp/B0G5XVMVJN" target="_blank" rel="nofollow"><strong>was $349 now $269</strong></a></li><li><strong>KitchenAid Artisan Series 5 Quart: </strong><a href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow"><strong>was $499 now $379</strong></a></li><li><strong>Breville Barista Express: </strong><a href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow"><strong>was $689 now $499</strong></a></li></ul><h3 class="article-body__section" id="section-best-kitchen-appliance-deals"><span>Best Kitchen Appliance Deals</span></h3><div class="product"><a data-dimension112="0f26c77c-c717-11f1-aa00-5b1f6e05ec2a" data-action="Deal Block" data-label="7-Quart Slow Cooker" data-dimension48="7-Quart Slow Cooker" data-dimension25="$35" href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1080px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="xxEFYRjw4hJpt8rETUuaiH" name="Crock-Pot 7-Quart Slow Cooker" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xxEFYRjw4hJpt8rETUuaiH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>This 7-quart slow cooker is the perfect size to house a big batch of chili or queso to snack on all day. Or you can plan ahead and slow cook a melt-in-your-mouth roast with some carrots and potatoes for an easy dinner.<a class="view-deal button" href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow" data-dimension112="0f26c77c-c717-11f1-aa00-5b1f6e05ec2a" data-action="Deal Block" data-label="7-Quart Slow Cooker" data-dimension48="7-Quart Slow Cooker" data-dimension25="$35">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c7fe-c717-11f1-bfd2-0bf8059f1e58" data-action="Deal Block" data-label="Blast Max" data-dimension48="Blast Max" data-dimension25="$69" href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1216px;"><p class="vanilla-image-block" style="padding-top:123.36%;"><img id="9Q4QY399FaozAFUt4j8dTW" name="ninja-blast-max-portable-blender--twist--bb517479-54ce-4a77-974c-58e2f44dde33.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/9Q4QY399FaozAFUt4j8dTW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1216" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Ninja Blast Max is capable of taking on any challenge you throw at it, including crushing ice and blitzing berries to make yummy smoothies. It comes with multiple blend settings to make sure your blender is using the right level of power for the task at hand, and the compact size means it’s a great option for anyone with a small kitchen. <a class="view-deal button" href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow" data-dimension112="0f26c7fe-c717-11f1-bfd2-0bf8059f1e58" data-action="Deal Block" data-label="Blast Max" data-dimension48="Blast Max" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c862-c717-11f1-92f4-dbbba92440d2" data-action="Deal Block" data-label="Cordless Citrus Juicer" data-dimension48="Cordless Citrus Juicer" data-dimension25="$79" href="https://www.amazon.com/KitchenAid-Cordless-Citrus-Juicer-separately/dp/B0DN6RX5Q3" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:964px;"><p class="vanilla-image-block" style="padding-top:155.60%;"><img id="HmFhrr2KfXYEaCMCSBwkhL" name="KitchenAid Go Cordless Citrus Juicer" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HmFhrr2KfXYEaCMCSBwkhL-1920-80.jpg" mos="" align="middle" fullscreen="" width="964" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The KitchenAid Go Cordless Citrus Juicer makes it so simple to have fresh juice every morning with minimal mess. If you hate pulp in your juice, this won’t be for you. But if you’re looking for the fastest way to juice your citrus, this is the answer. It’s simple to clean too, since the top half of the appliance is dishwasher-friendly.<a class="view-deal button" href="https://www.amazon.com/KitchenAid-Cordless-Citrus-Juicer-separately/dp/B0DN6RX5Q3" target="_blank" rel="nofollow" data-dimension112="0f26c862-c717-11f1-92f4-dbbba92440d2" data-action="Deal Block" data-label="Cordless Citrus Juicer" data-dimension48="Cordless Citrus Juicer" data-dimension25="$79">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c8d0-c717-11f1-a8e1-93a83928f07c" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$89" href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="EBqQHURi67ApM2ai2joGg6" name="_0007_CHEFMAN Multifunctional Digital Air Fryer+" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/EBqQHURi67ApM2ai2joGg6-1920-80.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow" data-dimension112="0f26c8d0-c717-11f1-a8e1-93a83928f07c" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$89">Multifunctional Digital Air Fryer: was $139 now $89</a></strong><br />An extra large digital air fryer, this CHEFMAN model has 17 presets and an easy-to-use touch screen so you can get cooking immediately. It's big enough for family-sized meals, party-sized appetizers and has a window so you can check your cooking without opening it.<a class="view-deal button" href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow" data-dimension112="0f26c8d0-c717-11f1-a8e1-93a83928f07c" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c934-c717-11f1-a3a0-c73f0e1578db" data-action="Deal Block" data-label="Air Fryer XL" data-dimension48="Air Fryer XL" data-dimension25="$119" href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B0CS3V8M9H?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1367px;"><p class="vanilla-image-block" style="padding-top:109.73%;"><img id="MvRPAsDrHySaXiXmcEDdLn" name="Ninja Air Fryer XL" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/MvRPAsDrHySaXiXmcEDdLn-1920-80.jpg" mos="" align="middle" fullscreen="" width="1367" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B0CS3V8M9H?" target="_blank" rel="nofollow" data-dimension112="0f26c934-c717-11f1-a3a0-c73f0e1578db" data-action="Deal Block" data-label="Air Fryer XL" data-dimension48="Air Fryer XL" data-dimension25="$119">Air Fryer XL: was $179 now $119</a></strong><br />The Ninja Pro XL 6-in-1 air fryer does everything you need an air fryer to. It cooks, it crisps, it bakes. It's the ideal first air fryer because it does utterly everything you could want. As someone who's used a lot of Ninja tech, I can also say with confidence that it's intuitive and easy to use. Ninja never lets you down.<a class="view-deal button" href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B0CS3V8M9H?" target="_blank" rel="nofollow" data-dimension112="0f26c934-c717-11f1-a3a0-c73f0e1578db" data-action="Deal Block" data-label="Air Fryer XL" data-dimension48="Air Fryer XL" data-dimension25="$119">View Deal</a></p></div><div class="product"><a data-dimension112="0f26c9c0-c717-11f1-a952-eb018f8e28f1" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$69" href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:230.93%;"><img id="SNGj6WoG25u9rj7PA3Zhre" name="Keurig K Express" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SNGj6WoG25u9rj7PA3Zhre-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="1568" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow" data-dimension112="0f26c9c0-c717-11f1-a952-eb018f8e28f1" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$69">K-Express: was $89 now $69</a></strong><br />The Keurig Express offers three cup sizes — 8, 10 and 12 oz and has a 42 oz detachable water reservoir, making it easy to remove, fill or clean. By removing the drip tray you can position a travel mug up to 7.4 inches tall under the brew stream. <a class="view-deal button" href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow" data-dimension112="0f26c9c0-c717-11f1-a952-eb018f8e28f1" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="0f26ca24-c717-11f1-8a2f-a332ea1e9bd7" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99" href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:99.56%;"><img id="4uiaRXRKY8Go6F4ZpM7UdA" name="Ninja coffee" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4uiaRXRKY8Go6F4ZpM7UdA-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="676" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow" data-dimension112="0f26ca24-c717-11f1-8a2f-a332ea1e9bd7" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99">Single Serve Coffee Maker with Pods and Grounds: was $129 now $99</a></strong><br />This stylish Ninja coffee maker comes in a gorgeous choice of colorways, including Sage Green, and is now on sale for $30 off. Whether you prefer pods or grounds, this device makes tasty brews in 7 sizes (6-oz. to 24-oz) and has a built-in, fold-away milk frother! The only problem you'll have is deciding which color to choose.<a class="view-deal button" href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow" data-dimension112="0f26ca24-c717-11f1-8a2f-a332ea1e9bd7" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="0f26ca88-c717-11f1-9d0c-a7ed1a74c9b4" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89" href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:717px;"><p class="vanilla-image-block" style="padding-top:163.18%;"><img id="LpQPvQCcU8GNALWdf2GLs4" name="51EcND+lspL._AC_SL1173_.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/LpQPvQCcU8GNALWdf2GLs4-1920-80.jpg" mos="" align="middle" fullscreen="" width="717" height="1170" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow" data-dimension112="0f26ca88-c717-11f1-9d0c-a7ed1a74c9b4" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89">PerfecTemp Cordless Electric Kettle: was $129 now $89</a></strong><br />This sleek electric Kettle heats and boils your brews quickly. With six preset heating profiles to choose from, it can extract the most flavor out of your tea or morning coffee. We rank it as one of the <a href="https://www.tomsguide.com/best-picks/the-best-electric-kettles">best electric kettles</a>.<a class="view-deal button" href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow" data-dimension112="0f26ca88-c717-11f1-9d0c-a7ed1a74c9b4" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cb32-c717-11f1-86a1-4563d8f6d155" data-action="Deal Block" data-label="NeverClog Cold Press Juicer" data-dimension48="NeverClog Cold Press Juicer" data-dimension25="$129" href="https://www.amazon.com/dp/B0BR8HZL9V?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1499px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="2WLwjdnMeBZu5mrkYrS2jH" name="Ninja NeverClog Cold Press Juicer" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/2WLwjdnMeBZu5mrkYrS2jH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1499" height="1499" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>Ninja's NeverClog Cold Press Juicer removes the hassle of juicing fruits and vegetables. The special filter pushes pulp through without clogging and lets you customize the amount of pulp in your juice with two interchangeable pulp filters. It comes with a 24-oz juice jug and a 36-oz pulp container, allowing you to make large batches of juice, rather than single servings.<a class="view-deal button" href="https://www.amazon.com/dp/B0BR8HZL9V?" target="_blank" rel="nofollow" data-dimension112="0f26cb32-c717-11f1-86a1-4563d8f6d155" data-action="Deal Block" data-label="NeverClog Cold Press Juicer" data-dimension48="NeverClog Cold Press Juicer" data-dimension25="$129">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cb96-c717-11f1-86ff-2918f2e4cacd" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149" href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1676px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="sWibiMn9jcqpLxyQRazy6f" name="Ninja Amazon 2.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/sWibiMn9jcqpLxyQRazy6f-1920-80.jpg" mos="" align="middle" fullscreen="" width="1676" height="1676" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow" data-dimension112="0f26cb96-c717-11f1-86ff-2918f2e4cacd" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149">Mega Kitchen System: was $219 now $149</a></strong><br />Leave all the multi-tasking in the kitchen to one appliance with this Ninja blender. With four functions for smoothies, processing, dough, drinks and more it will quickly become your go-to kitchen appliance. With this ultimate appliance, you’ll be enjoying fresh, healthy drinks, homemade bread and sweet bakes.<a class="view-deal button" href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow" data-dimension112="0f26cb96-c717-11f1-86ff-2918f2e4cacd" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cbfa-c717-11f1-bd56-e95c2b871575" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379" href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:91.20%;"><img id="HPfDur99xHfhfWNbGej8ZE" name="KitchenAid Artisan Mixer.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HPfDur99xHfhfWNbGej8ZE-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1368" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow" data-dimension112="0f26cbfa-c717-11f1-bd56-e95c2b871575" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379">Artisan Series 5 Quart: was $499 now $379</a></strong><br />A Tom's Guide favorite, in our <a href="https://www.tomsguide.com/opinion/the-kitchenaid-artisan-stand-mixer-is-my-best-kitchen-purchase-ever-heres-why">KitchenAid Artisan 5-Quart stand mixer review</a>, we dubbed it the "best kitchen purchase" you can ever make. It beats, whisks, and kneads at 10 different speeds, so you don't have to, reducing recipe times. The bowl is big enough to support 9 dozen cookies or 4 loaves of bread at a time. This machine also boasts a 59-point planetary mixing action — fancy words that translate into incredibly mixed ingredients. Plus, it ships with a flat beater, coated dough hook, 6-wire whip, and 1-piece pouring shield. <a class="view-deal button" href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow" data-dimension112="0f26cbfa-c717-11f1-bd56-e95c2b871575" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cc5e-c717-11f1-88a9-a9441d0fac87" data-action="Deal Block" data-label="Barista Express" data-dimension48="Barista Express" data-dimension25="$499" href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1306px;"><p class="vanilla-image-block" style="padding-top:114.85%;"><img id="xqb7yApNa26xAkZLUbt3tW" name="breville barista express.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xqb7yApNa26xAkZLUbt3tW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1306" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Breville Barista Express is one of the most iconic and respected bean-to-cup espresso machines ever made. Although it's been out for around 6 years at this point, the Barista Express shows no signs of slowing down. Right now it's just $499, which is the same price as Breville's compact Bambino Plus. You basically get a free grinder.<a class="view-deal button" href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow" data-dimension112="0f26cc5e-c717-11f1-88a9-a9441d0fac87" data-action="Deal Block" data-label="Barista Express" data-dimension48="Barista Express" data-dimension25="$499">View Deal</a></p></div><h3 class="article-body__section" id="section-best-home-appliance-deals"><span>Best Home Appliance Deals</span></h3><div class="product"><a data-dimension112="0f26cd26-c717-11f1-85c9-771a37eb4a98" data-action="Deal Block" data-label="Core Smart Air Purifier 200S-P" data-dimension48="Core Smart Air Purifier 200S-P" data-dimension25="$74" href="https://www.amazon.com/LEVOIT-Purifier-Allergies-Core-200S/dp/B08FJ678YK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1290px;"><p class="vanilla-image-block" style="padding-top:116.28%;"><img id="MUF285tRsNNeQZcGQueo6f" name="LEVOIT Air Purifier" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/MUF285tRsNNeQZcGQueo6f-1920-80.jpg" mos="" align="middle" fullscreen="" width="1290" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/LEVOIT-Purifier-Allergies-Core-200S/dp/B08FJ678YK" target="_blank" rel="nofollow" data-dimension112="0f26cd26-c717-11f1-85c9-771a37eb4a98" data-action="Deal Block" data-label="Core Smart Air Purifier 200S-P" data-dimension48="Core Smart Air Purifier 200S-P" data-dimension25="$74">Core Smart Air Purifier 200S-P: was $89 now $74</a></strong><br />If you’re after a small yet powerful purifier that can handle mid-large spaces, this Levoit Core smart model is ideal. It comes with a three-stage filtration, and has an auto feature that scans the air for particles and adjusts the fan speed accordingly. Plus, it sends back real-time reports to your phone, for added convenience.<a class="view-deal button" href="https://www.amazon.com/LEVOIT-Purifier-Allergies-Core-200S/dp/B08FJ678YK" target="_blank" rel="nofollow" data-dimension112="0f26cd26-c717-11f1-85c9-771a37eb4a98" data-action="Deal Block" data-label="Core Smart Air Purifier 200S-P" data-dimension48="Core Smart Air Purifier 200S-P" data-dimension25="$74">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cd8a-c717-11f1-b02a-4386a5dfc249" data-action="Deal Block" data-label="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension48="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension25="$86" href="https://www.amazon.com/BISSELL-Upholstery-HydroRinse-Self-Cleaning-4075/dp/B0DJMP6T3N" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:99.85%;"><img id="cbDzFRwy4MhLMix2v6GC7D" name="Little green mini" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/cbDzFRwy4MhLMix2v6GC7D-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="678" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/BISSELL-Upholstery-HydroRinse-Self-Cleaning-4075/dp/B0DJMP6T3N" target="_blank" rel="nofollow" data-dimension112="0f26cd8a-c717-11f1-b02a-4386a5dfc249" data-action="Deal Block" data-label="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension48="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension25="$86">Little Green Mini Portable Carpet and Upholstery Deep Cleaner: was $99 now $86</a></strong><br />This is a great discount for the mini version of the portable stain removing vacuum that can be used to remove spills and messes created by the whole family, including pets. The clean water tank has a 16 oz capacity, giving you more time between emptying and refilling. Plus, it comes with a 4-inch tough stain tool, HydroRinse self-cleaning hose tool, and trial size cleaning solution.<a class="view-deal button" href="https://www.amazon.com/BISSELL-Upholstery-HydroRinse-Self-Cleaning-4075/dp/B0DJMP6T3N" target="_blank" rel="nofollow" data-dimension112="0f26cd8a-c717-11f1-b02a-4386a5dfc249" data-action="Deal Block" data-label="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension48="Little Green Mini Portable Carpet and Upholstery Deep Cleaner" data-dimension25="$86">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cdee-c717-11f1-b23a-751d1a137976" data-action="Deal Block" data-label="Never Change Air Purifier" data-dimension48="Never Change Air Purifier" data-dimension25="$129" href="https://www.amazon.com/dp/B0F1GGDG94?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1006px;"><p class="vanilla-image-block" style="padding-top:149.11%;"><img id="oTnJrM8YckF83ojojweeS6" name="Shark NeverChange Compact" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/oTnJrM8YckF83ojojweeS6-1920-80.jpg" mos="" align="middle" fullscreen="" width="1006" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0F1GGDG94?" target="_blank" rel="nofollow" data-dimension112="0f26cdee-c717-11f1-b23a-751d1a137976" data-action="Deal Block" data-label="Never Change Air Purifier" data-dimension48="Never Change Air Purifier" data-dimension25="$129">Never Change Air Purifier: was $179 now $129</a></strong><br />Named the <a href="https://www.tomsguide.com/best-picks/best-air-purifier">best air purifier</a> for small spaces in our guide, this Shark air purifier suits rooms up to 250 sq ft, although this is based on one change of air over an hour. With an auto mode, it adjusts the fan speed based on the quality of the air and displays the corresponding data on the panel. It also has Odor Neutralizer Technology, that releases a fresh scent in the air.<a class="view-deal button" href="https://www.amazon.com/dp/B0F1GGDG94?" target="_blank" rel="nofollow" data-dimension112="0f26cdee-c717-11f1-b23a-751d1a137976" data-action="Deal Block" data-label="Never Change Air Purifier" data-dimension48="Never Change Air Purifier" data-dimension25="$129">View Deal</a></p></div><div class="product"><a data-dimension112="0f26ce52-c717-11f1-ba27-8bbc73b60570" data-action="Deal Block" data-label="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension48="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension25="$179" href="https://www.amazon.com/Shark-IZ662H-Lightweight-Multi-Tool-Anti-Allergen/dp/B0GZSST8ZT?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:863px;"><p class="vanilla-image-block" style="padding-top:173.81%;"><img id="QQQeiV62353jSCQyEPosXQ" name="Shark Cordless Pet" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/QQQeiV62353jSCQyEPosXQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="863" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Shark-IZ662H-Lightweight-Multi-Tool-Anti-Allergen/dp/B0GZSST8ZT?" target="_blank" rel="nofollow" data-dimension112="0f26ce52-c717-11f1-ba27-8bbc73b60570" data-action="Deal Block" data-label="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension48="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension25="$179">Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red): was $299 now $179</a></strong><br />This lightweight cordless vacuum cleaner can handle just about any task. Equipped with powerful suction, it comes with a multiflex wand that can tackle hard-to-reach places, DuoClean PowerFins, and a self-cleaning brushroll (great for pet hair). It also has a 40-minute runtime on a single charge.<a class="view-deal button" href="https://www.amazon.com/Shark-IZ662H-Lightweight-Multi-Tool-Anti-Allergen/dp/B0GZSST8ZT?" target="_blank" rel="nofollow" data-dimension112="0f26ce52-c717-11f1-ba27-8bbc73b60570" data-action="Deal Block" data-label="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension48="Cordless Vertex Pro Lightweight Cordless Stick Vacuum (Red)" data-dimension25="$179">View Deal</a></p></div><div class="product"><a data-dimension112="0f26ceb6-c717-11f1-942d-5d7dbb5f4bbf" data-action="Deal Block" data-label="HydroVac MessMaster wet and dry vacuum" data-dimension48="HydroVac MessMaster wet and dry vacuum" data-dimension25="$199" href="https://www.amazon.com/Shark-Multi-Surface-Self-Cleaning-Lightweight-WD261/dp/B0CZSBYB5V/ref" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="oDxSkPexrniGToXj2psqek" name="shark messmaster deal block" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/oDxSkPexrniGToXj2psqek-1920-80.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Shark-Multi-Surface-Self-Cleaning-Lightweight-WD261/dp/B0CZSBYB5V/ref" target="_blank" rel="nofollow" data-dimension112="0f26ceb6-c717-11f1-942d-5d7dbb5f4bbf" data-action="Deal Block" data-label="HydroVac MessMaster wet and dry vacuum" data-dimension48="HydroVac MessMaster wet and dry vacuum" data-dimension25="$199">HydroVac MessMaster wet and dry vacuum: was $299 now $199</a></strong><br />The Shark HydroVac MessMaster is one of the easiest wet and dry vacuums to use. It's so much lighter and easier than lugging around a mop, and the self-cleaning roller means it won't dispense mess back onto your floors. <a class="view-deal button" href="https://www.amazon.com/Shark-Multi-Surface-Self-Cleaning-Lightweight-WD261/dp/B0CZSBYB5V/ref" target="_blank" rel="nofollow" data-dimension112="0f26ceb6-c717-11f1-942d-5d7dbb5f4bbf" data-action="Deal Block" data-label="HydroVac MessMaster wet and dry vacuum" data-dimension48="HydroVac MessMaster wet and dry vacuum" data-dimension25="$199">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cf24-c717-11f1-a1a4-8bc1f1ae6688" data-action="Deal Block" data-label="Braava Jet M6" data-dimension48="Braava Jet M6" data-dimension25="$199" href="https://www.amazon.com/iRobot-Ultimate-Connected-Precision-Recharges/dp/B07QNM91NQ" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="bCAuL9bEPqJMBC5VpP4ji9" name="Braava jet m6.jpeg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/bCAuL9bEPqJMBC5VpP4ji9-1920-80.jpeg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/iRobot-Ultimate-Connected-Precision-Recharges/dp/B07QNM91NQ" target="_blank" rel="nofollow" data-dimension112="0f26cf24-c717-11f1-a1a4-8bc1f1ae6688" data-action="Deal Block" data-label="Braava Jet M6" data-dimension48="Braava Jet M6" data-dimension25="$199">Braava Jet M6: was $449 now $199</a></strong><br />Voted our <a href="https://www.tomsguide.com/best-picks/best-robot-mops">best robot mop,</a> this model provides a thorough cleaning performance that dries quickly. The accurate navigation and tight controls are impressive, with the ability to clean specific rooms on the map. It also link up to work together with compatible Roombas to boot.<a class="view-deal button" href="https://www.amazon.com/iRobot-Ultimate-Connected-Precision-Recharges/dp/B07QNM91NQ" target="_blank" rel="nofollow" data-dimension112="0f26cf24-c717-11f1-a1a4-8bc1f1ae6688" data-action="Deal Block" data-label="Braava Jet M6" data-dimension48="Braava Jet M6" data-dimension25="$199">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cf7e-c717-11f1-8deb-71f932728829" data-action="Deal Block" data-label="D20 Air Plus Robot Vacuum" data-dimension48="D20 Air Plus Robot Vacuum" data-dimension25="$269" href="https://www.amazon.com/dp/B0G5XVMVJN" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:82.60%;"><img id="tL9ig3M9LUrD4yX7axWboE" name="Dreame D20 Air Plus Robot Vacuum" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/tL9ig3M9LUrD4yX7axWboE-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1239" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0G5XVMVJN" target="_blank" rel="nofollow" data-dimension112="0f26cf7e-c717-11f1-8deb-71f932728829" data-action="Deal Block" data-label="D20 Air Plus Robot Vacuum" data-dimension48="D20 Air Plus Robot Vacuum" data-dimension25="$269">D20 Air Plus Robot Vacuum: was $349 now $269</a></strong><br />The Dreame D20 Air Plus can clean and mop your floors. It features 20,000Pa suction power for cleaning and a built-in electronic water tank for mopping. It uses LiDAR technology to navigate through your home and it automatically docks when it's time to empty out its bin. We also appreciate its 4L sealed dust bag that traps up to 120 days worth of dust, pet hair, and debris. <a class="view-deal button" href="https://www.amazon.com/dp/B0G5XVMVJN" target="_blank" rel="nofollow" data-dimension112="0f26cf7e-c717-11f1-8deb-71f932728829" data-action="Deal Block" data-label="D20 Air Plus Robot Vacuum" data-dimension48="D20 Air Plus Robot Vacuum" data-dimension25="$269">View Deal</a></p></div><div class="product"><a data-dimension112="0f26cfe2-c717-11f1-8557-916e8f29abce" data-action="Deal Block" data-label="V8 Cordless" data-dimension48="V8 Cordless" data-dimension25="$269" href="https://www.amazon.com/Dyson-626423-01-V8TM-Cordless-Vacuum/dp/B0GT2DG9SK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="3sSBPzCpGfLBqHoGiHApw4" name="Dyson V8 Absolute" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/3sSBPzCpGfLBqHoGiHApw4-1920-80.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Dyson-626423-01-V8TM-Cordless-Vacuum/dp/B0GT2DG9SK" target="_blank" rel="nofollow" data-dimension112="0f26cfe2-c717-11f1-8557-916e8f29abce" data-action="Deal Block" data-label="V8 Cordless" data-dimension48="V8 Cordless" data-dimension25="$269">V8 Cordless: was $389 now $269</a></strong><br />The Dyson V8 gets you up to 40 minutes of fade-free power. It also comes with two cleaning heads, the Hair Screw Tool (to pick up long hair without tangles), and two additional attachments. We also like that it features HEPA filtration and an additional cleaner head for hard floors​.<a class="view-deal button" href="https://www.amazon.com/Dyson-626423-01-V8TM-Cordless-Vacuum/dp/B0GT2DG9SK" target="_blank" rel="nofollow" data-dimension112="0f26cfe2-c717-11f1-8557-916e8f29abce" data-action="Deal Block" data-label="V8 Cordless" data-dimension48="V8 Cordless" data-dimension25="$269">View Deal</a></p></div><div class="product"><a data-dimension112="0f26d046-c717-11f1-8fb5-55e98d2348d8" data-action="Deal Block" data-label="AI Ultra Voice Control Robot Vacuum" data-dimension48="AI Ultra Voice Control Robot Vacuum" data-dimension25="$269" href="https://www.amazon.com/Shark-AV2511AE-Self-Empty-Capacity-Navigation/dp/B09T4YZGQR" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1438px;"><p class="vanilla-image-block" style="padding-top:93.05%;"><img id="BbfJrbM56fV2krqdoLohGm" name="Shark Robot Vac" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/BbfJrbM56fV2krqdoLohGm-1920-80.png" mos="" align="middle" fullscreen="" width="1438" height="1338" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Shark-AV2511AE-Self-Empty-Capacity-Navigation/dp/B09T4YZGQR" target="_blank" rel="nofollow" data-dimension112="0f26d046-c717-11f1-8fb5-55e98d2348d8" data-action="Deal Block" data-label="AI Ultra Voice Control Robot Vacuum" data-dimension48="AI Ultra Voice Control Robot Vacuum" data-dimension25="$269">AI Ultra Voice Control Robot Vacuum: was $599 now $269</a></strong><br />With a 55% discount, this makes this Shark robot vacuum a steal. With impressive suction power, this can easily pick up dirt, debris and pet hair on all floor types. It also has tons of features like Matrix Clean, precision mapping, AI voice control and a 60-day self-emptying capacity.  <a class="view-deal button" href="https://www.amazon.com/Shark-AV2511AE-Self-Empty-Capacity-Navigation/dp/B09T4YZGQR" target="_blank" rel="nofollow" data-dimension112="0f26d046-c717-11f1-8fb5-55e98d2348d8" data-action="Deal Block" data-label="AI Ultra Voice Control Robot Vacuum" data-dimension48="AI Ultra Voice Control Robot Vacuum" data-dimension25="$269">View Deal</a></p></div><h3 class="article-body__section" id="section-shop-more-deals"><span>Shop more deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=Everything&amp;retailer=Amazon&amp;rows=8&amp;view_mode=savings_squad&amp;widget_title=Top+Amazon+Deals+Handpicked+by+Our+Editors&amp;widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&amp;bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function getTimeAgo(dateString) {        if (!dateString) return '';        const date = new Date(dateString);        const now = new Date();        const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);        if (diffInSeconds < 60) return 'Just now';        const diffInMinutes = Math.floor(diffInSeconds / 60);        if (diffInMinutes < 60) return `${diffInMinutes} min${diffInMinutes > 1 ? 's' : ''} ago`;        const diffInHours = Math.floor(diffInMinutes / 60);        if (diffInHours < 24) return `${diffInHours} hr${diffInHours > 1 ? 's' : ''} ago`;        const diffInDays = Math.floor(diffInHours / 24);        if (diffInDays < 30) return `${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`;        const diffInMonths = Math.floor(diffInDays / 30);        if (diffInMonths < 12) return `${diffInMonths} mo${diffInMonths > 1 ? 's' : ''} ago`;        const diffInYears = Math.floor(diffInDays / 365);        return `${diffInYears} yr${diffInYears > 1 ? 's' : ''} ago`;      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;      position: relative;      z-index: 20;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      margin: 0 auto;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {      display: grid;      width: 100%;      grid-template-columns: repeat(4, 1fr);      gap: 12px;      margin: 0 auto;      max-width: 800px;    }                 .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;      width: 100%;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      width: 100%;      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }    @container tg-df (max-width: 768px) {      .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {        width: 100%;        margin: 0;        margin-bottom: -320px;        padding: 0 16px 320px 16px;        display: flex;        flex-wrap: nowrap;        gap: 8px;        overflow-x: auto;        overflow-y: hidden;        pointer-events: none;        scrollbar-width: none;        -webkit-overflow-scrolling: touch;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }      .tg-df-sort-wrapper {        pointer-events: auto;        flex: 0 0 auto;        width: 175px;        min-width: 175px;      }    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 120px;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 16px 16px 8px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }                  .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;        width: auto;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;      width: 100vw;      max-width: 1200px;      position: relative;      left: 50%;      transform: translateX(-50%);    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 14px;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    .tg-df-grid-wrapper { position: relative; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn {      display: inline-flex;      align-items: center;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.40);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #1f69ff; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #0056e0; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }    .tg-df-savings-squad-header { margin-bottom: 24px; text-align: center; display: none; }    .tg-df-banner-img-desktop { display: block; width: 100%; height: auto; margin-bottom: 32px; }    .tg-df-banner-img-mobile { display: none; width: 100%; height: auto; margin-bottom: 32px; }    @container tg-df (max-width: 600px) {      .tg-df-banner-img-desktop { display: none; }      .tg-df-banner-img-mobile { display: block; }    }    .tg-df-header-title { font-size: 28px; font-weight: 700; color: var(--tg-df-text); margin: 32px 0 12px 0; line-height: 1.3; }    .tg-df-header-subtitle { font-size: 16px; color: var(--tg-df-text-muted); margin: 0 0 32px 0; line-height: 1.5; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3Cdiv class="tg-df-savings-squad-header" id="tg-df-savings-squad-header">      \x3Cpicture>        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/xkh2og7m3d1778189998.png" alt="Deals Banner" class="tg-df-banner-img-desktop" />        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/gmak6rtdf41778245089.png" alt="Deals Banner Mobile" class="tg-df-banner-img-mobile" />      \x3C/picture>      \x3Cdiv class="tg-df-header-text">        \x3Ch2 class="tg-df-header-title" id="tg-df-header-title">Editor's Choice Deals\x3C/h2>        \x3Cp class="tg-df-header-subtitle" id="tg-df-header-subtitle">Discover the best discounts currently available, curated daily by the Tom's Guide Savings Squad.\x3C/p>      \x3C/div>    \x3C/div>    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Televisions" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/wcMxTsHgqu3roMbAx7RLnT-132-100.png" alt="TVs" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">TVs\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Phones" data-pr="over50">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/G3KGaRGzj24F6PUsw4bWpT-132-100.png" alt="Phones" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Phones\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Computing" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/znNvsLzx8NEgNkD9HSFSnT-132-100.png" alt="Computing" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Computing\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Gaming" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/Pgew8yaRQeZFHqHjTzvBnT-132-100.png" alt="Gaming" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Gaming\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Mattresses" data-pr="over500">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/cW7xsaLyesxkHFVSiC4kmT-132-100.png" alt="Mattresses" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Mattresses\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Audio" data-pr="over30">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/pCvBVHuhaQVjKt3VgCjbqT-132-100.png" alt="Audio" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Audio\x3C/span>            \x3C/div>                  \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E      \x3Cdiv class="tg-df-top-bar" id="tg-df-top-bar" style="position: relative; z-index: 100; margin: 0 auto 20px;">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>      \x3C/div>    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">              \x3Cdiv class="tg-df-filters-container" style="position: relative; width: 100%; max-width: 800px; margin: 0 auto;">          \x3Cbutton class="tg-df-scroll-btn left" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: -200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M15 18l-6-6 6-6"/>\x3C/svg>          \x3C/button>          \x3Cbutton class="tg-df-scroll-btn right" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: 200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M9 18l6-6-6-6"/>\x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-filters">          \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>          \x3C/div>        \x3C/div>        \x3C/div>      \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();        }        getViewMode() {          console.log("DEBUG getViewMode -> override:", this.viewModeOverride, "editorMode:", this.editorMode);          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          console.log("[DEBUG] applyLayoutMode CALLED! mode=", mode);          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          const showHeaderDetails = params.get('show_header_details') !== 'false';          const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          const topBarDiv = this.root.querySelector('#tg-df-top-bar');          const headerElement = this.root.querySelector('#tg-df-savings-squad-header');          if (headerElement) {             headerElement.style.display = (mode === 'savings_squad' && showHeaderDetails) ? 'block' : 'none';          }          if (mode === 'carousel') {             this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (topBarDiv) topBarDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.add('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (topBarDiv) topBarDiv.style.display = 'block';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!this.viewModeOverride && initialViewMode) {            this.viewModeOverride = initialViewMode;          }          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Gaming laptops';          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button, .tg-df-container .tg-df-card-cta { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover, .tg-df-container .tg-df-card-cta:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (this.viewModeSelect && params.has('view_mode')) {            this.viewModeSelect.value = params.get('view_mode');          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'date_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }          const headerTitleEl = this.root.querySelector('#tg-df-header-title');          const headerSubtitleEl = this.root.querySelector('#tg-df-header-subtitle');          if (params.has('widget_title') && headerTitleEl) {             headerTitleEl.textContent = params.get('widget_title');          }          if (params.has('widget_subtitle') && headerSubtitleEl) {             headerSubtitleEl.textContent = params.get('widget_subtitle');          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            if (this.getViewMode() === 'savings_squad') {              this.searchInput.value = '';            } else {              this.searchInput.value = this.currentQuery;            }          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'date_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const handleFiltersScroll = () => {            const filters = this.root.querySelector('.tg-df-filters');            const leftBtn = this.root.querySelector('.tg-df-scroll-btn.left');            const rightBtn = this.root.querySelector('.tg-df-scroll-btn.right');            if (filters && leftBtn && rightBtn) {              const { scrollLeft, scrollWidth, clientWidth } = filters;              leftBtn.style.display = scrollLeft > 0 ? 'flex' : 'none';              rightBtn.style.display = Math.ceil(scrollLeft + clientWidth) < scrollWidth - 5 ? 'flex' : 'none';            }          };          const filters = this.root.querySelector('.tg-df-filters');          if (filters) {            filters.addEventListener('scroll', handleFiltersScroll);            window.addEventListener('resize', handleFiltersScroll);            setTimeout(handleFiltersScroll, 100);                        // Also call after rendering dropdowns            const origRenderCategories = this.renderCategories;            if (origRenderCategories) {               this.renderCategories = (...args) => {                 origRenderCategories.apply(this, args);                 setTimeout(handleFiltersScroll, 50);               };            }          }                const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          const showAutocomplete = () => {             if (this.getViewMode() !== 'savings_squad' || !this.autocompleteDropdown || !this.airedaleTags) return;                          let terms = this.airedaleTags;             if (this.airedaleBrands) {                terms = terms.concat(this.airedaleBrands.map(b => b.formatted_value));             }             terms = [...new Set(terms)];                          const query = this.searchInput.value.trim();             let matches = [];             if (query.length > 0) {                 matches = terms.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase());             } else {                 matches = terms;             }                          if (matches.length > 0) {                 this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                 this.autocompleteDropdown.classList.add('active');             } else {                 this.autocompleteDropdown.classList.remove('active');             }          };          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('focus', showAutocomplete);            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              showAutocomplete();              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  if (this.getViewMode() === 'savings_squad') {                    this.activeDealTag = null;                    this.currentQuery = '';                    if (this.categoryFilter) this.categoryFilter.value = 'all';                    this.fetchDeals('');                  } else {                    this.deals = [];                    this.render();                  }                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                                let isTag = false;                if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;                if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;                this.activeDealTag = isTag ? query : null;                                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   if (query.length === 0 && this.getViewMode() === 'savings_squad') {                       if (this.categoryFilter) this.categoryFilter.value = 'all';                   }                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   if (this.categoryFilter && this.airedaleTags.includes(tag)) {                       this.categoryFilter.value = tag;                   }                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                            let isTag = false;              if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;              if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;              this.activeDealTag = isTag ? query : null;                            this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 if (query.length === 0 && this.getViewMode() === 'savings_squad') {                     if (this.categoryFilter) this.categoryFilter.value = 'all';                 }                 this.fetchDeals(query);              }            });          }          if(this.sortSelect && this.sortSelect.querySelector('option[value="date_desc"]') === null) {              const option = document.createElement('option');              option.value = "date_desc";              option.text = "Newest First";              this.sortSelect.insertBefore(option, this.sortSelect.firstChild);          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               if (val) {                 this.currentQuery = val;               } else {                 if (this.searchInput && this.currentQuery === document.querySelector('#tg-df-brand-trigger')?.getAttribute('data-active-brand')) {                     // don't clear current query if a brand is selected                 } else if (this.searchInput) {                     this.currentQuery = '';                     this.searchInput.value = '';                 }               }               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = 'date_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const finalHref = cardLink.href || cardLink.getAttribute('href') || '';                let actualRevenueId = cardLink.getAttribute('data-revenue-id');                const revMatch = finalHref.match(/(?:subId1|xcust|clickref|ascsubtag)=[^&]*?(\d{18,20})(?:&|$)/i);                if (revMatch && revMatch[1]) {                  actualRevenueId = revMatch[1];                }                const rewrittenLink = finalHref;                const revenueId = actualRevenueId;                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getRowsLimit() {          if (this.rowsSelect && this.rowsSelect.value) return parseInt(this.rowsSelect.value, 10);          let configSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {             configSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {             configSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(configSource);          if (params.has('rows')) return parseInt(params.get('rows'), 10) || 12;          return 12;        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }        async fetchDeals(query) {          this.showLoading();          this.deals = [];          this.displayLimit = this.getRowsLimit();                    try {            console.log("getViewMode returns:", this.getViewMode());            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad();            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query);               } else {                 await this.fetchHawkDeals(query);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const siteParam = this.website || 'tomsguide';            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=${siteParam}&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (!this.activeDealTag && this.currentQuery) {             const tagMatch = this.airedaleTags.find(t => t.toLowerCase() === this.currentQuery.toLowerCase());             if (tagMatch) {                this.activeDealTag = tagMatch;             }          }          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const siteParam = this.website || 'tomsguide';             const url = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let seenUrls = new Set();                    let overallBrandsCounts = {};                    // First pass: extract ALL brands from topArticles so the dropdown has all options          topArticles.forEach((article) => {             if (!article.articlepage) return;             let pageData = [];             try { pageData = JSON.parse(article.articlepage[0]); } catch(e){ console.warn(e); }             const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');             savingsSquad.forEach((block) => {                const data = block.data || {};                if (data.brand) {                   const cleanBrand = data.brand.replace(/^\d+\.\s*/, '').trim();                   overallBrandsCounts[cleanBrand] = (overallBrandsCounts[cleanBrand] || 0) + 1;                }             });          });          targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = this.decodeHTML(description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim());                summaryTitle = this.decodeHTML(summaryTitle);                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                if (externalUrl) {                   if (seenUrls.has(externalUrl)) return;                  seenUrls.add(externalUrl);                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || '',                   authorName: article.articleauthortext ? article.articleauthortext[0] : (article.articleauthor ? article.articleauthor[0] : ''),                   authorRole: article.articleauthorrole ? article.articleauthorrole[0] : '',                   authorImage: article.articleauthormedia ? article.articleauthormedia[0] : '',                   documentUrl: article.documenturl ? article.documenturl[0] : '',                   modifiedDate: article.contentmodifieddate || article.modifieddate || ''                });             });          });                    const airedaleBrandsList = Object.keys(overallBrandsCounts).map(b => ({              formatted_value: b,              count: overallBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    url.searchParams.append('rows', this.getRowsLimit().toString());          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = this.getRowsLimit();          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: this.decodeHTML(item.name || item.title || item.model_name || item.product_name || 'Unknown Product'),            brand: this.decodeHTML(item.brand || ''),            productName: this.decodeHTML(item.model_name || item.product_name || item.name || ''),            merchant: this.decodeHTML(item.merchant_name || item.merchant || item.retailer || 'Retailer'),            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : 'date_desc';          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                ${_div}              ${_div}              \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin:0; border-radius:0;">${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const finalHref = btn.href || btn.getAttribute('href') || '';                let actualRevenueId = btn.getAttribute('data-revenue-id');                const revMatch = finalHref.match(/(?:subId1|xcust|clickref|ascsubtag)=[^&]*?(\d{18,20})(?:&|$)/i);                if (revMatch && revMatch[1]) {                  actualRevenueId = revMatch[1];                }                const rewrittenLink = finalHref;                const revenueId = actualRevenueId;                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)}${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = 'View Deal';              if (isSavingsSquadMode) {                priceGroupHtml = ``;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = isSavingsSquadMode ? `` : `                \x3Cdiv class="tg-df-card-price-group">                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                          \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                          \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                            var c = this.parentNode;                            if (this.dataset.expanded === 'true') {                              var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                              if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                              pd.style.display = '-webkit-box';                              pd.style.webkitLineClamp = '3';                              this.textContent = 'READ MORE';                              this.style.position = 'absolute';                              this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                              this.style.paddingLeft = '16px';                              this.dataset.expanded = 'false';                            } else {                              var pd = this.previousElementSibling;                              pd.style.display = 'inline';                              pd.style.webkitLineClamp = 'unset';                              this.textContent = 'READ LESS';                              this.style.position = 'static';                              this.style.background = 'transparent';                              this.style.paddingLeft = '4px';                              this.dataset.expanded = 'true';                              pd.appendChild(this);                            }                          ">READ MORE${_button}                        \x3C/div>` : ''}                      ${_div}                    ${_div}                    ${deal.authorName ? `                      \x3Cdiv class="tg-df-author-line-mobile" style="padding: 0 0 12px 0; background: transparent;">                         \x3Cdiv style="display: flex; align-items: center; gap: 12px;">                            ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="40" height="40" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 40px; min-height: 40px;">` : ''}                            \x3Cdiv style="display: flex; flex-direction: column;">                               \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">\x3Cspan style="color: #FF6600;">${this.escapeHTML(deal.merchant)}${_span} deal recommended by:${_div}                               \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.3;">                                  \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                  ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                  ${deal.modifiedDate ? `\x3Cdiv style="color: var(--tg-df-text-muted); margin-top: 2px;">${getTimeAgo(deal.modifiedDate)}${_div}` : ''}                               ${_div}                            ${_div}                         ${_div}                      ${_div}                    ` : ''}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>View Deal${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                  \x3Cdiv class="tg-df-card-merchant-wrapper" style="position: absolute; bottom: 0; right: 0; background: transparent; padding: 8px 12px; z-index: 10;">                     \x3Cspan class="tg-df-card-merchant-pill" style="text-align: right; margin-bottom: 0;" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cdiv class="tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                    \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                    \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                      var c = this.parentNode;                      if (this.dataset.expanded === 'true') {                        var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                        if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                        pd.style.display = '-webkit-box';                        pd.style.webkitLineClamp = '3';                        this.textContent = 'READ MORE';                        this.style.position = 'absolute';                        this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                        this.style.paddingLeft = '16px';                        this.dataset.expanded = 'false';                      } else {                        var pd = this.previousElementSibling;                        pd.style.display = 'inline';                        pd.style.webkitLineClamp = 'unset';                        this.textContent = 'READ LESS';                        this.style.position = 'static';                        this.style.background = 'transparent';                        this.style.paddingLeft = '4px';                        this.dataset.expanded = 'true';                        pd.appendChild(this);                      }                    ">READ MORE${_button}                  \x3C/div>` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${deal.authorName ? `                    \x3Cdiv class="tg-df-author-line-desktop" style="padding: 0 0 ${isSavingsSquadMode ? 0 : 12}px 0;">                       \x3Cdiv style="display: flex; align-items: center; gap: 10px;">                          ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="36" height="36" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 36px; min-height: 36px;">` : ''}                          \x3Cdiv style="display: flex; flex-direction: column;">                             \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">Recommended by:${_div}                             \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.2;">                                \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                ${deal.modifiedDate ? `\x3Cspan style="color: var(--tg-df-text-muted);"> • ${getTimeAgo(deal.modifiedDate)}${_span}` : ''}                             ${_div}                          ${_div}                       ${_div}                    ${_div}                    ` : ''}                    ${priceGroupHtml}                  ${_div}                ${_div}                \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta" style="text-decoration: none; border-radius: 0;">${ctaText}${_a}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit) {            dealsHtml += `              \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer;">Load More${_button}              ${_div}            `;          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }          setTimeout(() => {            const contents = this.root.querySelectorAll('.tg-df-card-desc-content');            contents.forEach(p => {              if (p.scrollHeight > p.clientHeight || p.scrollHeight > 60) {                if (p.nextElementSibling) {                  p.nextElementSibling.style.display = 'block';                }              }            });                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));          }, 50);          const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              this.displayLimit += this.getRowsLimit();              this.render();            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tried the 'inyo-onyo' decluttering technique for the ultimate fall clean — and it's a game-changer ]]></title>
                                                                                                <dc:content><![CDATA[ <p>I'm a constant <a href="https://www.tomsguide.com/home/decluttering-fatigue-is-real-how-the-unfinished-business-test-can-get-rid-of-your-mess-for-good">declutterer</a>, yet I'm also a person with too much clutter. That doesn't sound like it makes any sense – and you're right. </p><p>But while I'm particular about what I have around my home, it's almost inevitable that it still becomes cluttered.</p><p>I have a busy household; there are kids running around, renovations currently happening, and the general day-to-day chaos of life. All of a sudden, despite my best efforts, there's clutter on my countertops and lining my entryway, on side tables, just <em>everywhere</em>. </p><p>So, I'm always on the lookout for decluttering techniques that'll help me (and others) to sort it out. Last year, I embraced the <a href="https://www.tomsguide.com/home/what-is-danshari-heres-how-this-japanese-decluttering-method-can-totally-transform-your-home">Japanese art of 'Danshari'</a> and now I'm trying to embrace something entirely new – 'inyo-onyo'. </p><p>Here's how this Japanese method has totally transformed my home and stopped the clutter.</p><h2 id="how-39-inyo-onyo-39-works">How 'inyo-onyo' works</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="fQPhTRarxX2kGyPpua5xX3" name="inyoonyo_1" alt="A cluttered side table in a bedroom" src="https://cdn.mos.cms.futurecdn.net/fQPhTRarxX2kGyPpua5xX3-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>You've likely heard of 'inyo-onyo' even if you don't know it because translated in Japanese it simply means 'yin and yang'. And yin and yang is a well-known ancient concept in China that describes the balance of opposing forces.</p><p>So, how does that translate into decluttering? Well, for inyo-onyo, it's about balancing out opposites when it comes to your home, empty and filled spaces, or negative and positive spaces. What 'inyo-onyo' wants you to do is embrace a focus on the open spaces you are creating, rather than focusing on exactly <em>what</em> you are getting rid of.</p><p>Instead of applying a negative connotation to any empty surface or space within your home, it's about embracing the openness and looking at it differently. You don't have to fill spaces for them to be impactful in your home and you also don't have to be strict about what you keep or don't keep. </p><p>As long as you look positively about creating more of these vacant spaces and displaying your items with intention, rather than feeling a need to fill it, you can harness the lifestyle choice of 'inyo-onyo'.</p><h2 id="what-happened-when-i-tried-it">What happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="xUxjHdSadWCcgstnxUqwY3" name="inyoonyo_2" alt="A decluttered side table in a bedroom" src="https://cdn.mos.cms.futurecdn.net/xUxjHdSadWCcgstnxUqwY3-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>It's a balance I've always struggled with, especially growing up in a home where my mom believed having things dotted all over the house was a clear sign of wealth and abundance. And I do still relate to that. Leaving empty space <em>does</em> sometimes feel like you're lacking something or missing something.</p><p>But, I'm also always telling myself I want to own less. So, to reframe my mind, I decided not to overwhelm myself with this new way of living and instead focused on harnessing 'inyo-onyo' just one room at a time. For this, I started with a less communal part of my home – the bedroom. </p><p>And while I thought I'd be approaching this method the same way as I have other decluttering techniques, like the '<a href="https://www.tomsguide.com/home/i-just-discovered-the-90-90-rule-for-decluttering-heres-how-it-helped-me-clear-out-my-home">90/90 rule</a>' and '<a href="https://www.tomsguide.com/home/i-tried-chaos-decluttering-for-the-ultimate-spring-clean-and-heres-why-i-wish-id-done-it-sooner">chaos decluttering</a>'. it turned out I wasn't going to turn it into a full-throttle declutter mode.</p><div class="product"><a data-dimension112="432f21e2-c3c3-11f1-b005-cf42bcbc4525" data-action="Deal Block" data-label="25-pcs Clear Drawer Organizers" data-dimension48="25-pcs Clear Drawer Organizers" data-dimension25="$17.99" href="https://www.amazon.com/Vtopmart-Organizers-Versatile-Organizer-Jewelries/dp/B08KXKVT4K" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="wTPRmaUVoE8mnKuEBP43Nm" name="drawer-organizers-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/wTPRmaUVoE8mnKuEBP43Nm-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Vtopmart-Organizers-Versatile-Organizer-Jewelries/dp/B08KXKVT4K" target="_blank" rel="nofollow" data-dimension112="432f21e2-c3c3-11f1-b005-cf42bcbc4525" data-action="Deal Block" data-label="25-pcs Clear Drawer Organizers" data-dimension48="25-pcs Clear Drawer Organizers" data-dimension25="$17.99">25-pcs Clear Drawer Organizers: was $19.99 now $17.99</a></strong><br />Sometimes creating intentional spaces is also about how you organize the things you have in certain drawers. So, this 25-pack of drawer organizers means my drawers are less cluttered and more thoughtful and intentional. There's plenty of variations and colors available, to fit all types of spaces.<a class="view-deal button" href="https://www.amazon.com/Vtopmart-Organizers-Versatile-Organizer-Jewelries/dp/B08KXKVT4K" target="_blank" rel="nofollow" data-dimension112="432f21e2-c3c3-11f1-b005-cf42bcbc4525" data-action="Deal Block" data-label="25-pcs Clear Drawer Organizers" data-dimension48="25-pcs Clear Drawer Organizers" data-dimension25="$17.99">View Deal</a></p></div><p>Instead, I decided to turn my focus to surfaces and the 'clutter' that's on show. If you're trying out this technique though, you can apply it to a full declutter, if you wish. I looked at my side tables where old mail lay, some loose change, discarded hairbands and books before considering how it made me feel.</p><p>Surprisingly, I realized that the cluttered space was negatively impacting my mood far more than if I let it become an emptier space. I decided that I'd let myself have just one book and my lamp. Ultimately, that's all I'd ever want access to from this space and the rest could be tided away.</p><p>Carrying this 'inyo-onyo' ethos through my entire room, I did struggle at times to leave such little amounts of things to be seen. I also worried I was just filling up cupboards and drawers instead, so sorting through my items was also a must. But, ultimately, I know that it made me feel better once it was done. </p><p>It's definitely something I'm going to embrace throughout my home and I already know I'm going to care about the things I keep in a more intentional way.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/what-is-danshari-heres-how-this-japanese-decluttering-method-can-totally-transform-your-home">I just discovered 'Danshari' — this Japanese cleaning philosophy could help me finally break up with clutter</a></li><li><a href="https://www.tomsguide.com/home/my-mom-cleaned-my-kitchen-and-its-never-looked-better-heres-3-tips-she-taught-me">My mom makes keeping a clean kitchen look easy — here's what she said when I asked how she does it</a></li><li><a href="https://www.tomsguide.com/home/i-tried-the-viral-house-purse-organization-hack-heres-what-happened">Say goodbye to clutter — the 'House Purse' organization trick is all you need</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/i-tried-the-inyo-onyo-decluttering-technique-for-the-ultimate-fall-clean-and-its-a-game-changer</link>
                                                                            <description>
                            <![CDATA[ I'm always on the hunt for decluttering methods and Japanese lifestyle principle, 'inyo-onyo', has completely changed the way I organize my home. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">cygUbvE9xyQL4X3GybjSxD</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/88UenBN3R6ZywwZucJo2si-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 13 Oct 2026 06:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/88UenBN3R6ZywwZucJo2si-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[woman sitting on bed in cluttered bedroom]]></media:description>                                                            <media:text><![CDATA[woman sitting on bed in cluttered bedroom]]></media:text>
                                <media:title type="plain"><![CDATA[woman sitting on bed in cluttered bedroom]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/88UenBN3R6ZywwZucJo2si-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I'm a constant <a href="https://www.tomsguide.com/home/decluttering-fatigue-is-real-how-the-unfinished-business-test-can-get-rid-of-your-mess-for-good">declutterer</a>, yet I'm also a person with too much clutter. That doesn't sound like it makes any sense – and you're right. </p><p>But while I'm particular about what I have around my home, it's almost inevitable that it still becomes cluttered.</p><p>I have a busy household; there are kids running around, renovations currently happening, and the general day-to-day chaos of life. All of a sudden, despite my best efforts, there's clutter on my countertops and lining my entryway, on side tables, just <em>everywhere</em>. </p><p>So, I'm always on the lookout for decluttering techniques that'll help me (and others) to sort it out. Last year, I embraced the <a href="https://www.tomsguide.com/home/what-is-danshari-heres-how-this-japanese-decluttering-method-can-totally-transform-your-home">Japanese art of 'Danshari'</a> and now I'm trying to embrace something entirely new – 'inyo-onyo'. </p><p>Here's how this Japanese method has totally transformed my home and stopped the clutter.</p><h2 id="how-39-inyo-onyo-39-works">How 'inyo-onyo' works</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="fQPhTRarxX2kGyPpua5xX3" name="inyoonyo_1" alt="A cluttered side table in a bedroom" src="https://cdn.mos.cms.futurecdn.net/fQPhTRarxX2kGyPpua5xX3-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>You've likely heard of 'inyo-onyo' even if you don't know it because translated in Japanese it simply means 'yin and yang'. And yin and yang is a well-known ancient concept in China that describes the balance of opposing forces.</p><p>So, how does that translate into decluttering? Well, for inyo-onyo, it's about balancing out opposites when it comes to your home, empty and filled spaces, or negative and positive spaces. What 'inyo-onyo' wants you to do is embrace a focus on the open spaces you are creating, rather than focusing on exactly <em>what</em> you are getting rid of.</p><p>Instead of applying a negative connotation to any empty surface or space within your home, it's about embracing the openness and looking at it differently. You don't have to fill spaces for them to be impactful in your home and you also don't have to be strict about what you keep or don't keep. </p><p>As long as you look positively about creating more of these vacant spaces and displaying your items with intention, rather than feeling a need to fill it, you can harness the lifestyle choice of 'inyo-onyo'.</p><h2 id="what-happened-when-i-tried-it">What happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="xUxjHdSadWCcgstnxUqwY3" name="inyoonyo_2" alt="A decluttered side table in a bedroom" src="https://cdn.mos.cms.futurecdn.net/xUxjHdSadWCcgstnxUqwY3-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>It's a balance I've always struggled with, especially growing up in a home where my mom believed having things dotted all over the house was a clear sign of wealth and abundance. And I do still relate to that. Leaving empty space <em>does</em> sometimes feel like you're lacking something or missing something.</p><p>But, I'm also always telling myself I want to own less. So, to reframe my mind, I decided not to overwhelm myself with this new way of living and instead focused on harnessing 'inyo-onyo' just one room at a time. For this, I started with a less communal part of my home – the bedroom. </p><p>And while I thought I'd be approaching this method the same way as I have other decluttering techniques, like the '<a href="https://www.tomsguide.com/home/i-just-discovered-the-90-90-rule-for-decluttering-heres-how-it-helped-me-clear-out-my-home">90/90 rule</a>' and '<a href="https://www.tomsguide.com/home/i-tried-chaos-decluttering-for-the-ultimate-spring-clean-and-heres-why-i-wish-id-done-it-sooner">chaos decluttering</a>'. it turned out I wasn't going to turn it into a full-throttle declutter mode.</p><div class="product"><a data-dimension112="432f21e2-c3c3-11f1-b005-cf42bcbc4525" data-action="Deal Block" data-label="25-pcs Clear Drawer Organizers" data-dimension48="25-pcs Clear Drawer Organizers" data-dimension25="$17.99" href="https://www.amazon.com/Vtopmart-Organizers-Versatile-Organizer-Jewelries/dp/B08KXKVT4K" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="wTPRmaUVoE8mnKuEBP43Nm" name="drawer-organizers-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/wTPRmaUVoE8mnKuEBP43Nm-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Vtopmart-Organizers-Versatile-Organizer-Jewelries/dp/B08KXKVT4K" target="_blank" rel="nofollow" data-dimension112="432f21e2-c3c3-11f1-b005-cf42bcbc4525" data-action="Deal Block" data-label="25-pcs Clear Drawer Organizers" data-dimension48="25-pcs Clear Drawer Organizers" data-dimension25="$17.99">25-pcs Clear Drawer Organizers: was $19.99 now $17.99</a></strong><br />Sometimes creating intentional spaces is also about how you organize the things you have in certain drawers. So, this 25-pack of drawer organizers means my drawers are less cluttered and more thoughtful and intentional. There's plenty of variations and colors available, to fit all types of spaces.<a class="view-deal button" href="https://www.amazon.com/Vtopmart-Organizers-Versatile-Organizer-Jewelries/dp/B08KXKVT4K" target="_blank" rel="nofollow" data-dimension112="432f21e2-c3c3-11f1-b005-cf42bcbc4525" data-action="Deal Block" data-label="25-pcs Clear Drawer Organizers" data-dimension48="25-pcs Clear Drawer Organizers" data-dimension25="$17.99">View Deal</a></p></div><p>Instead, I decided to turn my focus to surfaces and the 'clutter' that's on show. If you're trying out this technique though, you can apply it to a full declutter, if you wish. I looked at my side tables where old mail lay, some loose change, discarded hairbands and books before considering how it made me feel.</p><p>Surprisingly, I realized that the cluttered space was negatively impacting my mood far more than if I let it become an emptier space. I decided that I'd let myself have just one book and my lamp. Ultimately, that's all I'd ever want access to from this space and the rest could be tided away.</p><p>Carrying this 'inyo-onyo' ethos through my entire room, I did struggle at times to leave such little amounts of things to be seen. I also worried I was just filling up cupboards and drawers instead, so sorting through my items was also a must. But, ultimately, I know that it made me feel better once it was done. </p><p>It's definitely something I'm going to embrace throughout my home and I already know I'm going to care about the things I keep in a more intentional way.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/what-is-danshari-heres-how-this-japanese-decluttering-method-can-totally-transform-your-home">I just discovered 'Danshari' — this Japanese cleaning philosophy could help me finally break up with clutter</a></li><li><a href="https://www.tomsguide.com/home/my-mom-cleaned-my-kitchen-and-its-never-looked-better-heres-3-tips-she-taught-me">My mom makes keeping a clean kitchen look easy — here's what she said when I asked how she does it</a></li><li><a href="https://www.tomsguide.com/home/i-tried-the-viral-house-purse-organization-hack-heres-what-happened">Say goodbye to clutter — the 'House Purse' organization trick is all you need</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Why is my grass seed not growing? Lawn expert explains why and how to avoid it this fall ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Fall is official here, and it’s already taken its toll on my previously lush and<a href="https://www.tomsguide.com/how-to/how-to-make-grass-greener"> green grass</a>. But, before things get too chilly, October is the ideal time to repair your damaged lawn and prepare for the colder months ahead.</p><p>And if, like me, you’ve tackled this by scattering grass seed on those sparse or bare patches, it can be a little disheartening when you haven’t seen any growth sprouting through at all.  </p><p>That's why I called on a lawn care expert to find out why my grass isn't growing, common mistakes to avoid, and top tips on how to fix it.</p><h2 id="check-the-weather-forecast">Check the weather forecast</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:8674px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="DNe9kwrtK3EdUoANa8LTJW" name="Grass seeds - crop.jpg" alt="Holding grass seeds to plant" src="https://cdn.mos.cms.futurecdn.net/DNe9kwrtK3EdUoANa8LTJW-1920-80.jpg" mos="" align="middle" fullscreen="" width="8674" height="4879" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Holding grass seeds to plant </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>According to experts, now is the time to do those all-important lawn repairs. But the process just takes a bit more preparation than expected, and results will naturally depend on weather conditions and technique. </p><p>“Thriving spring lawns are built in fall. Thanks to a shift in weather patterns, soil temperatures are staying warmer for longer,” says Chris McIlroy, a lawn expert at<a href="https://74n5c4m7.r.eu-west-1.awstrack.me/L0/https:%2F%2Fthegrasspeople.com%2F/1/010201a11610edf8-e8f760c7-75b1-4520-aef1-f039dda4ee19-000000/DlTbwEujF-5L9QXJASzWJpqHVpA=473" target="_blank"> The Grass People</a>.</p><p>“If temperatures start to stay consistently below 46.4 °F to 50.0 °F, then the window for sowing is closing, so do keep an eye on the forecast. You need a two-week window where the temperatures are above this.”</p><div><blockquote><p>If temperatures start to stay consistently below 46.4 °F to 50.0 °F, then the window for sowing is closing</p><p>Chris McIlroy</p></blockquote></div><p>In addition, be sure to check your soil temperature using a soil thermometer before seeding. Typically, cool-season grasses like Kentucky bluegrass need soil temperatures below 65°F, while warm-season varieties like Bermuda grass need at least 65°F. </p><p>For more top tips, check out <a href="https://www.tomsguide.com/home/lawn-care/revive-your-lawn-this-fall-when-to-overseed-for-a-lush-green-yard">how to overseed your lawn in fall</a>.  </p><div class="product"><a data-dimension112="a78e53b8-c3e8-11f1-ba21-efb018bdca53" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31" href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2424px;"><p class="vanilla-image-block" style="padding-top:55.45%;"><img id="T2WUaZHkFF36kQyUDUWTTS" name="My Soil soil test kit" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/T2WUaZHkFF36kQyUDUWTTS-1920-80.png" mos="" align="middle" fullscreen="" width="2424" height="1344" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow" data-dimension112="a78e53b8-c3e8-11f1-ba21-efb018bdca53" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31">Soil Tests Kit: $31</a></strong><br />Know your soil before overseeding. This professional test measures 13 nutrient levels, including nitrogen and pH, to reveal exactly what your lawn needs. Results in 6 to 8 days help you apply the right products for stronger germination and healthier, sustainable grass growth.<a class="view-deal button" href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow" data-dimension112="a78e53b8-c3e8-11f1-ba21-efb018bdca53" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31">View Deal</a></p></div><h3 class="article-body__section" id="section-protect-it-from-hungry-birds"><span>Protect it from hungry birds</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5990px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="spRkECkC6pzRR4TMFYhT7Y" name="shutterstock_1149736673.jpg" alt="Two birds eating from a wooden bird feeder" src="https://cdn.mos.cms.futurecdn.net/spRkECkC6pzRR4TMFYhT7Y-1920-80.jpg" mos="" align="middle" fullscreen="" width="5990" height="3369" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>If you enjoy feeding or watching birds in your yard, these feathered visitors might be another reason your grass seed isn't growing. </p><p>“Birds can see freshly laid grass seed as an easy-access buffet, especially at this time of year when other food resources are starting to dwindle,” explains McIlroy. “So they’re taking your seed before it even has a chance to germinate."</p><p>So what can we do to prevent our hungry birds from swiping our freshly-laid grass seed?</p><p>"Shiny objects like tin foil and old CDs can deter birds from your garden, as the way they reflect light confuses them," adds McIlroy.</p><p>"Or you can also cover the seeds with tarp or netting, but make sure it’s not blocking too much light or water from the seeds.”</p><h3 class="article-body__section" id="section-not-sowing-deep-enough"><span>Not sowing deep enough</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:6038px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="tU4r8sDeJpW9CE47xUanAD" name="Plant seeds.jpg" alt="A hand distributing grass seed over soil" src="https://cdn.mos.cms.futurecdn.net/tU4r8sDeJpW9CE47xUanAD-1920-80.jpg" mos="" align="middle" fullscreen="" width="6038" height="3396" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">A hand distributing grass seed over soil </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Another common mistake is failing to plant seeds at the right depth or in suitable growing conditions. “Seeds should be roughly the depth of three stacked coins to ensure the right seed-to-soil contact for germination, advises McIlroy. </p><p>“It keeps seeds protected and warm, and provides the nutrients they need to grow. If the elements have left your seeds exposed, try adding a light layer of topsoil to give seedlings that extra support.”</p><p>In addition, you need to ensure you water your seeds properly, but don’t oversaturate them. If seeds are waterlogged or sitting in a pool of water, they won't survive. “Seeds also need to be hydrated but not waterlogged. If they’re left too dry, the seeds will die off, so keep an eye on soil moisture levels". </p><p>“Fixing drainage by aerating your lawn is a key step for success, ensuring water has somewhere to go when it rains. Similarly, if your lawn is bumpy, this creates areas for water to pool.”</p><p>Other tips include feeding your lawn with a starter fertilizer, which can help grass establish faster with stronger roots. Or simply have some patience, and let nature take its course.  </p><p>"Sometimes seeds just need a little more time; depending on the conditions, germination can take up to 14 days, and noticeable grass growth even longer." </p><p>Check out our expert-approved tips on <a href="https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best">how often you should aerate your lawn and how many passes are best. </a></p><p>You might also be interested in <a href="https://www.tomsguide.com/home/lawn-care/the-fall-lawncare-mistake-youre-probably-making-and-the-secret-to-a-greener-lawn-next-spring">the fall lawn care mistake you’re probably making </a>—<a href="https://www.tomsguide.com/home/lawn-care/the-fall-lawncare-mistake-youre-probably-making-and-the-secret-to-a-greener-lawn-next-spring">and the secret to a greener lawn next spring.</a> </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eG0N2W"></div>                            </div>                            <script src="https://kwizly.com/embed/eG0N2W.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-common-lawn-care-mistakes-you-are-probably-making-right-now"><u>7 common lawn care mistakes you’re probably making right now</u></a></li><li><a href="https://www.tomsguide.com/how-to/9-ways-to-get-the-most-out-of-your-lawn-mower">9 ways to get the most out of your lawn mower</a></li><li><a href="https://www.tomsguide.com/how-to/5-plants-that-will-keep-wasps-out-of-your-yard">5 plants that will keep wasps out of your yard</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/lawn-care/why-is-my-grass-seed-not-growing-lawn-expert-explains-why-and-how-to-avoid-it-this-fall</link>
                                                                            <description>
                            <![CDATA[ Lawn expert explains why my grass seed is not growing, as well as some top tips to get top results. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">dvhwJbaJLNsMAAGfsebBVP</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/tyBNke4AjR6gYGGH8NUiDZ-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 11 Oct 2026 05:00:00 +0000</pubDate>                                                                                                                                <updated>Wed, 14 Oct 2026 16:13:13 +0000</updated>
                                                                                                                                            <category><![CDATA[Lawn Care]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                                    <dc:creator><![CDATA[ Cynthia Lawrence ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/4hFvAy3JvgCJamhKf5KoPU-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/tyBNke4AjR6gYGGH8NUiDZ-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Brown patches in grass]]></media:description>                                                            <media:text><![CDATA[Brown patches in grass]]></media:text>
                                <media:title type="plain"><![CDATA[Brown patches in grass]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/tyBNke4AjR6gYGGH8NUiDZ-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Fall is official here, and it’s already taken its toll on my previously lush and<a href="https://www.tomsguide.com/how-to/how-to-make-grass-greener"> green grass</a>. But, before things get too chilly, October is the ideal time to repair your damaged lawn and prepare for the colder months ahead.</p><p>And if, like me, you’ve tackled this by scattering grass seed on those sparse or bare patches, it can be a little disheartening when you haven’t seen any growth sprouting through at all.  </p><p>That's why I called on a lawn care expert to find out why my grass isn't growing, common mistakes to avoid, and top tips on how to fix it.</p><h2 id="check-the-weather-forecast">Check the weather forecast</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:8674px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="DNe9kwrtK3EdUoANa8LTJW" name="Grass seeds - crop.jpg" alt="Holding grass seeds to plant" src="https://cdn.mos.cms.futurecdn.net/DNe9kwrtK3EdUoANa8LTJW-1920-80.jpg" mos="" align="middle" fullscreen="" width="8674" height="4879" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Holding grass seeds to plant </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>According to experts, now is the time to do those all-important lawn repairs. But the process just takes a bit more preparation than expected, and results will naturally depend on weather conditions and technique. </p><p>“Thriving spring lawns are built in fall. Thanks to a shift in weather patterns, soil temperatures are staying warmer for longer,” says Chris McIlroy, a lawn expert at<a href="https://74n5c4m7.r.eu-west-1.awstrack.me/L0/https:%2F%2Fthegrasspeople.com%2F/1/010201a11610edf8-e8f760c7-75b1-4520-aef1-f039dda4ee19-000000/DlTbwEujF-5L9QXJASzWJpqHVpA=473" target="_blank"> The Grass People</a>.</p><p>“If temperatures start to stay consistently below 46.4 °F to 50.0 °F, then the window for sowing is closing, so do keep an eye on the forecast. You need a two-week window where the temperatures are above this.”</p><div><blockquote><p>If temperatures start to stay consistently below 46.4 °F to 50.0 °F, then the window for sowing is closing</p><p>Chris McIlroy</p></blockquote></div><p>In addition, be sure to check your soil temperature using a soil thermometer before seeding. Typically, cool-season grasses like Kentucky bluegrass need soil temperatures below 65°F, while warm-season varieties like Bermuda grass need at least 65°F. </p><p>For more top tips, check out <a href="https://www.tomsguide.com/home/lawn-care/revive-your-lawn-this-fall-when-to-overseed-for-a-lush-green-yard">how to overseed your lawn in fall</a>.  </p><div class="product"><a data-dimension112="a78e53b8-c3e8-11f1-ba21-efb018bdca53" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31" href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2424px;"><p class="vanilla-image-block" style="padding-top:55.45%;"><img id="T2WUaZHkFF36kQyUDUWTTS" name="My Soil soil test kit" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/T2WUaZHkFF36kQyUDUWTTS-1920-80.png" mos="" align="middle" fullscreen="" width="2424" height="1344" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow" data-dimension112="a78e53b8-c3e8-11f1-ba21-efb018bdca53" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31">Soil Tests Kit: $31</a></strong><br />Know your soil before overseeding. This professional test measures 13 nutrient levels, including nitrogen and pH, to reveal exactly what your lawn needs. Results in 6 to 8 days help you apply the right products for stronger germination and healthier, sustainable grass growth.<a class="view-deal button" href="https://www.amazon.com/MySoil-Soil-Provides-Complete-Nutrient-Recommendations/dp/B084TSNR79?th=" target="_blank" rel="nofollow" data-dimension112="a78e53b8-c3e8-11f1-ba21-efb018bdca53" data-action="Deal Block" data-label="Soil Tests Kit" data-dimension48="Soil Tests Kit" data-dimension25="$31">View Deal</a></p></div><h3 class="article-body__section" id="section-protect-it-from-hungry-birds"><span>Protect it from hungry birds</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5990px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="spRkECkC6pzRR4TMFYhT7Y" name="shutterstock_1149736673.jpg" alt="Two birds eating from a wooden bird feeder" src="https://cdn.mos.cms.futurecdn.net/spRkECkC6pzRR4TMFYhT7Y-1920-80.jpg" mos="" align="middle" fullscreen="" width="5990" height="3369" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>If you enjoy feeding or watching birds in your yard, these feathered visitors might be another reason your grass seed isn't growing. </p><p>“Birds can see freshly laid grass seed as an easy-access buffet, especially at this time of year when other food resources are starting to dwindle,” explains McIlroy. “So they’re taking your seed before it even has a chance to germinate."</p><p>So what can we do to prevent our hungry birds from swiping our freshly-laid grass seed?</p><p>"Shiny objects like tin foil and old CDs can deter birds from your garden, as the way they reflect light confuses them," adds McIlroy.</p><p>"Or you can also cover the seeds with tarp or netting, but make sure it’s not blocking too much light or water from the seeds.”</p><h3 class="article-body__section" id="section-not-sowing-deep-enough"><span>Not sowing deep enough</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:6038px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="tU4r8sDeJpW9CE47xUanAD" name="Plant seeds.jpg" alt="A hand distributing grass seed over soil" src="https://cdn.mos.cms.futurecdn.net/tU4r8sDeJpW9CE47xUanAD-1920-80.jpg" mos="" align="middle" fullscreen="" width="6038" height="3396" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">A hand distributing grass seed over soil </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Another common mistake is failing to plant seeds at the right depth or in suitable growing conditions. “Seeds should be roughly the depth of three stacked coins to ensure the right seed-to-soil contact for germination, advises McIlroy. </p><p>“It keeps seeds protected and warm, and provides the nutrients they need to grow. If the elements have left your seeds exposed, try adding a light layer of topsoil to give seedlings that extra support.”</p><p>In addition, you need to ensure you water your seeds properly, but don’t oversaturate them. If seeds are waterlogged or sitting in a pool of water, they won't survive. “Seeds also need to be hydrated but not waterlogged. If they’re left too dry, the seeds will die off, so keep an eye on soil moisture levels". </p><p>“Fixing drainage by aerating your lawn is a key step for success, ensuring water has somewhere to go when it rains. Similarly, if your lawn is bumpy, this creates areas for water to pool.”</p><p>Other tips include feeding your lawn with a starter fertilizer, which can help grass establish faster with stronger roots. Or simply have some patience, and let nature take its course.  </p><p>"Sometimes seeds just need a little more time; depending on the conditions, germination can take up to 14 days, and noticeable grass growth even longer." </p><p>Check out our expert-approved tips on <a href="https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best">how often you should aerate your lawn and how many passes are best. </a></p><p>You might also be interested in <a href="https://www.tomsguide.com/home/lawn-care/the-fall-lawncare-mistake-youre-probably-making-and-the-secret-to-a-greener-lawn-next-spring">the fall lawn care mistake you’re probably making </a>—<a href="https://www.tomsguide.com/home/lawn-care/the-fall-lawncare-mistake-youre-probably-making-and-the-secret-to-a-greener-lawn-next-spring">and the secret to a greener lawn next spring.</a> </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eG0N2W"></div>                            </div>                            <script src="https://kwizly.com/embed/eG0N2W.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-common-lawn-care-mistakes-you-are-probably-making-right-now"><u>7 common lawn care mistakes you’re probably making right now</u></a></li><li><a href="https://www.tomsguide.com/how-to/9-ways-to-get-the-most-out-of-your-lawn-mower">9 ways to get the most out of your lawn mower</a></li><li><a href="https://www.tomsguide.com/how-to/5-plants-that-will-keep-wasps-out-of-your-yard">5 plants that will keep wasps out of your yard</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I've been testing Ninja's microwave/air fryer hybrid for 2 weeks — now I don't want it to leave my kitchen ]]></title>
                                                                                                <dc:content><![CDATA[ <div  class="fancy-box"><div class="fancy_box-title">Ninja Crispi Microwave Specs</div><div class="fancy_box_body"><p class="fancy-box__body-text">Price: $449<br />Weight: 41 lbs<br />Dimensions: 203.3 (L) x 17.56 (W) x 14.1 (H) inches<br />Capacity: 5.5 qt glass dish / 0.9 cu ft microwave<br />Wattage: 1,000 (microwave)  / 1,700 air fryer<br />Microwave presets: 8<br />Airfryer presets: 5<br />Maximum temperature: 450°F<br />Materials: CleanCrisp Glassware and crisper plate are PFAS, PTFE, and PFOS-free<br />Dishwasher: Glassware and plate</p></div></div><p>Whatever new product Ninja launches, it always causes a stir, as it did with the <a href="https://www.tomsguide.com/home/air-fryers/ninja-crispi-air-fryer-review">Ninja Crispi air fryer.</a> The brand can’t seem to miss the mark with consumers. Everyone just raves about Ninja. <br /><br />That’s why I was excited to try <a href="https://www.tomsguide.com/home/kitchen-dining/ninja-just-fixed-the-worst-thing-about-microwaves-and-it-might-replace-your-air-fryer">Ninja’s Crispi Microwave,</a> launched in the U.K. in September, just a couple of months after its July U.S. release. It's Ninja’s first entry into the microwave market, but instead of playing it safe, the company has created a multifunction appliance that uses FusionCrisp technology to not only heat but crisp your food on demand.  </p><p>I've been taking it through its paces to discover whether it's worth a place on your countertop. </p><h3 class="article-body__section" id="section-ninja-crispi-microwave-price-and-availability"><span>Ninja Crispi Microwave: Price and availability</span></h3><p>The Ninja Crispi Microwave launched at $449 in the U.S. and £359 in the U.K. However, do look around, as it’s currently reduced to <a href="https://www.amazon.com/dp/B0FKBXMPRF?" target="_blank" rel="nofollow">$399 at Amazon</a>, but if you’re in the U.K., it’s still <a href="https://www.amazon.co.uk/Ninja-Microwave-FusionCrisp-Technology-MW101UKSDBRN/dp/B0HFSNBZ1M?" target="_blank" rel="nofollow">£359 at Amazon</a></p><p>Looking at the microwaves recommended in our buying guide, Toshiba’s EM131A5C-BS Countertop Microwave takes the top spot, and you’ll pay <a href="https://www.amazon.com/TOSHIBA-Countertop-Microwave-Cu-Ft-1000W/dp/B071WCB1T6/ref=sr_1_1?" target="_blank">$149 at Amazon</a> for it. Meanwhile, the best combi microwave is IKEA’s GÅTEBO 3-in-1 microwave, which can heat, grill and air fry and costs <a href="https://www.ikea.com/us/en/p/gatebo-microwave-oven-with-air-fryer-function-ikea-500-black-70603506/?" target="_blank" rel="nofollow">$199 at IKEA.</a></p><p>While the Ninja is more expensive, you do get two-in-one appliances, so don't dismiss this product just because of the price.</p><h3 class="article-body__section" id="section-ninja-crispi-microwave-unboxing-and-setup"><span>Ninja Crispi Microwave: Unboxing and setup</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/V6MAxeinK334tKMsYdgJrC-1920-80.jpg" alt="Ninja Crispi Microwave unboxing" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/EJBsXucqAgb7wm8gZyb2kC-1920-80.jpg" alt="Ninja Crispi Microwave unboxing" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/z3jY9F6AEFW5G9Q37et2fC-1920-80.jpg" alt="Ninja Crispi Microwave unboxing" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/CXjuHBe2VRNaP4qcxkdd4U-1920-80.jpg" alt="Ninja Crispi Microwave Glass dish, crisper plate and quick start guide" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>Don’t underestimate how big this appliance is. It’s a two-man job to get it out of its box. In fact, I was surprised by how much countertop space it took up. </p><p>The product is securely packaged, and apart from the microwave, it comes packed with a large 5.5-quart glass dish and a crisper plate. You also get an owner’s guide and a quick start guide — including recipes, charts and instructions. Keep hold of these as they’re invaluable when you first get going.</p><p>They also explain how to use the glass dish and crisper plate, which mustn’t be used when using the standard microwave function. You’ll also learn when to place the dish in the lower or upper position; it depends on the mode you’re using and what you are cooking.</p><p>But this microwave doesn’t have a turntable. Unlike most microwaves, Ninja’s version foregoes the turntable for a flatbed design, which gives you 20% more usable cooking space than a standard turntable. Plus, that’s one less thing to wash!</p><h3 class="article-body__section" id="section-ninja-crispi-microwave-design"><span>Ninja Crispi Microwave: Design</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/RhJ5SK5eAYDcZiPALJA3tc-1920-80.jpg" alt="Ninja Crispi Microwave" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/P6xwaT2Y2nB72XLaCzX8jd-1920-80.jpg" alt="Ninja Crispi Microwave" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/KxDfUh4c4FEnkGmaXw526d-1920-80.jpg" alt="Ninja Crispi Microwave" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>Did I mention it was large? Beyond taking up more depth, width and height in my kitchen than my usual microwave, you’ll need to make sure you have enough safe clearance around the appliance to keep its air vents clear. </p><p>You’ll need 11.81 inches of clearance from the top of the appliance to any cabinets or shelves above it, and it shouldn’t be wall-mounted or placed inside a cabinet.</p><p>It has a smart design and looks like any other microwave, except it is bigger. You can also choose from three colors — Silver, Cyberspace and Black. However, when you peek inside, you’ll see it’s missing the standard microwave turntable. You’ll also notice shelf runners at the top; they help the glass dish slide into the top position. </p><h3 class="article-body__section" id="section-ninja-crispi-microwave-ease-of-use"><span>Ninja Crispi Microwave: Ease of use</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/awQKu9S9uihDd75hTjaDt9-1920-80.jpg" alt="Ninja Crispi Microwave controls" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/xKivAkNudm6myLvcCfvxz9-1920-80.jpg" alt="Ninja Crispi Microwave controls" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>It didn’t take me long to get the microwave up and running, but since it’s a multifunctional appliance, give yourself time to read the instructions. Beyond standard air fry and microwave modes, it offers a lot of functionality, including presets and FusionCrisp. </p><p>It has eight microwave presets (Defrost, Beverage, Soup, Popcorn, Potato, Soup, Soften Butter, Frozen Vegetable, and Porridge) and five Air Fry presets (Air Fry, Max Crisp, Air Roast, Air Bake, and Air Grill).</p><p>At first, it might seem a bit complicated, but after a few goes, I was confident I was using it proficiently. </p><p>However, one recurring issue is knowing what times to set when using the FusionCrisp function. I could follow recipes in the quick start guide, and there are also guidelines for cooking a wide range of other dishes, but I couldn’t always find the timings for what I wanted to cook. In these instances, I searched online for advice.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="E5eqiw88ghZSYVWxhVKdkQ" name="Ninja-Crispi--Crisper-in-top-position" alt="Ninja Crispi Microwave - dish in top position" src="https://cdn.mos.cms.futurecdn.net/E5eqiw88ghZSYVWxhVKdkQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Another issue I had was the weight of the glass dish. I found it was very heavy, especially when full, and removing it from the top position was tricky. It was difficult to grab with oven mitts, which was essential once the food had been cooked. However, when the glass dish was placed in the bottom position, it wasn’t as much of an issue.</p><h3 class="article-body__section" id="section-ninja-crispi-microwave-performance"><span>Ninja Crispi Microwave: Performance</span></h3><p>As I've already mentioned, there's lots of scope with how you use Ninja's Crispi Microwave. During my testing I used the microwave and air fry functions independently and combined them both using the FusionCrisp mode. Here's how  I got on heating, reheating and crisping food.</p><h2 id="fusioncrisp">FusionCrisp</h2><p>The standout feature of this microwave is its FusionCrisp technology — the ability to microwave and air fry. Beyond ending soggy microwave reheats, it can do much more. </p><p><strong>Fruit crumble</strong> <br />With a sweet tooth, I couldn’t help but notice a fruit crumble recipe in the quick start guide, and it seemed like a good place to start. Crumble is one of my favorite desserts; it has plenty of fruit, is quick to make, and I love the richness of the crumbly topping. What’s more, it seemed like a fitting way to see just how well FusionCrisp mode works.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="fpjTA9hBZj3JzGFJDbAfzd" name="Ninja Crispi Microwave Crumble recipe" alt="Ninja Crispi Microwave Crumble recipe" src="https://cdn.mos.cms.futurecdn.net/fpjTA9hBZj3JzGFJDbAfzd-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I’ve already covered making the fruit crumble in my<a href="https://www.tomsguide.com/home/kitchen-dining/im-testing-ninjas-first-ever-microwave-with-air-frying-built-in-and-it-fixes-the-worst-thing-about-microwaves"> first impressions of the Ninja Crispi Microwave, </a>where I explain how large and heavy the glass bowl is. It will allow you to make a huge serving, but this might not be what you want. </p><p>When baking the crumble, I placed the bowl in the top position and pressed the FusionCrisp button. I then set the microwave time to 20 minutes, followed by the air fry time to 10 minutes, as the recipe directed. </p><p>You'll hear the appliance beep when the microwave finishes and before the air frying starts. Then, once complete, 'Cool' appears on the digital display. This is when the internal fan runs to dissipate residual heat.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="nm2hqsUaMzB7SDfnMGETiC" name="Fruit crumble made in Ninja Crispi Microwave" alt="Fruit crumble made in Ninja Crispi Microwave" src="https://cdn.mos.cms.futurecdn.net/nm2hqsUaMzB7SDfnMGETiC-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I was really pleased with the result. The fruit was cooked through and piping hot, and the crumble was just how it would be if I’d cooked it in my oven. With a total cook time of 30 minutes, it saved me 10 minutes on my usual oven bake.</p><p>Would I make this again in the Ninja Crispi Microwave? Definitely. </p><p><strong>Baked potatoes</strong></p><p>Who doesn’t love a baked potato with a crispy skin? I usually start by microwaving my potatoes, then leaving them to crisp in the oven, but that takes ages, and it's too long for a quick lunch. However, using the FusionCrisp mode makes it feasible when you are short on time.</p><p>I started by pricking my potatoes all over with a fork, and then gave them a light coating with sunflower oil. I couldn’t find the cooking times for baked potatoes in the guide, so I searched online and placed two potatoes (weighing between 250-300g each) on the crisper plate in the glass dish in the top position. I set the microwave for 14 minutes and the air fryer for 10 minutes. </p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/3ct5SpnoGw4perUqacYH5m-1920-80.jpg" alt="Ninja Crispi Microwave baking potatoes" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/Nyaq7pSVNRbojd5TSFfdFm-1920-80.jpg" alt="Ninja Crispi Microwave baking potatoes" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/8axkPPUHha6hwXCSDJp74m-1920-80.jpg" alt="Ninja Crispi Microwave baking potatoes" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>Baking potatoes and how crisp you like the skin is a personal preference — I like mine on the extra-crispy side, enough to give your jaw a workout. So, you’ll probably need to play around with the air fryer timings, depending on your own taste. However, these were a real winner, and although I’d extend the air-frying time, the inside of the potatoes were soft and cooked through. </p><p><strong>A whole chicken</strong></p><p>Since using the <a href="https://www.tomsguide.com/home/home-appliances/cosori-turboblaze-air-fryer-review">Cosori TurboBlaze Air Fryer</a>, I’ve swapped cooking whole chickens in my oven for using my air fryer. I find it’s quicker, and my air fryer basket is easier to clean than my oven.</p><p>So, I was keen to discover how my regular chicken would look and taste after using the FusionCrisp mode. I followed the recipe in the quick start guide for a 1.5 kg chicken (3.3 lb); I lightly coated the chicken in vegetable oil, seasoned it and placed it on the crisper plate in the glass dish. </p><p>Although everything I had previously cooked using the FusionCrisp mode had been placed in the top position, the size of the chicken called for it to be cooked in the bottom position.</p><p>I set the microwave time to 30 minutes and the air fry dial to 45 minutes. The recipe didn’t specify turning the chicken, like I normally do when I air-fry protein this size, so I skipped this step.</p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/oNeCgrZUk6QbdfPgnAH82A-1920-80.jpg" alt="Ninja Crispi Microwave cooking a whole chicken" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/2GueYM2STFsCF7A3DVu9t3-1920-80.jpg" alt="Ninja Crispi Microwave - chicken after microwave stage" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>Once the microwave stage was complete and the appliance beeped, I removed the chicken to check on its progress. As expected, it still looked pale and unappetizing. However, once the air-frying cook time was up, I checked the temperature of the chicken with my<a href="https://www.tomsguide.com/best-picks/best-meat-thermometers#section-best-meat-thermometer-overall" target="_blank" rel="nofollow"> Thermoworks Thermapen One thermometer</a> and it was above the recommended temperature for cooked chicken.</p><p>However, when I turned the chicken over, it still looked pale, and after inserting the thermometer, it was not at a safe temperature to eat. I therefore returned the chicken, uncooked side up, to the microwave and gave it a few more minutes on the air fry setting.</p><p>This wouldn't stop me from cooking a whole chicken in the microwave; I'd just return to my normal practice and turn the chicken halfway through the cook. </p><p>What about the clean-up? I took a cloth, rinsed it in warm, soapy water and wiped over the internal surface of the microwave to remove the splatters of chicken fat. It was easy to remove, since I hadn't let the fat settle. </p><p><strong>Vegetable lasagna</strong></p><p>One of my favorite recipes is <a href="https://www.bbcgoodfood.com/recipes/easy-pesto-lasagne" target="_blank">pesto lasagna</a>, made with pesto, spinach, pine nuts and mascarpone — try it, you’ll be surprised!</p><p>Since the quick start guide includes a vegetable lasagna recipe, I thought I’d use the same cooking times. I made the lasagna in the glass bowl, then placed it in the top position in the microwave, setting the microwave time to 20 minutes and the air fry time to 8 minutes.</p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/qq6UtxQjMRjmxG6ZCCNdXN-1920-80.jpg" alt="Ninja Crispi Microwave baking lasagna" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/ff3muYv98mHybyYSHWJrMN-1920-80.jpg" alt="Ninja Crispi Microwave baking lasagna" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/xfJXKx9X93EFFu6htnatdN-1920-80.jpg" alt="Ninja Crispi Microwave baking lasagna" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>I was pretty pleased with this bake. The lasagna was well-cooked, the filling hot and the top crispy — if not a little too dark. Since making this lasagna, I've continued to use the microwave for other pasta bakes, as it makes an easy, quick win during the week</p><h2 id="air-fryer">Air fryer</h2><p>Since I'd already used the air fry mode within the FusionCrisp mode, I didn't test the stand alone air fry function as extensively as I would a normal air fryer — to me, it had already proofed that's it's more than capable.</p><p><strong>Grilled cheese toasty</strong></p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="xQ5h32xREod6DTFgJkd8G3" name="Ninja Crispi Microwave" alt="Ninja Crispi Microwave - grilled cheese toasty" src="https://cdn.mos.cms.futurecdn.net/xQ5h32xREod6DTFgJkd8G3-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>To go with the soup I heated in the microwave (see below), I made a grilled cheese toasty. I spread butter on the outside of two slices of granary bread and filled the inside with grated cheddar cheese. I placed the bread on the crisper plate in the glass dish and used the top position in the microwave.</p><p>I checked online to get an idea of timings, and set the temperature to 240°C for 8 minutes, flipping the toasty over at the halfway point.</p><p>The toasty was incredibly moreish, with oozing cheese and a crispy texture. Since making this in the microwave, I've been eating cheese toasties on repeat. </p><p><strong>Thick-cut frozen chips</strong></p><p>Frozen chips are a staple in my house for quick dinners, and it was a no-brainer to try them in the air fryer. I placed them on the crisper tray in the glass dish (there’s plenty of room for large portions), selected the Max Crisp Air Fry setting and set the timer for 20 minutes. </p><p>I checked them after nine minutes, gave them a shake and saw they were cooking faster than I thought. So, after 12 minutes, I checked again, and they were baked. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="LhQ3RQBuHePxLjDS3KALFG" name="Ninja-Crisp-Fries in air fryer" alt="Ninja Crispi Microwave - cooking fries" src="https://cdn.mos.cms.futurecdn.net/LhQ3RQBuHePxLjDS3KALFG-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>Beef burgers</strong><br />To go with the thick chips, I used the air fryer mode to cook frozen beef burgers. Although the quick start guide does give you timings for using the FUSIONCRISP mode (5 minutes microwave, 10-12 minutes air fry). </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="GK7PdTAReSzXy9QasJ3bvT" name="Ninja-Crispi- Microwave cooking beefburgers" alt="Ninja Crispi Microwave cooking beefburgers using the air fry function" src="https://cdn.mos.cms.futurecdn.net/GK7PdTAReSzXy9QasJ3bvT-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I placed two quarter-pounders on the crisper plate in the top glass bowl and set the air fry time to 14 mins at 180°C/356°F, flipping them halfway through. I was pleased with the result, but I will try using the FUSIONCRISP mode next time to see if it makes a difference. </p><h2 id="microwave">Microwave</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="k96qS23vv773g5h3oZJdmC" name="Ninja Crispi Microwave presets" alt="Ninja Crispi Microwave presets" src="https://cdn.mos.cms.futurecdn.net/k96qS23vv773g5h3oZJdmC-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>My normal microwave is very basic and lacks functions, so I was excited to try the Ninja and work through the presets; plus, it was handy for reheating dinners after I went to the gym.</p><p>Overall, I was impressed with the microwave’s functionality, its ability to heat without cold spots, and how easy it is to adjust the timing with the control knob or in 30+/- intervals, as well as the power level.  </p><p><strong>Melting butter</strong><br />I tend to keep my butter in the fridge, especially in summer, when it can start to go rancid. This means my butter is often too hard to spread and definitely not soft enough for cake batters. I found this function really handy, and it meant I didn’t have to think about how long to microwave my butter or which temperature setting to use. It was a surprise to open the microwave and find softened butter instead of my usual melted mess. The preset is set to 30 seconds, but you can adjust this either way. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="efuJj6tzbzYeyQjNgwcGwK" name="Ninja Crispi Microwave softening butter" alt="Ninja Crispi Microwave softening butter" src="https://cdn.mos.cms.futurecdn.net/efuJj6tzbzYeyQjNgwcGwK-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>Heating soup</strong><br />With cozy season upon us, I've started to enjoy warming lunches, so I used the preset to heat through some chicken and vegetable soup. I placed my bowl of soup in the base of the microwave and kept it in for the full 2 1/2 minutes. Once complete, I gave the soup a stir, and it was piping hot.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1962px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="opYABN54qHaZJCVGi4Qm43" name="Ninja Crispi Microwave" alt="Ninja Crispi Microwave - heating soup" src="https://cdn.mos.cms.futurecdn.net/opYABN54qHaZJCVGi4Qm43-1920-80.png" mos="" align="middle" fullscreen="" width="1962" height="1104" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>Porridge</strong><br />With the mornings getting cooler, I was able to make the most of the porridge preset and make myself a bowl of steaming oats. I put 1/2 cup of oats in a bowl with 1 cup of milk, stirred and selected the porridge preset. After two minutes, I removed my oats (though they had boiled over the sides a little), and my breakfast was steaming hot with no cold spots. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="LBkvz6D3nZtwtfxh2Bfxi9" name="Ninja Crispi Microwave making porridge preset" alt="Ninja Crispi Microwave making porridge preset" src="https://cdn.mos.cms.futurecdn.net/LBkvz6D3nZtwtfxh2Bfxi9-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future /Camilla Sharman)</span></figcaption></figure><p>OK, so I had a bit of leakage; normally I'd remove the turntable from my microwave and wash it by hand or put it in my dishwasher. However, with the Ninja, I simply took a damp cloth and wiped up the mess. I found the inner design makes it easy to clean up messes, with no ridges to hold a turntable. </p><h3 class="article-body__section" id="section-ninja-crispi-microwave-verdict"><span>Ninja Crispi Microwave: Verdict</span></h3><p>I’m in love with the Ninja Crispi Microwave, and I don’t want this to disappear from my kitchen. It’s great for baking pasta bakes and crumbles, and it does a good job with whole chickens (just remember to flip the food halfway through). Plus, the presets are super handy, and the best bit is that it’s fun to use. </p><p>So why haven’t I given it 5 stars? It’s got nothing to do with its prowess as a cooking appliance; it’s simply its size. You need serious space in your kitchen for this microwave, not to mention the clearance headroom above it, and the large glass dish is heavy to handle, especially when it’s placed in the top position. If you can work around these issues, it’s well worth considering.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Xrgp0e"></div>                            </div>                            <script src="https://kwizly.com/embed/Xrgp0e.js" async=""></script> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/kitchen-dining/ive-been-testing-ninjas-microwave-air-fryer-hybrid-for-2-weeks-now-i-dont-want-it-to-leave-my-kitchen</link>
                                                                            <description>
                            <![CDATA[ Ninja's first-ever microwave also includes a unique air fryer capability and after putting it through its paces, I'm sold on the cooking if not the overall size of the appliance. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">bzyZ4J6yWv7AfPVXdWCNmK</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/w8di4J3wehEM4CeQzccvsM-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 10 Oct 2026 05:30:00 +0000</pubDate>                                                                                                                                <updated>Sat, 10 Oct 2026 12:19:01 +0000</updated>
                                                                                                                                            <category><![CDATA[Kitchen & Dining]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                <author><![CDATA[ camilla.sharman@futurenet.com (Camilla Sharman) ]]></author>                    <dc:creator><![CDATA[ Camilla Sharman ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/nY4nvWzofHKHpvzAqN5LVH-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Camilla is the Homes Staff Writer and covers everything to do with homes and gardens. She has a wealth of editorial experience, mounting over 30 years, and covers news and features, tests products for reviews and compiles buying guides.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Her work has appeared in business and consumer titles, including Ideal Home, Real Homes, House Beautiful, Homebuilding &amp;amp; Renovation, and Kitchen &amp;amp; Bathroom Business. She’s even appeared on the cover of Your Home, writing about her own house renovation.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Although she’s obsessed with decorating her home, she also enjoys baking and trying out the latest kitchen appliances. But when she’s not inside, you’ll find her pottering about in her yard, tending to her vegetable patch or taking in her prized hydrangeas. She also enjoys keeping fit, and if she&#039;s not on a spin bike trying to keep up with the class, she&#039;ll be in the pool, or trying to perfect her headstand in a yoga class.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/w8di4J3wehEM4CeQzccvsM-1920-80.jpg">
                                                            <media:credit><![CDATA[Future / Camilla Sharman]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Ninja Crispi Microwave]]></media:description>                                                            <media:text><![CDATA[Ninja Crispi Microwave]]></media:text>
                                <media:title type="plain"><![CDATA[Ninja Crispi Microwave]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/w8di4J3wehEM4CeQzccvsM-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <div  class="fancy-box"><div class="fancy_box-title">Ninja Crispi Microwave Specs</div><div class="fancy_box_body"><p class="fancy-box__body-text">Price: $449<br />Weight: 41 lbs<br />Dimensions: 203.3 (L) x 17.56 (W) x 14.1 (H) inches<br />Capacity: 5.5 qt glass dish / 0.9 cu ft microwave<br />Wattage: 1,000 (microwave)  / 1,700 air fryer<br />Microwave presets: 8<br />Airfryer presets: 5<br />Maximum temperature: 450°F<br />Materials: CleanCrisp Glassware and crisper plate are PFAS, PTFE, and PFOS-free<br />Dishwasher: Glassware and plate</p></div></div><p>Whatever new product Ninja launches, it always causes a stir, as it did with the <a href="https://www.tomsguide.com/home/air-fryers/ninja-crispi-air-fryer-review">Ninja Crispi air fryer.</a> The brand can’t seem to miss the mark with consumers. Everyone just raves about Ninja. <br /><br />That’s why I was excited to try <a href="https://www.tomsguide.com/home/kitchen-dining/ninja-just-fixed-the-worst-thing-about-microwaves-and-it-might-replace-your-air-fryer">Ninja’s Crispi Microwave,</a> launched in the U.K. in September, just a couple of months after its July U.S. release. It's Ninja’s first entry into the microwave market, but instead of playing it safe, the company has created a multifunction appliance that uses FusionCrisp technology to not only heat but crisp your food on demand.  </p><p>I've been taking it through its paces to discover whether it's worth a place on your countertop. </p><h3 class="article-body__section" id="section-ninja-crispi-microwave-price-and-availability"><span>Ninja Crispi Microwave: Price and availability</span></h3><p>The Ninja Crispi Microwave launched at $449 in the U.S. and £359 in the U.K. However, do look around, as it’s currently reduced to <a href="https://www.amazon.com/dp/B0FKBXMPRF?" target="_blank" rel="nofollow">$399 at Amazon</a>, but if you’re in the U.K., it’s still <a href="https://www.amazon.co.uk/Ninja-Microwave-FusionCrisp-Technology-MW101UKSDBRN/dp/B0HFSNBZ1M?" target="_blank" rel="nofollow">£359 at Amazon</a></p><p>Looking at the microwaves recommended in our buying guide, Toshiba’s EM131A5C-BS Countertop Microwave takes the top spot, and you’ll pay <a href="https://www.amazon.com/TOSHIBA-Countertop-Microwave-Cu-Ft-1000W/dp/B071WCB1T6/ref=sr_1_1?" target="_blank">$149 at Amazon</a> for it. Meanwhile, the best combi microwave is IKEA’s GÅTEBO 3-in-1 microwave, which can heat, grill and air fry and costs <a href="https://www.ikea.com/us/en/p/gatebo-microwave-oven-with-air-fryer-function-ikea-500-black-70603506/?" target="_blank" rel="nofollow">$199 at IKEA.</a></p><p>While the Ninja is more expensive, you do get two-in-one appliances, so don't dismiss this product just because of the price.</p><h3 class="article-body__section" id="section-ninja-crispi-microwave-unboxing-and-setup"><span>Ninja Crispi Microwave: Unboxing and setup</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/V6MAxeinK334tKMsYdgJrC-1920-80.jpg" alt="Ninja Crispi Microwave unboxing" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/EJBsXucqAgb7wm8gZyb2kC-1920-80.jpg" alt="Ninja Crispi Microwave unboxing" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/z3jY9F6AEFW5G9Q37et2fC-1920-80.jpg" alt="Ninja Crispi Microwave unboxing" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/CXjuHBe2VRNaP4qcxkdd4U-1920-80.jpg" alt="Ninja Crispi Microwave Glass dish, crisper plate and quick start guide" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>Don’t underestimate how big this appliance is. It’s a two-man job to get it out of its box. In fact, I was surprised by how much countertop space it took up. </p><p>The product is securely packaged, and apart from the microwave, it comes packed with a large 5.5-quart glass dish and a crisper plate. You also get an owner’s guide and a quick start guide — including recipes, charts and instructions. Keep hold of these as they’re invaluable when you first get going.</p><p>They also explain how to use the glass dish and crisper plate, which mustn’t be used when using the standard microwave function. You’ll also learn when to place the dish in the lower or upper position; it depends on the mode you’re using and what you are cooking.</p><p>But this microwave doesn’t have a turntable. Unlike most microwaves, Ninja’s version foregoes the turntable for a flatbed design, which gives you 20% more usable cooking space than a standard turntable. Plus, that’s one less thing to wash!</p><h3 class="article-body__section" id="section-ninja-crispi-microwave-design"><span>Ninja Crispi Microwave: Design</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/RhJ5SK5eAYDcZiPALJA3tc-1920-80.jpg" alt="Ninja Crispi Microwave" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/P6xwaT2Y2nB72XLaCzX8jd-1920-80.jpg" alt="Ninja Crispi Microwave" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/KxDfUh4c4FEnkGmaXw526d-1920-80.jpg" alt="Ninja Crispi Microwave" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>Did I mention it was large? Beyond taking up more depth, width and height in my kitchen than my usual microwave, you’ll need to make sure you have enough safe clearance around the appliance to keep its air vents clear. </p><p>You’ll need 11.81 inches of clearance from the top of the appliance to any cabinets or shelves above it, and it shouldn’t be wall-mounted or placed inside a cabinet.</p><p>It has a smart design and looks like any other microwave, except it is bigger. You can also choose from three colors — Silver, Cyberspace and Black. However, when you peek inside, you’ll see it’s missing the standard microwave turntable. You’ll also notice shelf runners at the top; they help the glass dish slide into the top position. </p><h3 class="article-body__section" id="section-ninja-crispi-microwave-ease-of-use"><span>Ninja Crispi Microwave: Ease of use</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/awQKu9S9uihDd75hTjaDt9-1920-80.jpg" alt="Ninja Crispi Microwave controls" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/xKivAkNudm6myLvcCfvxz9-1920-80.jpg" alt="Ninja Crispi Microwave controls" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>It didn’t take me long to get the microwave up and running, but since it’s a multifunctional appliance, give yourself time to read the instructions. Beyond standard air fry and microwave modes, it offers a lot of functionality, including presets and FusionCrisp. </p><p>It has eight microwave presets (Defrost, Beverage, Soup, Popcorn, Potato, Soup, Soften Butter, Frozen Vegetable, and Porridge) and five Air Fry presets (Air Fry, Max Crisp, Air Roast, Air Bake, and Air Grill).</p><p>At first, it might seem a bit complicated, but after a few goes, I was confident I was using it proficiently. </p><p>However, one recurring issue is knowing what times to set when using the FusionCrisp function. I could follow recipes in the quick start guide, and there are also guidelines for cooking a wide range of other dishes, but I couldn’t always find the timings for what I wanted to cook. In these instances, I searched online for advice.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="E5eqiw88ghZSYVWxhVKdkQ" name="Ninja-Crispi--Crisper-in-top-position" alt="Ninja Crispi Microwave - dish in top position" src="https://cdn.mos.cms.futurecdn.net/E5eqiw88ghZSYVWxhVKdkQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Another issue I had was the weight of the glass dish. I found it was very heavy, especially when full, and removing it from the top position was tricky. It was difficult to grab with oven mitts, which was essential once the food had been cooked. However, when the glass dish was placed in the bottom position, it wasn’t as much of an issue.</p><h3 class="article-body__section" id="section-ninja-crispi-microwave-performance"><span>Ninja Crispi Microwave: Performance</span></h3><p>As I've already mentioned, there's lots of scope with how you use Ninja's Crispi Microwave. During my testing I used the microwave and air fry functions independently and combined them both using the FusionCrisp mode. Here's how  I got on heating, reheating and crisping food.</p><h2 id="fusioncrisp">FusionCrisp</h2><p>The standout feature of this microwave is its FusionCrisp technology — the ability to microwave and air fry. Beyond ending soggy microwave reheats, it can do much more. </p><p><strong>Fruit crumble</strong> <br />With a sweet tooth, I couldn’t help but notice a fruit crumble recipe in the quick start guide, and it seemed like a good place to start. Crumble is one of my favorite desserts; it has plenty of fruit, is quick to make, and I love the richness of the crumbly topping. What’s more, it seemed like a fitting way to see just how well FusionCrisp mode works.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="fpjTA9hBZj3JzGFJDbAfzd" name="Ninja Crispi Microwave Crumble recipe" alt="Ninja Crispi Microwave Crumble recipe" src="https://cdn.mos.cms.futurecdn.net/fpjTA9hBZj3JzGFJDbAfzd-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I’ve already covered making the fruit crumble in my<a href="https://www.tomsguide.com/home/kitchen-dining/im-testing-ninjas-first-ever-microwave-with-air-frying-built-in-and-it-fixes-the-worst-thing-about-microwaves"> first impressions of the Ninja Crispi Microwave, </a>where I explain how large and heavy the glass bowl is. It will allow you to make a huge serving, but this might not be what you want. </p><p>When baking the crumble, I placed the bowl in the top position and pressed the FusionCrisp button. I then set the microwave time to 20 minutes, followed by the air fry time to 10 minutes, as the recipe directed. </p><p>You'll hear the appliance beep when the microwave finishes and before the air frying starts. Then, once complete, 'Cool' appears on the digital display. This is when the internal fan runs to dissipate residual heat.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="nm2hqsUaMzB7SDfnMGETiC" name="Fruit crumble made in Ninja Crispi Microwave" alt="Fruit crumble made in Ninja Crispi Microwave" src="https://cdn.mos.cms.futurecdn.net/nm2hqsUaMzB7SDfnMGETiC-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I was really pleased with the result. The fruit was cooked through and piping hot, and the crumble was just how it would be if I’d cooked it in my oven. With a total cook time of 30 minutes, it saved me 10 minutes on my usual oven bake.</p><p>Would I make this again in the Ninja Crispi Microwave? Definitely. </p><p><strong>Baked potatoes</strong></p><p>Who doesn’t love a baked potato with a crispy skin? I usually start by microwaving my potatoes, then leaving them to crisp in the oven, but that takes ages, and it's too long for a quick lunch. However, using the FusionCrisp mode makes it feasible when you are short on time.</p><p>I started by pricking my potatoes all over with a fork, and then gave them a light coating with sunflower oil. I couldn’t find the cooking times for baked potatoes in the guide, so I searched online and placed two potatoes (weighing between 250-300g each) on the crisper plate in the glass dish in the top position. I set the microwave for 14 minutes and the air fryer for 10 minutes. </p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/3ct5SpnoGw4perUqacYH5m-1920-80.jpg" alt="Ninja Crispi Microwave baking potatoes" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/Nyaq7pSVNRbojd5TSFfdFm-1920-80.jpg" alt="Ninja Crispi Microwave baking potatoes" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/8axkPPUHha6hwXCSDJp74m-1920-80.jpg" alt="Ninja Crispi Microwave baking potatoes" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>Baking potatoes and how crisp you like the skin is a personal preference — I like mine on the extra-crispy side, enough to give your jaw a workout. So, you’ll probably need to play around with the air fryer timings, depending on your own taste. However, these were a real winner, and although I’d extend the air-frying time, the inside of the potatoes were soft and cooked through. </p><p><strong>A whole chicken</strong></p><p>Since using the <a href="https://www.tomsguide.com/home/home-appliances/cosori-turboblaze-air-fryer-review">Cosori TurboBlaze Air Fryer</a>, I’ve swapped cooking whole chickens in my oven for using my air fryer. I find it’s quicker, and my air fryer basket is easier to clean than my oven.</p><p>So, I was keen to discover how my regular chicken would look and taste after using the FusionCrisp mode. I followed the recipe in the quick start guide for a 1.5 kg chicken (3.3 lb); I lightly coated the chicken in vegetable oil, seasoned it and placed it on the crisper plate in the glass dish. </p><p>Although everything I had previously cooked using the FusionCrisp mode had been placed in the top position, the size of the chicken called for it to be cooked in the bottom position.</p><p>I set the microwave time to 30 minutes and the air fry dial to 45 minutes. The recipe didn’t specify turning the chicken, like I normally do when I air-fry protein this size, so I skipped this step.</p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/oNeCgrZUk6QbdfPgnAH82A-1920-80.jpg" alt="Ninja Crispi Microwave cooking a whole chicken" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/2GueYM2STFsCF7A3DVu9t3-1920-80.jpg" alt="Ninja Crispi Microwave - chicken after microwave stage" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>Once the microwave stage was complete and the appliance beeped, I removed the chicken to check on its progress. As expected, it still looked pale and unappetizing. However, once the air-frying cook time was up, I checked the temperature of the chicken with my<a href="https://www.tomsguide.com/best-picks/best-meat-thermometers#section-best-meat-thermometer-overall" target="_blank" rel="nofollow"> Thermoworks Thermapen One thermometer</a> and it was above the recommended temperature for cooked chicken.</p><p>However, when I turned the chicken over, it still looked pale, and after inserting the thermometer, it was not at a safe temperature to eat. I therefore returned the chicken, uncooked side up, to the microwave and gave it a few more minutes on the air fry setting.</p><p>This wouldn't stop me from cooking a whole chicken in the microwave; I'd just return to my normal practice and turn the chicken halfway through the cook. </p><p>What about the clean-up? I took a cloth, rinsed it in warm, soapy water and wiped over the internal surface of the microwave to remove the splatters of chicken fat. It was easy to remove, since I hadn't let the fat settle. </p><p><strong>Vegetable lasagna</strong></p><p>One of my favorite recipes is <a href="https://www.bbcgoodfood.com/recipes/easy-pesto-lasagne" target="_blank">pesto lasagna</a>, made with pesto, spinach, pine nuts and mascarpone — try it, you’ll be surprised!</p><p>Since the quick start guide includes a vegetable lasagna recipe, I thought I’d use the same cooking times. I made the lasagna in the glass bowl, then placed it in the top position in the microwave, setting the microwave time to 20 minutes and the air fry time to 8 minutes.</p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/qq6UtxQjMRjmxG6ZCCNdXN-1920-80.jpg" alt="Ninja Crispi Microwave baking lasagna" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/ff3muYv98mHybyYSHWJrMN-1920-80.jpg" alt="Ninja Crispi Microwave baking lasagna" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/xfJXKx9X93EFFu6htnatdN-1920-80.jpg" alt="Ninja Crispi Microwave baking lasagna" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>I was pretty pleased with this bake. The lasagna was well-cooked, the filling hot and the top crispy — if not a little too dark. Since making this lasagna, I've continued to use the microwave for other pasta bakes, as it makes an easy, quick win during the week</p><h2 id="air-fryer">Air fryer</h2><p>Since I'd already used the air fry mode within the FusionCrisp mode, I didn't test the stand alone air fry function as extensively as I would a normal air fryer — to me, it had already proofed that's it's more than capable.</p><p><strong>Grilled cheese toasty</strong></p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="xQ5h32xREod6DTFgJkd8G3" name="Ninja Crispi Microwave" alt="Ninja Crispi Microwave - grilled cheese toasty" src="https://cdn.mos.cms.futurecdn.net/xQ5h32xREod6DTFgJkd8G3-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>To go with the soup I heated in the microwave (see below), I made a grilled cheese toasty. I spread butter on the outside of two slices of granary bread and filled the inside with grated cheddar cheese. I placed the bread on the crisper plate in the glass dish and used the top position in the microwave.</p><p>I checked online to get an idea of timings, and set the temperature to 240°C for 8 minutes, flipping the toasty over at the halfway point.</p><p>The toasty was incredibly moreish, with oozing cheese and a crispy texture. Since making this in the microwave, I've been eating cheese toasties on repeat. </p><p><strong>Thick-cut frozen chips</strong></p><p>Frozen chips are a staple in my house for quick dinners, and it was a no-brainer to try them in the air fryer. I placed them on the crisper tray in the glass dish (there’s plenty of room for large portions), selected the Max Crisp Air Fry setting and set the timer for 20 minutes. </p><p>I checked them after nine minutes, gave them a shake and saw they were cooking faster than I thought. So, after 12 minutes, I checked again, and they were baked. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="LhQ3RQBuHePxLjDS3KALFG" name="Ninja-Crisp-Fries in air fryer" alt="Ninja Crispi Microwave - cooking fries" src="https://cdn.mos.cms.futurecdn.net/LhQ3RQBuHePxLjDS3KALFG-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>Beef burgers</strong><br />To go with the thick chips, I used the air fryer mode to cook frozen beef burgers. Although the quick start guide does give you timings for using the FUSIONCRISP mode (5 minutes microwave, 10-12 minutes air fry). </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="GK7PdTAReSzXy9QasJ3bvT" name="Ninja-Crispi- Microwave cooking beefburgers" alt="Ninja Crispi Microwave cooking beefburgers using the air fry function" src="https://cdn.mos.cms.futurecdn.net/GK7PdTAReSzXy9QasJ3bvT-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I placed two quarter-pounders on the crisper plate in the top glass bowl and set the air fry time to 14 mins at 180°C/356°F, flipping them halfway through. I was pleased with the result, but I will try using the FUSIONCRISP mode next time to see if it makes a difference. </p><h2 id="microwave">Microwave</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="k96qS23vv773g5h3oZJdmC" name="Ninja Crispi Microwave presets" alt="Ninja Crispi Microwave presets" src="https://cdn.mos.cms.futurecdn.net/k96qS23vv773g5h3oZJdmC-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>My normal microwave is very basic and lacks functions, so I was excited to try the Ninja and work through the presets; plus, it was handy for reheating dinners after I went to the gym.</p><p>Overall, I was impressed with the microwave’s functionality, its ability to heat without cold spots, and how easy it is to adjust the timing with the control knob or in 30+/- intervals, as well as the power level.  </p><p><strong>Melting butter</strong><br />I tend to keep my butter in the fridge, especially in summer, when it can start to go rancid. This means my butter is often too hard to spread and definitely not soft enough for cake batters. I found this function really handy, and it meant I didn’t have to think about how long to microwave my butter or which temperature setting to use. It was a surprise to open the microwave and find softened butter instead of my usual melted mess. The preset is set to 30 seconds, but you can adjust this either way. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="efuJj6tzbzYeyQjNgwcGwK" name="Ninja Crispi Microwave softening butter" alt="Ninja Crispi Microwave softening butter" src="https://cdn.mos.cms.futurecdn.net/efuJj6tzbzYeyQjNgwcGwK-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>Heating soup</strong><br />With cozy season upon us, I've started to enjoy warming lunches, so I used the preset to heat through some chicken and vegetable soup. I placed my bowl of soup in the base of the microwave and kept it in for the full 2 1/2 minutes. Once complete, I gave the soup a stir, and it was piping hot.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1962px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="opYABN54qHaZJCVGi4Qm43" name="Ninja Crispi Microwave" alt="Ninja Crispi Microwave - heating soup" src="https://cdn.mos.cms.futurecdn.net/opYABN54qHaZJCVGi4Qm43-1920-80.png" mos="" align="middle" fullscreen="" width="1962" height="1104" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>Porridge</strong><br />With the mornings getting cooler, I was able to make the most of the porridge preset and make myself a bowl of steaming oats. I put 1/2 cup of oats in a bowl with 1 cup of milk, stirred and selected the porridge preset. After two minutes, I removed my oats (though they had boiled over the sides a little), and my breakfast was steaming hot with no cold spots. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="LBkvz6D3nZtwtfxh2Bfxi9" name="Ninja Crispi Microwave making porridge preset" alt="Ninja Crispi Microwave making porridge preset" src="https://cdn.mos.cms.futurecdn.net/LBkvz6D3nZtwtfxh2Bfxi9-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future /Camilla Sharman)</span></figcaption></figure><p>OK, so I had a bit of leakage; normally I'd remove the turntable from my microwave and wash it by hand or put it in my dishwasher. However, with the Ninja, I simply took a damp cloth and wiped up the mess. I found the inner design makes it easy to clean up messes, with no ridges to hold a turntable. </p><h3 class="article-body__section" id="section-ninja-crispi-microwave-verdict"><span>Ninja Crispi Microwave: Verdict</span></h3><p>I’m in love with the Ninja Crispi Microwave, and I don’t want this to disappear from my kitchen. It’s great for baking pasta bakes and crumbles, and it does a good job with whole chickens (just remember to flip the food halfway through). Plus, the presets are super handy, and the best bit is that it’s fun to use. </p><p>So why haven’t I given it 5 stars? It’s got nothing to do with its prowess as a cooking appliance; it’s simply its size. You need serious space in your kitchen for this microwave, not to mention the clearance headroom above it, and the large glass dish is heavy to handle, especially when it’s placed in the top position. If you can work around these issues, it’s well worth considering.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Xrgp0e"></div>                            </div>                            <script src="https://kwizly.com/embed/Xrgp0e.js" async=""></script>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Gardening experts reveal how often you should aerate your lawn and how many passes are best ]]></title>
                                                                                                <dc:content><![CDATA[ <p>It's a great time of year to roll out your lawn aerator and get to work. Bringing air into the lawn soil will not only help relieve any pressure and compaction that's happened over the year, but it'll also improve airflow, water absorption and your lawn's overall ability to access nutrients to help it grow.</p><p>It's not something you need to do too often, but it's a step you don't really want to miss if your lawn is heavily <a href="https://www.tomsguide.com/home/gardening/your-soil-might-still-be-compacted-from-winter-heres-how-to-fix-it-before-planting">compacted </a>or struggling to drain water (especially with all the rain).</p><p>Only after you put in all that effort to push your lawn aerator across your lawn, you might be left wondering if you've done a good enough job. It's certainly something I've contemplated as I stare at my own lawn, unsure whether I've made any <em>real</em> difference.</p><p>I've asked the experts for their professional advice on how often you should aerate your lawn, how many passes are enough, and other tips and tricks to get the best results.</p><h2 id="when-to-aerate-your-lawn">When to aerate your lawn</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5972px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Dzg3UWE9aBJfJQ7KEfxNUW" name="Aerate.jpg" alt="A core aerator being used to aerate a lawn" src="https://cdn.mos.cms.futurecdn.net/Dzg3UWE9aBJfJQ7KEfxNUW-1920-80.jpg" mos="" align="middle" fullscreen="" width="5972" height="3359" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Soil compaction is the ultimate telltale sign that your lawn needs aerating, but how exactly do you figure out if that's what's going on beneath the soil?</p><p>Allison Koenig, a lawn and garden expert at <a href="https://www.tractorsupply.com/" target="_blank" rel="nofollow">Tractor Supply</a>, says: "Homeowners should consider aeration if they're seeing standing water after rain, hard-packed soil, thinning grass, or areas that get a lot of traffic.</p><p>"A good rule of thumb is the screwdriver test: if it's hard to push a screwdriver into the soil, compaction is probably preventing healthy root growth."</p><p>And once you've figured out that your lawn needs aerating, you also have to consider if it's a good time to do it. </p><p>"Timing is everything when it comes to aeration. The best time to aerate your lawn depends on the grass type you have," explains Chris Ramos, PR &amp; Events Coordinator at <a href="https://www.farmandfleet.com/?srsltid=AU7gw4U82Zk_CyStWTHVpfkHlWVB5E0Ig6XomDtg_oYBShVItwHwGjEy" target="_blank" rel="nofollow">Blain's Farm &amp; Fleet</a></p><p>When it comes to cool-season grasses like Fescue and Bluegrass, early fall or spring are ideal times, as these grasses grow most vigorously during colder months.</p><p>And if you've got warm-season grasses like Bermuda or Zoysia, then late spring to early summer is optimal, coinciding with their peak growing season.</p><p>Though Koenig adds: "However, once the ground freezes or the grass has gone fully dormant, it's best to hold off on aggressive projects like aerating, heavy raking, or major repairs."</p><p>Once you've figured out the best time though, Ramos reveals you only <em>really</em> need to aerate your lawn once a year.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OKyEoe"></div>                            </div>                            <script src="https://kwizly.com/embed/OKyEoe.js" async=""></script><h2 id="how-many-passes-should-you-make-with-your-lawn-aerator">How many passes should you make with your lawn aerator</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5990px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="wzY9HsKADfcT4HZffh4D5g" name="Tidy.jpg" alt="A strip of lawn which has been freshly aerated with cores of soil on top" src="https://cdn.mos.cms.futurecdn.net/wzY9HsKADfcT4HZffh4D5g-1920-80.jpg" mos="" align="middle" fullscreen="" width="5990" height="3369" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>So, you're planning to aerate your lawn, but how many passes should you be making to get the best results? </p><p>According to Ramos, one or two passes should relieve soil compaction. In addition, choosing the right tool in the first place will have a major impact on how effective your lawn aeration is.  </p><p>"There are two types of aerators. Spike Aerators: These tools create holes by pushing spikes into the soil," adds Ramos. "They're simple to use but might not be as effective on highly compacted soil.</p><p>"Plug Aerators: These remove small plugs of soil from your lawn, providing more lasting benefits by reducing compaction more effectively. They're generally the preferred option for most lawns."</p><div class="product"><a data-dimension112="1c4ac4c8-c300-11f1-a59c-6590ed8b5fb5" data-action="Deal Block" data-label="Manual Lawn Aerator" data-dimension48="Manual Lawn Aerator" data-dimension25="$48.95" href="https://www.amazon.com/Yard-Butler-Dethatching-Aeration-ID-6C/dp/B00EOMCJD6" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="j4eKrVnj6ds9aBJ7rXJMSb" name="lawn_aerator_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/j4eKrVnj6ds9aBJ7rXJMSb-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Yard-Butler-Dethatching-Aeration-ID-6C/dp/B00EOMCJD6" target="_blank" rel="nofollow" data-dimension112="1c4ac4c8-c300-11f1-a59c-6590ed8b5fb5" data-action="Deal Block" data-label="Manual Lawn Aerator" data-dimension48="Manual Lawn Aerator" data-dimension25="$48.95">Manual Lawn Aerator: $48.95</a></strong><br />This Yard Butler manual lawn coring aerator has a long handle for extra leverage, soft cushioning for your hands and a powder-coated steel design to work hard all-year round. It also uses dual plugs and a versatile foot bar to help you leverage out those holes with ease.<a class="view-deal button" href="https://www.amazon.com/Yard-Butler-Dethatching-Aeration-ID-6C/dp/B00EOMCJD6" target="_blank" rel="nofollow" data-dimension112="1c4ac4c8-c300-11f1-a59c-6590ed8b5fb5" data-action="Deal Block" data-label="Manual Lawn Aerator" data-dimension48="Manual Lawn Aerator" data-dimension25="$48.95">View Deal</a></p></div><h2 id="additional-top-tips">Additional top tips</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:8674px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="DNe9kwrtK3EdUoANa8LTJW" name="Grass seeds - crop.jpg" alt="Holding grass seeds to plant" src="https://cdn.mos.cms.futurecdn.net/DNe9kwrtK3EdUoANa8LTJW-1920-80.jpg" mos="" align="middle" fullscreen="" width="8674" height="4879" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Lawn aeration alone isn't <em>all</em> you should be doing. As Brian Feldman, Senior Director of Technical Operations and Agronomy at <a href="https://www.trugreen.com/" target="_blank" rel="nofollow">TruGreen</a> explains: "One of the biggest misconceptions in the industry is viewing aeration as a standalone service.</p><p>"The greatest results occur when aeration is intergrated into a comprehensive turf management program that includes proper mowing, fertilization, irrigation, and overseeding practices."</p><p>In fact, he suggests that if you're really looking for best practice when aerating your lawn, you should be "overseeding and fertilizing immediately after aerating to maximize growth. </p><p>It's also important to leave the soil cores on your lawn after aerating, as they will naturally break down and help recycle nutrients and other beneficial microorganisms."</p><p>So, while you can do an excellent job with your lawn aeration, timing it right and carrying out one or two passes until you're satisfied that you've relieved compaction, it's important to take the opportunity to do more for your lawn when it's at its most receptive.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><strong></strong><a href="https://www.tomsguide.com/how-to/how-to-aerate-a-lawn-and-when-to-do-it"><strong>How to aerate a lawn and when to do it</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/home/gardening/i-asked-gardening-experts-the-secret-to-a-greener-lawn-heres-what-they-want-you-to-do-this-spring"><strong>I asked gardening experts the secret to a greener lawn — here's what they want you to do</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/how-to/7-signs-your-lawn-needs-aerating"><strong>9 signs your lawn needs aerating</strong></a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/lawn-care/gardening-experts-reveal-how-often-you-should-aerate-your-lawn-and-how-many-passes-are-best</link>
                                                                            <description>
                            <![CDATA[ Aerating your lawn can make all the difference between grass that's thriving or grass that's suffering. Here's what the experts suggest to help you achieve the best results. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">22kwW5EESFLtokAGSbS447</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/HRQv45H8EwrfGdoY9G4Yz4-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 09 Oct 2026 08:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Lawn Care]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/HRQv45H8EwrfGdoY9G4Yz4-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A gas powered aerator being used on a lawn]]></media:description>                                                            <media:text><![CDATA[A gas powered aerator being used on a lawn]]></media:text>
                                <media:title type="plain"><![CDATA[A gas powered aerator being used on a lawn]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/HRQv45H8EwrfGdoY9G4Yz4-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>It's a great time of year to roll out your lawn aerator and get to work. Bringing air into the lawn soil will not only help relieve any pressure and compaction that's happened over the year, but it'll also improve airflow, water absorption and your lawn's overall ability to access nutrients to help it grow.</p><p>It's not something you need to do too often, but it's a step you don't really want to miss if your lawn is heavily <a href="https://www.tomsguide.com/home/gardening/your-soil-might-still-be-compacted-from-winter-heres-how-to-fix-it-before-planting">compacted </a>or struggling to drain water (especially with all the rain).</p><p>Only after you put in all that effort to push your lawn aerator across your lawn, you might be left wondering if you've done a good enough job. It's certainly something I've contemplated as I stare at my own lawn, unsure whether I've made any <em>real</em> difference.</p><p>I've asked the experts for their professional advice on how often you should aerate your lawn, how many passes are enough, and other tips and tricks to get the best results.</p><h2 id="when-to-aerate-your-lawn">When to aerate your lawn</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5972px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Dzg3UWE9aBJfJQ7KEfxNUW" name="Aerate.jpg" alt="A core aerator being used to aerate a lawn" src="https://cdn.mos.cms.futurecdn.net/Dzg3UWE9aBJfJQ7KEfxNUW-1920-80.jpg" mos="" align="middle" fullscreen="" width="5972" height="3359" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Soil compaction is the ultimate telltale sign that your lawn needs aerating, but how exactly do you figure out if that's what's going on beneath the soil?</p><p>Allison Koenig, a lawn and garden expert at <a href="https://www.tractorsupply.com/" target="_blank" rel="nofollow">Tractor Supply</a>, says: "Homeowners should consider aeration if they're seeing standing water after rain, hard-packed soil, thinning grass, or areas that get a lot of traffic.</p><p>"A good rule of thumb is the screwdriver test: if it's hard to push a screwdriver into the soil, compaction is probably preventing healthy root growth."</p><p>And once you've figured out that your lawn needs aerating, you also have to consider if it's a good time to do it. </p><p>"Timing is everything when it comes to aeration. The best time to aerate your lawn depends on the grass type you have," explains Chris Ramos, PR &amp; Events Coordinator at <a href="https://www.farmandfleet.com/?srsltid=AU7gw4U82Zk_CyStWTHVpfkHlWVB5E0Ig6XomDtg_oYBShVItwHwGjEy" target="_blank" rel="nofollow">Blain's Farm &amp; Fleet</a></p><p>When it comes to cool-season grasses like Fescue and Bluegrass, early fall or spring are ideal times, as these grasses grow most vigorously during colder months.</p><p>And if you've got warm-season grasses like Bermuda or Zoysia, then late spring to early summer is optimal, coinciding with their peak growing season.</p><p>Though Koenig adds: "However, once the ground freezes or the grass has gone fully dormant, it's best to hold off on aggressive projects like aerating, heavy raking, or major repairs."</p><p>Once you've figured out the best time though, Ramos reveals you only <em>really</em> need to aerate your lawn once a year.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OKyEoe"></div>                            </div>                            <script src="https://kwizly.com/embed/OKyEoe.js" async=""></script><h2 id="how-many-passes-should-you-make-with-your-lawn-aerator">How many passes should you make with your lawn aerator</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5990px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="wzY9HsKADfcT4HZffh4D5g" name="Tidy.jpg" alt="A strip of lawn which has been freshly aerated with cores of soil on top" src="https://cdn.mos.cms.futurecdn.net/wzY9HsKADfcT4HZffh4D5g-1920-80.jpg" mos="" align="middle" fullscreen="" width="5990" height="3369" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>So, you're planning to aerate your lawn, but how many passes should you be making to get the best results? </p><p>According to Ramos, one or two passes should relieve soil compaction. In addition, choosing the right tool in the first place will have a major impact on how effective your lawn aeration is.  </p><p>"There are two types of aerators. Spike Aerators: These tools create holes by pushing spikes into the soil," adds Ramos. "They're simple to use but might not be as effective on highly compacted soil.</p><p>"Plug Aerators: These remove small plugs of soil from your lawn, providing more lasting benefits by reducing compaction more effectively. They're generally the preferred option for most lawns."</p><div class="product"><a data-dimension112="1c4ac4c8-c300-11f1-a59c-6590ed8b5fb5" data-action="Deal Block" data-label="Manual Lawn Aerator" data-dimension48="Manual Lawn Aerator" data-dimension25="$48.95" href="https://www.amazon.com/Yard-Butler-Dethatching-Aeration-ID-6C/dp/B00EOMCJD6" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="j4eKrVnj6ds9aBJ7rXJMSb" name="lawn_aerator_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/j4eKrVnj6ds9aBJ7rXJMSb-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Yard-Butler-Dethatching-Aeration-ID-6C/dp/B00EOMCJD6" target="_blank" rel="nofollow" data-dimension112="1c4ac4c8-c300-11f1-a59c-6590ed8b5fb5" data-action="Deal Block" data-label="Manual Lawn Aerator" data-dimension48="Manual Lawn Aerator" data-dimension25="$48.95">Manual Lawn Aerator: $48.95</a></strong><br />This Yard Butler manual lawn coring aerator has a long handle for extra leverage, soft cushioning for your hands and a powder-coated steel design to work hard all-year round. It also uses dual plugs and a versatile foot bar to help you leverage out those holes with ease.<a class="view-deal button" href="https://www.amazon.com/Yard-Butler-Dethatching-Aeration-ID-6C/dp/B00EOMCJD6" target="_blank" rel="nofollow" data-dimension112="1c4ac4c8-c300-11f1-a59c-6590ed8b5fb5" data-action="Deal Block" data-label="Manual Lawn Aerator" data-dimension48="Manual Lawn Aerator" data-dimension25="$48.95">View Deal</a></p></div><h2 id="additional-top-tips">Additional top tips</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:8674px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="DNe9kwrtK3EdUoANa8LTJW" name="Grass seeds - crop.jpg" alt="Holding grass seeds to plant" src="https://cdn.mos.cms.futurecdn.net/DNe9kwrtK3EdUoANa8LTJW-1920-80.jpg" mos="" align="middle" fullscreen="" width="8674" height="4879" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Lawn aeration alone isn't <em>all</em> you should be doing. As Brian Feldman, Senior Director of Technical Operations and Agronomy at <a href="https://www.trugreen.com/" target="_blank" rel="nofollow">TruGreen</a> explains: "One of the biggest misconceptions in the industry is viewing aeration as a standalone service.</p><p>"The greatest results occur when aeration is intergrated into a comprehensive turf management program that includes proper mowing, fertilization, irrigation, and overseeding practices."</p><p>In fact, he suggests that if you're really looking for best practice when aerating your lawn, you should be "overseeding and fertilizing immediately after aerating to maximize growth. </p><p>It's also important to leave the soil cores on your lawn after aerating, as they will naturally break down and help recycle nutrients and other beneficial microorganisms."</p><p>So, while you can do an excellent job with your lawn aeration, timing it right and carrying out one or two passes until you're satisfied that you've relieved compaction, it's important to take the opportunity to do more for your lawn when it's at its most receptive.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><strong></strong><a href="https://www.tomsguide.com/how-to/how-to-aerate-a-lawn-and-when-to-do-it"><strong>How to aerate a lawn and when to do it</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/home/gardening/i-asked-gardening-experts-the-secret-to-a-greener-lawn-heres-what-they-want-you-to-do-this-spring"><strong>I asked gardening experts the secret to a greener lawn — here's what they want you to do</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/how-to/7-signs-your-lawn-needs-aerating"><strong>9 signs your lawn needs aerating</strong></a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ When should you winterize your sprinklers — and how to do it right ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Leaving water in your irrigation system over winter is a fast way to ruin expensive plumbing. As trapped water freezes, it expands, snapping underground PVC pipes, shattering valve manifolds, and cracking exposed backflow assemblies. Fixing freeze damage in the spring often requires tearing up your lawn and paying hefty repair bills. </p><p>Taking a little time in the autumn to properly shut down and drain your sprinklers protects your equipment, saves money, and ensures your system is ready to fire back up smoothly when warmer weather returns.</p><section class="howto-block">                    <h3>Why you need to winterize your sprinklers</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/2Rniz968qgivF8qdX7XBNc.jpg"                                        alt="Leaves on frosty lawn"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/2Rniz968qgivF8qdX7XBNc.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Ignoring your sprinkler system in the fall is a gamble your wallet will lose. Water left trapped inside your pipes expands with incredible force when it freezes, turning underground PVC lines into brittle plastic, shattering valve manifolds, and exploding your backflow assembly. </p><p>What starts as a minor late-season maintenance chore quickly turns into a nightmare of torn-up lawns, flooded soil beds, and a hefty repair bill. Properly draining and blowing out your water lines in the fall prevents these structural failures and keeps your system functional for the following season.</p></p>                </section><section class="howto-block">                    <h3>When to winterize your sprinklers </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/4fCwWy8bMKMMZEvz2Jjtqa.jpg"                                        alt="A lawn being watered by sprinklers at night"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/4fCwWy8bMKMMZEvz2Jjtqa.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Timing is everything when shutting down your irrigation for the year. <strong>You should aim to winterize your system in mid-to-late fall</strong>, ideally 1 to 2 weeks before your region’s forecasted first hard freeze. </p><p>While light ground frosts around 32°F won't immediately penetrate the soil to damage buried pipes, a hard freeze (defined as temperatures dropping to 28°F or lower for several continuous hours) will quickly freeze water inside shallow lines and exposed backflow preventers. </p><p><strong>Another clear signal is your lawn's growth cycle</strong>. Once daily average temperatures consistently drop below 50°F, grass enters dormancy and no longer requires active watering, making it the perfect time to turn off the faucet.</p></p>                </section><section class="howto-block">                    <h3>How to winterize your sprinklers</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/R3kPv5CKUexspaNmoirrgK.jpg"                                        alt="Backflow preventer for sprinkler system "                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/R3kPv5CKUexspaNmoirrgK.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p><strong>Start by shutting off the main water valve to your irrigation line</strong>, usually located in your basement, crawl space, or an underground box near your meter. Next, <strong>turn your sprinkler controller to "Off" or "Rain Mode" </strong>so your saved settings stay intact without triggering dry valves. </p><p>To clear the water, the safest method for freezing climates is a compressed air blowout: <strong>attach a compressor to your blowout port </strong>downstream of the backflow preventer, <strong>cap the pressure at 50 to 80 PSI maximum</strong> to protect your pipes, and<strong> run air through one zone at a time for 1 to 2 minutes</strong> until only fine mist emerges. </p><p>If your system features manual or automatic drain valves at the lowest points of the piping, open those to let gravity empty the lines. </p><p>Finally, protect your above-ground backflow preventer by <strong>opening the test cocks, setting the ball valves at a 45-degree angle</strong> so water isn't trapped inside the valve seats, and <strong>wrapping the unit in an insulated cover</strong>.</p></p>                </section><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eAG7EO"></div>                            </div>                            <script src="https://kwizly.com/embed/eAG7EO.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/how-to-prepare-your-above-ground-pool-for-winter-7-simple-steps">How to prepare your above ground pool for winter in 7 simple steps </a></li><li><a href="https://www.tomsguide.com/home/lawn-care/the-secret-to-stopping-weeds-next-spring-apply-this-simple-barrier-to-your-lawn-right-now">Stop spring lawn weeds before they sprout with a simple fall pre-emergent barrier — applying it now saves you hours of yard work next year</a></li><li><a href="https://www.tomsguide.com/home/gardening/3-essential-fall-jobs-to-protect-young-trees-before-the-first-cold-snap">3 essential fall jobs to protect young trees before the first cold snap</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/outdoors/freezing-weather-can-destroy-your-sprinkler-system-heres-how-to-winterize-it-now-clone</link>
                                                                            <description>
                            <![CDATA[ Learn when to winterize your sprinkler system before the first hard freeze and the key steps to drain your lines to prevent costly repairs. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">sxzrV3AVWCC3ohNFtBiMRj</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/xZsyBB9oLXiQLfFv8kPgyD-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 06 Oct 2026 08:03:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Outdoors]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                                                                <author><![CDATA[ kaycee.hill@futurenet.com (Kaycee Hill) ]]></author>                    <dc:creator><![CDATA[ Kaycee Hill ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/xHn6RmpEqg87cvtLwrBu9G-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/xZsyBB9oLXiQLfFv8kPgyD-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Sprinkler system compressed air]]></media:description>                                                            <media:text><![CDATA[Sprinkler system compressed air]]></media:text>
                                <media:title type="plain"><![CDATA[Sprinkler system compressed air]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/xZsyBB9oLXiQLfFv8kPgyD-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Leaving water in your irrigation system over winter is a fast way to ruin expensive plumbing. As trapped water freezes, it expands, snapping underground PVC pipes, shattering valve manifolds, and cracking exposed backflow assemblies. Fixing freeze damage in the spring often requires tearing up your lawn and paying hefty repair bills. </p><p>Taking a little time in the autumn to properly shut down and drain your sprinklers protects your equipment, saves money, and ensures your system is ready to fire back up smoothly when warmer weather returns.</p><section class="howto-block">                    <h3>Why you need to winterize your sprinklers</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/2Rniz968qgivF8qdX7XBNc.jpg"                                        alt="Leaves on frosty lawn"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/2Rniz968qgivF8qdX7XBNc.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Ignoring your sprinkler system in the fall is a gamble your wallet will lose. Water left trapped inside your pipes expands with incredible force when it freezes, turning underground PVC lines into brittle plastic, shattering valve manifolds, and exploding your backflow assembly. </p><p>What starts as a minor late-season maintenance chore quickly turns into a nightmare of torn-up lawns, flooded soil beds, and a hefty repair bill. Properly draining and blowing out your water lines in the fall prevents these structural failures and keeps your system functional for the following season.</p></p>                </section><section class="howto-block">                    <h3>When to winterize your sprinklers </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/4fCwWy8bMKMMZEvz2Jjtqa.jpg"                                        alt="A lawn being watered by sprinklers at night"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/4fCwWy8bMKMMZEvz2Jjtqa.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Timing is everything when shutting down your irrigation for the year. <strong>You should aim to winterize your system in mid-to-late fall</strong>, ideally 1 to 2 weeks before your region’s forecasted first hard freeze. </p><p>While light ground frosts around 32°F won't immediately penetrate the soil to damage buried pipes, a hard freeze (defined as temperatures dropping to 28°F or lower for several continuous hours) will quickly freeze water inside shallow lines and exposed backflow preventers. </p><p><strong>Another clear signal is your lawn's growth cycle</strong>. Once daily average temperatures consistently drop below 50°F, grass enters dormancy and no longer requires active watering, making it the perfect time to turn off the faucet.</p></p>                </section><section class="howto-block">                    <h3>How to winterize your sprinklers</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/R3kPv5CKUexspaNmoirrgK.jpg"                                        alt="Backflow preventer for sprinkler system "                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/R3kPv5CKUexspaNmoirrgK.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p><strong>Start by shutting off the main water valve to your irrigation line</strong>, usually located in your basement, crawl space, or an underground box near your meter. Next, <strong>turn your sprinkler controller to "Off" or "Rain Mode" </strong>so your saved settings stay intact without triggering dry valves. </p><p>To clear the water, the safest method for freezing climates is a compressed air blowout: <strong>attach a compressor to your blowout port </strong>downstream of the backflow preventer, <strong>cap the pressure at 50 to 80 PSI maximum</strong> to protect your pipes, and<strong> run air through one zone at a time for 1 to 2 minutes</strong> until only fine mist emerges. </p><p>If your system features manual or automatic drain valves at the lowest points of the piping, open those to let gravity empty the lines. </p><p>Finally, protect your above-ground backflow preventer by <strong>opening the test cocks, setting the ball valves at a 45-degree angle</strong> so water isn't trapped inside the valve seats, and <strong>wrapping the unit in an insulated cover</strong>.</p></p>                </section><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eAG7EO"></div>                            </div>                            <script src="https://kwizly.com/embed/eAG7EO.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/how-to-prepare-your-above-ground-pool-for-winter-7-simple-steps">How to prepare your above ground pool for winter in 7 simple steps </a></li><li><a href="https://www.tomsguide.com/home/lawn-care/the-secret-to-stopping-weeds-next-spring-apply-this-simple-barrier-to-your-lawn-right-now">Stop spring lawn weeds before they sprout with a simple fall pre-emergent barrier — applying it now saves you hours of yard work next year</a></li><li><a href="https://www.tomsguide.com/home/gardening/3-essential-fall-jobs-to-protect-young-trees-before-the-first-cold-snap">3 essential fall jobs to protect young trees before the first cold snap</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I ditched my mop and bucket for the Flash Speed Mop — and it's the best cleaning decision I've ever made ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Cleaning my floors is one of those jobs I just <em>never</em> want to do. For some reason, the idea of filling up a bucket with soapy water and pushing a soggy mop around my kitchen and bathrooms is so low on my priority list that it often gets ignored completely. And don't even get me started on cleaning the mop head afterwards. </p><p>I've tried a spin mop, mops with replaceable and washable heads, and even a vacuum mop hybrid, yet the idea of washing my floors still feels like too much of a chore. </p><p>But, my social media has clearly been listening to me ranting about what mop I <em>should</em> be buying as my feed was suddenly very mop-heavy. </p><p>And then, amongst it all, I saw someone cleaning up their floors in record time with what appeared to be no fuss at all – and it was thanks to the Flash Speed Mop. Well, consider me thoroughly influenced to try it.</p><h2 id="how-does-it-work-3">How does it work?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="YgsLxDELL9W8gLgyDwgFLQ" name="flashmop_8" alt="A Flash Speed Mop propped against a kitchen wall" src="https://cdn.mos.cms.futurecdn.net/YgsLxDELL9W8gLgyDwgFLQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The Flash Speed Mop is ridiculously simple. It's an all-in-one flat floor mop equipped to hold scented wet wipes, or dry wipes, which are then pushed around your floors with a little bit of scrubbing. </p><p>The wet wipes are pre-moistened and contain dirt-dissolving cleansers ready to wipe up any spills and stains. It also has 360-degree swivel, meaning its super flexible when you're trying to get in hard-to-reach places and up against corners.</p><p>Then, when you're done, you simply remove the wipe, throw it in the bin, and replace whenever you're ready to clean again.</p><div class="product"><a data-dimension112="ef297a0c-c0a7-11f1-a9d1-9b15e888d0b3" data-action="Deal Block" data-label="Speed Mop Starter Kit" data-dimension48="Speed Mop Starter Kit" data-dimension25="$53.31" href="https://www.amazon.com/Speedmop-Cleaner-Starter-Cleaning-Floors/dp/B0GJFKH6BT" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="B32GdhRNZAv7hTEvQMwRnU" name="flash_speed_mop_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/B32GdhRNZAv7hTEvQMwRnU-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>This Flash Speed Mop Starter Kit comes with 20 wet refills and, of course, the actual mop. I was surprised how compact the package was when it showed up, but you easily click all the parts together and it's ready to go. Not only will it clean up your floors, it'll also leave them smelling nice, too.<a class="view-deal button" href="https://www.amazon.com/Speedmop-Cleaner-Starter-Cleaning-Floors/dp/B0GJFKH6BT" target="_blank" rel="nofollow" data-dimension112="ef297a0c-c0a7-11f1-a9d1-9b15e888d0b3" data-action="Deal Block" data-label="Speed Mop Starter Kit" data-dimension48="Speed Mop Starter Kit" data-dimension25="$53.31">View Deal</a></p></div><h2 id="here-39-s-what-happened-when-i-tried-it-3">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="2S4kpxf8DNo6sGGP4bXjHH" name="flashmop_3" alt="The Flash Speed Mop with wipe attached" src="https://cdn.mos.cms.futurecdn.net/2S4kpxf8DNo6sGGP4bXjHH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The kit I ordered came with both the easy-to-assemble mop and a packet of lemon-scented wipes to get started. And I can happily say it was really simple to put together and also super affordable.</p><p>The only thing that was a little bit 'tricky' was putting the wipes onto the mop head as they're very wet in order to spread across as much floor as possible. Unfortunately, that meant my hands also get pretty wet when pushing the wipes into the mop head in the four gripper holes (one on each corner).</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UB9hKYcUXdYxVvgD8EC9TH" name="flashmop_7" alt="The Flash Speed Mop being used on wooden floors" src="https://cdn.mos.cms.futurecdn.net/UB9hKYcUXdYxVvgD8EC9TH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Fortunately, it takes around 10 seconds to do, so it's not much of a complaint and I found it secures the wipes on very well. It's also worth the soggy sacrifice because that solution then made the mop easy to glide around the floors and also had a surprising amount of coverage (as well as picking up a surprising amount of dirt).</p><p>It was also a lot nicer than getting down on my hands and knees and pushing the wipes around myself, which is something I find myself doing in hard-to-reach places. </p><p>But, what I enjoyed the most about this handy mop was being able to pull the wipe off at the end and throw it in the bin. None of the hassle of a mop and bucket, none of the extra cleaning needed to get your mop head washed, and at the end, it was easily stored away.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="zZfofeuXxcsTRgawQLH5TH" name="flashmop_6" alt="The Flash Speed Mop and a used wipe next to it" src="https://cdn.mos.cms.futurecdn.net/zZfofeuXxcsTRgawQLH5TH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>We're about to get more hard floors put down in our house, which made my search for a new mop even more necessary. But, even if you've only got a room or two with hard floors like the kitchen or bathroom, it's not an expensive investment to only use sometimes.</p><p>Plus, the wipes are resealable meaning they're ready to use whenever you want. There's a couple of things that are worth weighing up though. The Flash Speed Mop is certainly less environmentally-friendly with one-use wipes and it also can't be used on certain floor types. These include unfinished, oiled, or waxed wooden boards, plus non-sealed tiles or carpeted floors.</p><p>For me though, it's made cleaning my floors easier than ever before and I can finally stop buying mops that I end up actively avoiding while I watch my floor get dirtier and dirtier!</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/how-to-mop-your-floors-properly-tips-for-spotless-results">How to mop your floors properly — 5 tips for spotless results</a></li><li><a href="https://www.tomsguide.com/home/no-more-dirty-mop-water-this-simple-cleaning-tool-is-a-game-changer">No more dirty mop water — this simple cleaning tool is a game-changer</a></li><li><a href="https://www.tomsguide.com/home/smart-home/i-tried-roborocks-new-wet-floor-cleaner-and-it-does-one-thing-that-dyson-doesnt">I tried Roborock’s new wet floor cleaner and it does one thing that Dyson doesn't</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/i-ditched-my-mop-and-bucket-for-the-flash-speed-mop-and-its-the-best-cleaning-decision-ive-ever-made</link>
                                                                            <description>
                            <![CDATA[ I've had a love-hate relationship with my mop and bucket for a long time, but I've finally made a change that's turned cleaning my floors into a quick and easy task. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">HoCuxDA5CzkzBiSbUTEjZk</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/gReSSU9FGqRKsjurtvLdSH-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 06 Oct 2026 07:00:00 +0000</pubDate>                                                                                                                                <updated>Tue, 06 Oct 2026 08:20:37 +0000</updated>
                                                                                                                                            <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/gReSSU9FGqRKsjurtvLdSH-1920-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Flash Speed Mop next to a packet of wipes]]></media:description>                                                            <media:text><![CDATA[The Flash Speed Mop next to a packet of wipes]]></media:text>
                                <media:title type="plain"><![CDATA[The Flash Speed Mop next to a packet of wipes]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/gReSSU9FGqRKsjurtvLdSH-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Cleaning my floors is one of those jobs I just <em>never</em> want to do. For some reason, the idea of filling up a bucket with soapy water and pushing a soggy mop around my kitchen and bathrooms is so low on my priority list that it often gets ignored completely. And don't even get me started on cleaning the mop head afterwards. </p><p>I've tried a spin mop, mops with replaceable and washable heads, and even a vacuum mop hybrid, yet the idea of washing my floors still feels like too much of a chore. </p><p>But, my social media has clearly been listening to me ranting about what mop I <em>should</em> be buying as my feed was suddenly very mop-heavy. </p><p>And then, amongst it all, I saw someone cleaning up their floors in record time with what appeared to be no fuss at all – and it was thanks to the Flash Speed Mop. Well, consider me thoroughly influenced to try it.</p><h2 id="how-does-it-work-3">How does it work?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="YgsLxDELL9W8gLgyDwgFLQ" name="flashmop_8" alt="A Flash Speed Mop propped against a kitchen wall" src="https://cdn.mos.cms.futurecdn.net/YgsLxDELL9W8gLgyDwgFLQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The Flash Speed Mop is ridiculously simple. It's an all-in-one flat floor mop equipped to hold scented wet wipes, or dry wipes, which are then pushed around your floors with a little bit of scrubbing. </p><p>The wet wipes are pre-moistened and contain dirt-dissolving cleansers ready to wipe up any spills and stains. It also has 360-degree swivel, meaning its super flexible when you're trying to get in hard-to-reach places and up against corners.</p><p>Then, when you're done, you simply remove the wipe, throw it in the bin, and replace whenever you're ready to clean again.</p><div class="product"><a data-dimension112="ef297a0c-c0a7-11f1-a9d1-9b15e888d0b3" data-action="Deal Block" data-label="Speed Mop Starter Kit" data-dimension48="Speed Mop Starter Kit" data-dimension25="$53.31" href="https://www.amazon.com/Speedmop-Cleaner-Starter-Cleaning-Floors/dp/B0GJFKH6BT" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="B32GdhRNZAv7hTEvQMwRnU" name="flash_speed_mop_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/B32GdhRNZAv7hTEvQMwRnU-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>This Flash Speed Mop Starter Kit comes with 20 wet refills and, of course, the actual mop. I was surprised how compact the package was when it showed up, but you easily click all the parts together and it's ready to go. Not only will it clean up your floors, it'll also leave them smelling nice, too.<a class="view-deal button" href="https://www.amazon.com/Speedmop-Cleaner-Starter-Cleaning-Floors/dp/B0GJFKH6BT" target="_blank" rel="nofollow" data-dimension112="ef297a0c-c0a7-11f1-a9d1-9b15e888d0b3" data-action="Deal Block" data-label="Speed Mop Starter Kit" data-dimension48="Speed Mop Starter Kit" data-dimension25="$53.31">View Deal</a></p></div><h2 id="here-39-s-what-happened-when-i-tried-it-3">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="2S4kpxf8DNo6sGGP4bXjHH" name="flashmop_3" alt="The Flash Speed Mop with wipe attached" src="https://cdn.mos.cms.futurecdn.net/2S4kpxf8DNo6sGGP4bXjHH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The kit I ordered came with both the easy-to-assemble mop and a packet of lemon-scented wipes to get started. And I can happily say it was really simple to put together and also super affordable.</p><p>The only thing that was a little bit 'tricky' was putting the wipes onto the mop head as they're very wet in order to spread across as much floor as possible. Unfortunately, that meant my hands also get pretty wet when pushing the wipes into the mop head in the four gripper holes (one on each corner).</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UB9hKYcUXdYxVvgD8EC9TH" name="flashmop_7" alt="The Flash Speed Mop being used on wooden floors" src="https://cdn.mos.cms.futurecdn.net/UB9hKYcUXdYxVvgD8EC9TH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Fortunately, it takes around 10 seconds to do, so it's not much of a complaint and I found it secures the wipes on very well. It's also worth the soggy sacrifice because that solution then made the mop easy to glide around the floors and also had a surprising amount of coverage (as well as picking up a surprising amount of dirt).</p><p>It was also a lot nicer than getting down on my hands and knees and pushing the wipes around myself, which is something I find myself doing in hard-to-reach places. </p><p>But, what I enjoyed the most about this handy mop was being able to pull the wipe off at the end and throw it in the bin. None of the hassle of a mop and bucket, none of the extra cleaning needed to get your mop head washed, and at the end, it was easily stored away.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="zZfofeuXxcsTRgawQLH5TH" name="flashmop_6" alt="The Flash Speed Mop and a used wipe next to it" src="https://cdn.mos.cms.futurecdn.net/zZfofeuXxcsTRgawQLH5TH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>We're about to get more hard floors put down in our house, which made my search for a new mop even more necessary. But, even if you've only got a room or two with hard floors like the kitchen or bathroom, it's not an expensive investment to only use sometimes.</p><p>Plus, the wipes are resealable meaning they're ready to use whenever you want. There's a couple of things that are worth weighing up though. The Flash Speed Mop is certainly less environmentally-friendly with one-use wipes and it also can't be used on certain floor types. These include unfinished, oiled, or waxed wooden boards, plus non-sealed tiles or carpeted floors.</p><p>For me though, it's made cleaning my floors easier than ever before and I can finally stop buying mops that I end up actively avoiding while I watch my floor get dirtier and dirtier!</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/how-to-mop-your-floors-properly-tips-for-spotless-results">How to mop your floors properly — 5 tips for spotless results</a></li><li><a href="https://www.tomsguide.com/home/no-more-dirty-mop-water-this-simple-cleaning-tool-is-a-game-changer">No more dirty mop water — this simple cleaning tool is a game-changer</a></li><li><a href="https://www.tomsguide.com/home/smart-home/i-tried-roborocks-new-wet-floor-cleaner-and-it-does-one-thing-that-dyson-doesnt">I tried Roborock’s new wet floor cleaner and it does one thing that Dyson doesn't</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Copper upgrades its battery-powered induction stove to bring even more heat to your kitchen ]]></title>
                                                                                                <dc:content><![CDATA[ <p>When<a href="https://www.tomsguide.com/home/kitchen-dining/i-put-a-battery-powered-induction-stove-to-the-test-heres-what-surprised-me"> we put the Copper Charlie induction stove to the test</a> earlier this year, we were impressed by its innovative battery-powered tech that could represent the future of home appliances.</p><p>But, it turns out there's always room for improvement as the 'Classic Charlie' has a newer sibling that's just been released, simply called the 'New Charlie'.</p><p>There's some hefty upgrades to talk about, building on what Copper has already carved out in this futuristic cookery space. The most notable new feature is its ability to plug it into both 120-volt and 240-volt outlets, giving homeowners more flexibility; the  Classic Charlie only works with 120-volt outlets.</p><p>And while that's certainly one of the best upgrades of the New Charlie, it's also not the only way its bringing the heat to kitchens. Here's what else you can expect from the New Charlie.</p><div class="product"><a data-dimension112="01eaccd4-bb14-11f1-bda8-67391bdbba2e" data-action="Deal Block" data-label="Charlie" data-dimension48="Charlie" data-dimension25="$7199" href="https://copperhome.com/products/new-charlie?variant=45044698284125" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="8jBMoevBhdogBN65Nd2Si4" name="copper_charlie_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/8jBMoevBhdogBN65Nd2Si4-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The New Charlie uses an integrated battery that Copper says is even more powerful than gas. In fact, it says, it will boil water 3-4 times faster on any cooking zone. While this powerful battery-powered stove will set you back $7,199 for the Black Walnut design, the Inkwell Black Polymer is $400 less, depending which finish you want.<a class="view-deal button" href="https://copperhome.com/products/new-charlie?variant=45044698284125" target="_blank" rel="nofollow" data-dimension112="01eaccd4-bb14-11f1-bda8-67391bdbba2e" data-action="Deal Block" data-label="Charlie" data-dimension48="Charlie" data-dimension25="$7199">View Deal</a></p></div><h2 id="more-heat-less-waiting">More heat, less waiting</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="E3w5uLa9qk8Te9Fg5vBpmD" name="copper_charlie_2" alt="The Copper Charlie battery-powered induction stove in a kitchen" src="https://cdn.mos.cms.futurecdn.net/E3w5uLa9qk8Te9Fg5vBpmD-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Copper)</span></figcaption></figure><p>The New Charlie's induction coils have also received an upgrade to 3000 Watts, up from 2800 Watts on the original stove. The broiler, too, is also more powerful: it's now 3000 Watts, up from 2700 Watts in the Classic Charlie. </p><p>As a result, the company says that the time to preheat to 350°F has been reduced from 4 minutes 30 seconds down to just 3 minutes 50 seconds.</p><p>Though the new model ships with the 120-volt plug, it can be replaced with a 240 VAC field-wireable attachment plug, if desired.</p><p>Like the Classic Charlie, the New Charlie still has the built-in battery, meaning it'll cook for you even if you're in a blackout.</p><h2 id="availability">Availability</h2><p>While all of these new upgrades are impressive, it's worth bearing in mind the price. The Classic Charlie already came with an expensive price tag of <a href="https://copperhome.com/products/classic-charlie" target="_blank" rel="nofollow">$5,999</a> for the Inkwell Black Polymer design. And you'll see this bump up to $6,399 for the Black Walnut detailing.</p><p>For the New Charlie then, you're looking at a base rate of <a href="https://copperhome.com/products/new-charlie?srsltid=AU7gw4XPoZHk5xEZ5N4tOQNmOClIeWlInuDiDO1F_k-wwuBeRps13EpR" target="_blank" rel="nofollow">$6,799 at copperhome.com</a>, jumping to <a href="https://copperhome.com/products/new-charlie?variant=45044698284125" target="_blank" rel="nofollow">$7,199 for the Black Walnut</a>. That's $800 more for these powerful improvements. </p><p>It's a hard sell at this price, even with all its seriously impressive features, but if you're making the investment, Copper is bringing the heat.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/kitchen-dining/ive-always-been-tempted-by-induction-cooktops-but-id-never-buy-one-for-my-small-kitchen-heres-why">I've always been tempted by induction cooktops, but I'd never buy one for my small kitchen — here's why</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/ive-swapped-to-an-induction-cooktop-from-gas-3-things-i-love-and-1-thing-you-need-to-know">I’ve swapped to an induction cooktop from gas — 3 things I love, and 1 thing you need to know</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/are-you-damaging-your-induction-cooktop-heres-what-you-should-do-to-protect-it">Are you damaging your induction cooktop? Here’s what you should do to protect it</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/kitchen-dining/copper-upgrades-its-battery-powered-induction-stove-to-bring-even-more-heat-to-your-kitchen</link>
                                                                            <description>
                            <![CDATA[ Copper has released the New Charlie, an upgraded version of its innovative battery-powered induction stove – now bringing even more power and style to your kitchen. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Q9GzyPp36hidv5rtNdvXM</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/vXELtZYcMeSZnAWr8kp4nD-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 30 Sep 2026 15:57:50 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Kitchen & Dining]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/vXELtZYcMeSZnAWr8kp4nD-1920-80.jpg">
                                                            <media:credit><![CDATA[Copper]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Copper Charlie battery-powered induction stove in a kitchen]]></media:description>                                                            <media:text><![CDATA[The Copper Charlie battery-powered induction stove in a kitchen]]></media:text>
                                <media:title type="plain"><![CDATA[The Copper Charlie battery-powered induction stove in a kitchen]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/vXELtZYcMeSZnAWr8kp4nD-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>When<a href="https://www.tomsguide.com/home/kitchen-dining/i-put-a-battery-powered-induction-stove-to-the-test-heres-what-surprised-me"> we put the Copper Charlie induction stove to the test</a> earlier this year, we were impressed by its innovative battery-powered tech that could represent the future of home appliances.</p><p>But, it turns out there's always room for improvement as the 'Classic Charlie' has a newer sibling that's just been released, simply called the 'New Charlie'.</p><p>There's some hefty upgrades to talk about, building on what Copper has already carved out in this futuristic cookery space. The most notable new feature is its ability to plug it into both 120-volt and 240-volt outlets, giving homeowners more flexibility; the  Classic Charlie only works with 120-volt outlets.</p><p>And while that's certainly one of the best upgrades of the New Charlie, it's also not the only way its bringing the heat to kitchens. Here's what else you can expect from the New Charlie.</p><div class="product"><a data-dimension112="01eaccd4-bb14-11f1-bda8-67391bdbba2e" data-action="Deal Block" data-label="Charlie" data-dimension48="Charlie" data-dimension25="$7199" href="https://copperhome.com/products/new-charlie?variant=45044698284125" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="8jBMoevBhdogBN65Nd2Si4" name="copper_charlie_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/8jBMoevBhdogBN65Nd2Si4-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The New Charlie uses an integrated battery that Copper says is even more powerful than gas. In fact, it says, it will boil water 3-4 times faster on any cooking zone. While this powerful battery-powered stove will set you back $7,199 for the Black Walnut design, the Inkwell Black Polymer is $400 less, depending which finish you want.<a class="view-deal button" href="https://copperhome.com/products/new-charlie?variant=45044698284125" target="_blank" rel="nofollow" data-dimension112="01eaccd4-bb14-11f1-bda8-67391bdbba2e" data-action="Deal Block" data-label="Charlie" data-dimension48="Charlie" data-dimension25="$7199">View Deal</a></p></div><h2 id="more-heat-less-waiting">More heat, less waiting</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="E3w5uLa9qk8Te9Fg5vBpmD" name="copper_charlie_2" alt="The Copper Charlie battery-powered induction stove in a kitchen" src="https://cdn.mos.cms.futurecdn.net/E3w5uLa9qk8Te9Fg5vBpmD-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Copper)</span></figcaption></figure><p>The New Charlie's induction coils have also received an upgrade to 3000 Watts, up from 2800 Watts on the original stove. The broiler, too, is also more powerful: it's now 3000 Watts, up from 2700 Watts in the Classic Charlie. </p><p>As a result, the company says that the time to preheat to 350°F has been reduced from 4 minutes 30 seconds down to just 3 minutes 50 seconds.</p><p>Though the new model ships with the 120-volt plug, it can be replaced with a 240 VAC field-wireable attachment plug, if desired.</p><p>Like the Classic Charlie, the New Charlie still has the built-in battery, meaning it'll cook for you even if you're in a blackout.</p><h2 id="availability">Availability</h2><p>While all of these new upgrades are impressive, it's worth bearing in mind the price. The Classic Charlie already came with an expensive price tag of <a href="https://copperhome.com/products/classic-charlie" target="_blank" rel="nofollow">$5,999</a> for the Inkwell Black Polymer design. And you'll see this bump up to $6,399 for the Black Walnut detailing.</p><p>For the New Charlie then, you're looking at a base rate of <a href="https://copperhome.com/products/new-charlie?srsltid=AU7gw4XPoZHk5xEZ5N4tOQNmOClIeWlInuDiDO1F_k-wwuBeRps13EpR" target="_blank" rel="nofollow">$6,799 at copperhome.com</a>, jumping to <a href="https://copperhome.com/products/new-charlie?variant=45044698284125" target="_blank" rel="nofollow">$7,199 for the Black Walnut</a>. That's $800 more for these powerful improvements. </p><p>It's a hard sell at this price, even with all its seriously impressive features, but if you're making the investment, Copper is bringing the heat.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/kitchen-dining/ive-always-been-tempted-by-induction-cooktops-but-id-never-buy-one-for-my-small-kitchen-heres-why">I've always been tempted by induction cooktops, but I'd never buy one for my small kitchen — here's why</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/ive-swapped-to-an-induction-cooktop-from-gas-3-things-i-love-and-1-thing-you-need-to-know">I’ve swapped to an induction cooktop from gas — 3 things I love, and 1 thing you need to know</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/are-you-damaging-your-induction-cooktop-heres-what-you-should-do-to-protect-it">Are you damaging your induction cooktop? Here’s what you should do to protect it</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Ooni Halo Core Spiral Mixer Review ]]></title>
                                                                                                <dc:content><![CDATA[ <div  class="fancy-box"><div class="fancy_box-title"></div><div class="fancy_box_body"><p class="fancy-box__body-text"><strong>Price: </strong>$599<br /><strong>Weight:</strong> 18 pounds<br /><strong>Dimensions: </strong>7.7" (H) x 7.2" (W) x 14.2" (D)<br /><strong>Capacity: </strong>4.8 quart<br /><strong>Wattage: </strong>300W<br /><strong>Speed levels: </strong>20 Speeds<br /><strong>Attachments:</strong> Flexible Beater, Spiral Dough Hook, Breaker Bar, Geared Whisk, Splash Guard, Removable Bowl with Proofing Lid<br /><strong>Materials:</strong> Die Cast Aluminium Internal Core, Polymer Outer Body, Stainless Steel Bowl</p></div></div><p>KitchenAid has long been synonymous with stand mixers, but it now faces stiff competition from an unexpected rival. Ooni, known primarily for its outdoor <a href="https://www.tomsguide.com/best-picks/best-outdoor-pizza-ovens">pizza ovens,</a> is expanding into the baking market. </p><p>Following the launch of its second spiral mixer, Ooni is proving to be a serious contender for home bakers who enjoy crafting dough from scratch. <a href="https://www.tomsguide.com/home/home-appliances/ooni-halo-pro-spiral-stand-mixer-review">Ooni’s Halo Pro spiral mixer</a> already takes the top spot for bread making in our <a href="https://www.tomsguide.com/best-picks/best-stand-mixers">best stand mixer buying guide</a>, but at <a href="https://www.amazon.com/dp/B0F746CZ3L?" target="_blank" rel="nofollow">$799 on Amazon</a> it’s above most people’s budgets. </p><p>To address that issue, Ooni has released the Ooni Halo Core, with a smaller 4.8-quart capacity and a more favorable price point, although it’s still undoubtedly expensive at <a href="https://www.amazon.com/dp/B0H5RCW4W2?" target="_blank" rel="nofollow">$599 on Amazon</a>.<br /><br />My verdict? If you make more dough than cakes and cookies, the Halo Core Spiral Mixer is a great buy. But if the majority of your bakes don’t require kneading, I'd stick with my favorite <a href="https://www.tomsguide.com/home/kitchenaid-artisan-plus-mixer-review">KitchenAid Artisan Plus, </a>which just happens to be the same price.</p><h3 class="article-body__section" id="section-ooni-halo-core-review-price-and-availability"><span>Ooni Halo Core review: Price and availability</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/PojSFw8QqGmgEEmhJQiRoD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/jNCVMMgxxMVx9nALeH3UeD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>As already mentioned, the Halo Core Spiral Mixer is <a href="https://www.amazon.com/dp/B0H5RCW4W2?" target="_blank" rel="nofollow">$599 at Amazon</a>, where it’s available in Foundry Black. It’s also available for <a href="https://www.williams-sonoma.com/products/ooni-halo-core-spiral-mixer/" target="_blank" rel="nofollow">$599 at Williams Sonoma</a>, where you’ll also find the Polar White version that I tested. </p><p>In the U.K., you can buy it directly for <a href="https://uk.ooni.com/products/ooni-halo-core-spiral-mixer" target="_blank" rel="nofollow">£499 at Ooni,</a> and it’s also available for the same price at <a href="https://www.johnlewis.com/ooni-halo-core-pizza-dough-home-baking-spiral-stand-mixer/black/p115465364?" target="_blank" rel="nofollow">John Lewis</a> and<a href="https://www.lakeland.co.uk/products/ooni-halo-core-spiral-mixer-charcoal-gre?" target="_blank" rel="nofollow"> Lakeland</a>.</p><h3 class="article-body__section" id="section-ooni-halo-core-review-unboxing-and-set-up"><span>Ooni Halo Core review: Unboxing and set up</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/rYAZeW4GzbfMH2u3NVncqD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/7ccNz77BebQmzvGdkKa5uD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/eoXjCDqYPo3DFrh6RFMRtD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>The appliance arrives well packed, and along with the <strong>4.8-quart bowl</strong> (with a <strong>proofing lid</strong>), you get a <strong>dough hook and beater bar</strong>, a <strong>double-edged silicone beater</strong>, and a <strong>dual-motor whisk</strong>, (I'll be sharing more on the attachments later). The <strong>cable also detaches</strong>, making it easy to store and keep out of the way when not in use. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="X72dJnxrZZhm9oUGYvCRmD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/X72dJnxrZZhm9oUGYvCRmD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Ooni’s stand mixers are a little different from the likes of KitchenAid, and while I like to think appliances are intuitive and I can use them without poring over the instruction booklet for hours, I didn’t take that risk with the Ooni Halo Core. Although my colleague has already tested the Halo Core’s big brother, I was going blind with its younger sibling. For this reason, I'd recommend downloading the <strong>Ooni app </strong>before you get started. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="r6i79R6iVvAgfRVG2QLN7Y" name="Ooni Halo Core dough hook and breaker bar" alt="Ooni Halo Core, dough hook and breaker bar" src="https://cdn.mos.cms.futurecdn.net/r6i79R6iVvAgfRVG2QLN7Y-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>What makes Ooni’s spiral mixers different?</strong></p><p>The Halo Core’s main attraction is its <strong>dough-making ability</strong>, which sets it apart from other stand mixers. Instead of a dough hook for kneading, it also includes a breaker bar. I’ve never used a stand mixer with a breaker bar before, and it’s not just a gimmick. </p><p>Beyond stopping the dough from climbing up the dough hook, the breaker bar creates a double-kneading action that builds stronger gluten strands, which Ooni says is essential for high-hydration pizza and bread dough. </p><p>Professional appliances have a permanently attached breaker bar, but Ooni’s can be removed so that you can use the appliance for other bakes, such as cakes and cookies. </p><div class="youtube-video" data-nosnippet ><div class="video-aspect-box"><iframe data-lazy-priority="high" data-lazy-src="https://www.youtube-nocookie.com/embed/oFnoOIq1U6o" allowfullscreen=""></iframe></div></div><p>You also need to know that the bowl doesn’t stay put. Traditional stand mixers work with an attachment around a fixed bowl, but with Ooni’s mixers, <strong>both the bowl and attachments rotate</strong>. It’s fun to watch! It's similar to how the <a href="https://www.tomsguide.com/home/home-appliances/i-made-cake-cookies-and-bread-in-the-ankarsrum-assistent-stand-mixer-and-its-worth-the-learning-curve">Ankarsrum mixer</a> works, with the base rotating above the attachments on its arm. </p><h3 class="article-body__section" id="section-ooni-halo-core-review-design"><span>Ooni Halo Core review: Design</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.20%;"><img id="t5ogtFJvvCASUtM8HBepQ7" name="Ooni's Halo Core stand mixer" alt="Ooni's Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/t5ogtFJvvCASUtM8HBepQ7-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1124" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Ooni)</span></figcaption></figure><p>The Ooni Halo Core looks like it means business. It doesn’t come in any shiny colorways like other domestic mixers, including KitchenAid’s extensive offering and <a href="https://www.tomsguide.com/home/smegs-newest-stand-mixer-gives-kitchenaid-a-run-for-its-money-heres-why-it-won-me-over">Smeg’s Retro stand mixer</a>. Still, you can choose <strong>Polar White</strong> or<strong> Foundry Black</strong>. I think it has a contemporary look, although it might not be your first choice if you want a stand mixer that looks pretty on your countertop.</p><p>The Halo Core isn’t as large as the Halo Pro, but it can still handle anything from <strong>1 lb to 5.5 lbs of dough </strong>(500g to 2.5kg) — the equivalent of two to ten 12-inch pizzas in a single batch. </p><h3 class="article-body__section" id="section-ooni-halo-core-review-ease-of-use"><span>Ooni Halo Core review: Ease of use</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5t8RT4LPphdDu7yV5yQdZD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/5t8RT4LPphdDu7yV5yQdZD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Apart from being the younger sibling, it’s also 25% smaller and 30% lighter than the Pro, and although it’s over 3 lbs lighter than Kitchen’s Artisan Plus, at <strong>18 lbs</strong> it still feels hefty.</p><p>The mixer has a <strong>tilt-head design</strong> and locks in place, releasing with a lever on the right side. You’ll find the<strong> control button on top of the mixer</strong>, making it easy to use whether you’re right- or left-handed. The <strong>20 speed settings </strong>aren't marked in numbers; instead, an interface lights up around the control dial at 10% increments. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5j49rkGXibn9bw4HG8qqVD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/5j49rkGXibn9bw4HG8qqVD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>To <strong>pause the machine</strong>, tap the control button; there’s no need to go back through the settings to zero. It’s an excellent feature if you want to pause your mix partway through, and then you can press the control dial again, and it will resume where it left off. I love this feature. <br /><br />Unlike other mixers I’ve tested, the <strong>splash guard</strong> attaches neatly to the mixer, not the bowl, so when you lift the mixer’s head, you don’t need to remove the cover to get a clear view into the bowl. It also has a small space to pour in liquid, and when using the dough hook and beater bar, the liquid goes straight to the bar — to the heart of the mix. </p><p>Plus, you always get a clear view of what’s happening inside the bowl, with <strong>two LED lights</strong> positioned on either side of where the beater bar attaches to the mixer. </p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/XyRmzFpiyY28hAPxB78PTd-1920-80.jpg" alt="Ooni Halo Core guard" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/FMLq8uhw9S3ArhC3uUGgtD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>The<strong> attachments</strong> feel premium and heavyweight, with the <strong>dough hook and breaker bar </strong>used together, plus an <strong>angled silicone-edged beater</strong> designed to work deep in the bowl for a better mix while scraping ingredients off the side. It also includes a <strong>dual-motor whisk</strong> with an integrated gearbox to increase mixing speed for rapid, high-performance whipping. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="CKtigEdNkS3RLxrveeoowD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/CKtigEdNkS3RLxrveeoowD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><h3 class="article-body__section" id="section-ooni-halo-core-review-performance"><span>Ooni Halo Core review: Performance</span></h3><h2 id="cake">Cake</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="eBnYdPxJosZn5DkE2kuFEH" name="Ooni Halo Core cake battter" alt="Ooni Halo Core- Bread cake batter" src="https://cdn.mos.cms.futurecdn.net/eBnYdPxJosZn5DkE2kuFEH-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I used an all-in-one lemon cake recipe, and after attaching the flat beater, I added all the ingredients to the bowl. I used softened butter, but in hindsight, I would have softened it more. Unlike the KitchenAid stand mixers I’ve tested, the Ooni Halo Core struggled to beat in the butter. Even at 100% power, I found small bits of unblended butter in the mix, though from a distance it looked perfect. In fact, I found a large clump of butter left on the beater. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UBmpYsrHZzvv9FDEMkEYpM" name="Ooni Halo Core Cake" alt="Ooni Halo Core, cake" src="https://cdn.mos.cms.futurecdn.net/UBmpYsrHZzvv9FDEMkEYpM-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I have since used the mixer again to make cake, and I softened the butter even further to help it incorporate into the mix. But be warned, I didn’t find its performance quite up to the standard of a KitchenAid for cake batters.</p><p>However, the splash guard worked perfectly and stopped any mixture from dispersing from the bowl, and even on full power the mixer stayed steady on my countertop. </p><h2 id="whisking">Whisking</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="meZBSQFjrR6TbefkE39twD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/meZBSQFjrR6TbefkE39twD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>Making butter</strong></p><p>I usually test a mixer’s whisk by whipping heavy cream or whisking egg whites, but following my colleague who tested the Ooni Halo Pro, I made butter. I’ve never had a reason to make butter before, and if you haven’t either, I’d recommend giving it a go. It’s fun to try, and the results were tasty.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="xHwDGuDr248Qqx3Atd4PY3" name="Ooni Halo Core--Making butter - Double cream" alt="Ooni Halo Core making butter and whisking full cream" src="https://cdn.mos.cms.futurecdn.net/xHwDGuDr248Qqx3Atd4PY3-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I added 10fl. oz. (300ml) of heavy cream to the bowl with a pinch of sea salt, attached the splashguard and set the speed to 50%. After a short while, I gradually increased the speed to full power, at which point it measured 74 dB, although the appliance wasn’t under any strain. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="C5pfYH35JpwZFzXdQJgCPi" name="Ooni Halo Core making butter - Buttermilk separating" alt="Ooni Halo Core making butter - Buttermilk separating" src="https://cdn.mos.cms.futurecdn.net/C5pfYH35JpwZFzXdQJgCPi-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>As soon as the cream started to look like overcooked scrambled eggs, I could see the buttermilk separating from the fat — it happens quickly! So beware: keep the splashguard in place instead of lifting the flap to peek inside.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="uksJekV3BFZN8do5AexC58" name="Ooni Halo Core making butter" alt="Ooni Halo Core making butter" src="https://cdn.mos.cms.futurecdn.net/uksJekV3BFZN8do5AexC58-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Once I was happy with how the buttermilk had separated, I strained away the liquid (I saved it for pancakes), squeezed the butter and ran it under cold water to remove any remaining buttermilk. I then shaped it and placed it on some baking parchment in a butter dish. </p><h2 id="bread-dough">Bread dough</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3MQomXp4TmRQJmhFT8ZnuB" name="Ooni Halo Core--Bread dough stuck on side of bowl, needs incorporating" alt="Ooni Halo Core, dough stuck on side of bowl" src="https://cdn.mos.cms.futurecdn.net/3MQomXp4TmRQJmhFT8ZnuB-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I started by making an easy white loaf in the Halo Core. It’s a standard recipe I turn to that uses 1.1 lb (500g) of strong white flour, and olive oil as the fat. </p><p>I attached the dough hook and the breaker bar. The breaker bar slides into place and needs to be tightened with a nut — this is slightly different from the other attachments, which are simply locked in place by twisting. I also attached the splash guard.</p><p>I added the dry ingredients to the bowl, started the mixer on low speed, and then poured in the liquid through the slot in the guard. You’ll see that the liquid is directed straight to the breaker bar.</p><p>I noticed it was taking a little while for the ingredients to pull in from the square edge of the bowl, so I increased the speed to 50% to help the remaining flour incorporate. With KitchenAid mixers, the bowls are narrower at the bottom, so there is less chance of dry ingredients getting stuck around the edges. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2500px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="ipKeRKmJPwwVkjzuLSLaVC" name="Ooni Halo Core stand mixer bread proving" alt="Ooni Halo Core stand mixer bread proving" src="https://cdn.mos.cms.futurecdn.net/ipKeRKmJPwwVkjzuLSLaVC-1920-80.png" mos="" align="middle" fullscreen="" width="2500" height="1406" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I set a timer for 10 minutes and left the dough hook and breaker bar to work the dough to form strong gluten strands. During the kneading phase I noticed how well the mixer handled the tough job; it didn't appear overworked and remained steady on my countertop, as it had done previously. </p><p>Once the kneading was complete, I removed the dough, which looked soft and smooth, knocked it back and waited for it to double in size. I then knocked it back again, shaped it into a round loaf, and placed it on a baking tray, leaving it to prove for an hour before baking. </p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/nwY3Sqe4DgyhDBCrNneZBi-1920-80.jpg" alt="Ooni Halo Core Bread" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/uMMBgCWXYaxyPUnjiocTZ3-1920-80.jpg" alt="Ooni Halo Core Sliced bread" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p> The finished loaf had a lovely flavor with a light texture. In fact, my husband didn’t realize it was homemade, and he was even more surprised when we enjoyed it spread with homemade butter. </p><h2 id="pizza-dough">Pizza dough</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Pb6Z8X65bYx67RqUnwyrJE" name="Ooni Halo Core kneading dough" alt="Ooni Halo Core kneading dough" src="https://cdn.mos.cms.futurecdn.net/Pb6Z8X65bYx67RqUnwyrJE-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Ooni is known for its pizza ovens, so I wasn’t going to get away without making pizza dough in the Ooni Halo Core. I’d already discovered how good it is at making bread, so I expected to impress my family with homemade pizza and a perfect crust. </p><div class="youtube-video" data-nosnippet ><div class="video-aspect-box"><iframe data-lazy-priority="low" data-lazy-src="https://www.youtube-nocookie.com/embed/W0fm1bs4Xhw" allowfullscreen=""></iframe></div></div><p>I used a New York-style pizza dough recipe using 1.5 lbs (638 g) of flour, using a mix of 00 and bread flour. I set the speed to 20% and watched the ingredients come together as I slowly added the liquid. I kept the mixer on for 10 minutes, then removed it for cold proofing overnight in the fridge. </p><p>I loved watching the dough hook and breaker bar form an attractive pattern as it kneaded. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="jMJg82ZYisJEMfrgqeXZAM" name="Pizza dough proving" alt="Pizza dough proving" src="https://cdn.mos.cms.futurecdn.net/jMJg82ZYisJEMfrgqeXZAM-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I could clearly see how the dough was developing, and then, two hours before baking, I removed it from the fridge to allow it to come back to room temperature. After that, I stretched out the dough and covered it with my favorite toppings. </p><p>I’m not the best at shaping pizza — I obviously need more practice — but the dough formed a beautiful crust. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="e4wKhqR8uUyJDw5umpNEoB" name="Ooni Halo Core spiral mixer pizza" alt="Ooni Halo Core spiral mixer pizza" src="https://cdn.mos.cms.futurecdn.net/e4wKhqR8uUyJDw5umpNEoB-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><h3 class="article-body__section" id="section-ooni-halo-core-review-verdict"><span>Ooni Halo Core review: Verdict</span></h3><p>The Ooni Halo Core spiral mixer is a real powerhouse when it comes to making dough — whether you want to make homemade pies or bake bread. The breaker bar is a real genius at double kneading and stopping the dough from climbing up the dough hook, destabilizing the mixer. Plus, it’s much more affordable than the Ooni Halo Pro and brings professional mastery into domestic kitchens.</p><p>I’m not convinced it’s as good as other stand mixers for making cake batters, particularly when dealing with butter, but if you make more dough than cakes and cookies, the Halo Core is a good choice. However, if you’re serious about sweet treats and only occasionally need extra power to knead dough, I’d stick with a KitchenAid. </p><p>There’s no doubt that it’s a premium appliance — if I had my choice I hold onto my KitchenAid Artisan Plus for cakes and use the Ooni Halo Core for breads.</p> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/home-appliances/ooni-halo-core-spiral-mixer-review</link>
                                                                            <description>
                            <![CDATA[ Ooni’s Halo Core Spiral Mixer is impressive, but it’s not quite perfect. Will it make me switch from my favorite KitchenAid stand mixer? ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Rd5EkTGVkmPuKmtbG7NwAX</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/A9zbzoJxMjkaZkdbeWR3dD-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 30 Sep 2026 08:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home Appliances]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                                                                <author><![CDATA[ camilla.sharman@futurenet.com (Camilla Sharman) ]]></author>                    <dc:creator><![CDATA[ Camilla Sharman ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/nY4nvWzofHKHpvzAqN5LVH-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Camilla is the Homes Staff Writer and covers everything to do with homes and gardens. She has a wealth of editorial experience, mounting over 30 years, and covers news and features, tests products for reviews and compiles buying guides.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Her work has appeared in business and consumer titles, including Ideal Home, Real Homes, House Beautiful, Homebuilding &amp;amp; Renovation, and Kitchen &amp;amp; Bathroom Business. She’s even appeared on the cover of Your Home, writing about her own house renovation.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Although she’s obsessed with decorating her home, she also enjoys baking and trying out the latest kitchen appliances. But when she’s not inside, you’ll find her pottering about in her yard, tending to her vegetable patch or taking in her prized hydrangeas. She also enjoys keeping fit, and if she&#039;s not on a spin bike trying to keep up with the class, she&#039;ll be in the pool, or trying to perfect her headstand in a yoga class.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/A9zbzoJxMjkaZkdbeWR3dD-1920-80.jpg">
                                                            <media:credit><![CDATA[Future / Camilla Sharman]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Ooni Halo Core stand mixer]]></media:description>                                                            <media:text><![CDATA[Ooni Halo Core stand mixer]]></media:text>
                                <media:title type="plain"><![CDATA[Ooni Halo Core stand mixer]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/A9zbzoJxMjkaZkdbeWR3dD-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <div  class="fancy-box"><div class="fancy_box-title"></div><div class="fancy_box_body"><p class="fancy-box__body-text"><strong>Price: </strong>$599<br /><strong>Weight:</strong> 18 pounds<br /><strong>Dimensions: </strong>7.7" (H) x 7.2" (W) x 14.2" (D)<br /><strong>Capacity: </strong>4.8 quart<br /><strong>Wattage: </strong>300W<br /><strong>Speed levels: </strong>20 Speeds<br /><strong>Attachments:</strong> Flexible Beater, Spiral Dough Hook, Breaker Bar, Geared Whisk, Splash Guard, Removable Bowl with Proofing Lid<br /><strong>Materials:</strong> Die Cast Aluminium Internal Core, Polymer Outer Body, Stainless Steel Bowl</p></div></div><p>KitchenAid has long been synonymous with stand mixers, but it now faces stiff competition from an unexpected rival. Ooni, known primarily for its outdoor <a href="https://www.tomsguide.com/best-picks/best-outdoor-pizza-ovens">pizza ovens,</a> is expanding into the baking market. </p><p>Following the launch of its second spiral mixer, Ooni is proving to be a serious contender for home bakers who enjoy crafting dough from scratch. <a href="https://www.tomsguide.com/home/home-appliances/ooni-halo-pro-spiral-stand-mixer-review">Ooni’s Halo Pro spiral mixer</a> already takes the top spot for bread making in our <a href="https://www.tomsguide.com/best-picks/best-stand-mixers">best stand mixer buying guide</a>, but at <a href="https://www.amazon.com/dp/B0F746CZ3L?" target="_blank" rel="nofollow">$799 on Amazon</a> it’s above most people’s budgets. </p><p>To address that issue, Ooni has released the Ooni Halo Core, with a smaller 4.8-quart capacity and a more favorable price point, although it’s still undoubtedly expensive at <a href="https://www.amazon.com/dp/B0H5RCW4W2?" target="_blank" rel="nofollow">$599 on Amazon</a>.<br /><br />My verdict? If you make more dough than cakes and cookies, the Halo Core Spiral Mixer is a great buy. But if the majority of your bakes don’t require kneading, I'd stick with my favorite <a href="https://www.tomsguide.com/home/kitchenaid-artisan-plus-mixer-review">KitchenAid Artisan Plus, </a>which just happens to be the same price.</p><h3 class="article-body__section" id="section-ooni-halo-core-review-price-and-availability"><span>Ooni Halo Core review: Price and availability</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/PojSFw8QqGmgEEmhJQiRoD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/jNCVMMgxxMVx9nALeH3UeD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>As already mentioned, the Halo Core Spiral Mixer is <a href="https://www.amazon.com/dp/B0H5RCW4W2?" target="_blank" rel="nofollow">$599 at Amazon</a>, where it’s available in Foundry Black. It’s also available for <a href="https://www.williams-sonoma.com/products/ooni-halo-core-spiral-mixer/" target="_blank" rel="nofollow">$599 at Williams Sonoma</a>, where you’ll also find the Polar White version that I tested. </p><p>In the U.K., you can buy it directly for <a href="https://uk.ooni.com/products/ooni-halo-core-spiral-mixer" target="_blank" rel="nofollow">£499 at Ooni,</a> and it’s also available for the same price at <a href="https://www.johnlewis.com/ooni-halo-core-pizza-dough-home-baking-spiral-stand-mixer/black/p115465364?" target="_blank" rel="nofollow">John Lewis</a> and<a href="https://www.lakeland.co.uk/products/ooni-halo-core-spiral-mixer-charcoal-gre?" target="_blank" rel="nofollow"> Lakeland</a>.</p><h3 class="article-body__section" id="section-ooni-halo-core-review-unboxing-and-set-up"><span>Ooni Halo Core review: Unboxing and set up</span></h3><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/rYAZeW4GzbfMH2u3NVncqD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/7ccNz77BebQmzvGdkKa5uD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/eoXjCDqYPo3DFrh6RFMRtD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>The appliance arrives well packed, and along with the <strong>4.8-quart bowl</strong> (with a <strong>proofing lid</strong>), you get a <strong>dough hook and beater bar</strong>, a <strong>double-edged silicone beater</strong>, and a <strong>dual-motor whisk</strong>, (I'll be sharing more on the attachments later). The <strong>cable also detaches</strong>, making it easy to store and keep out of the way when not in use. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="X72dJnxrZZhm9oUGYvCRmD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/X72dJnxrZZhm9oUGYvCRmD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Ooni’s stand mixers are a little different from the likes of KitchenAid, and while I like to think appliances are intuitive and I can use them without poring over the instruction booklet for hours, I didn’t take that risk with the Ooni Halo Core. Although my colleague has already tested the Halo Core’s big brother, I was going blind with its younger sibling. For this reason, I'd recommend downloading the <strong>Ooni app </strong>before you get started. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="r6i79R6iVvAgfRVG2QLN7Y" name="Ooni Halo Core dough hook and breaker bar" alt="Ooni Halo Core, dough hook and breaker bar" src="https://cdn.mos.cms.futurecdn.net/r6i79R6iVvAgfRVG2QLN7Y-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>What makes Ooni’s spiral mixers different?</strong></p><p>The Halo Core’s main attraction is its <strong>dough-making ability</strong>, which sets it apart from other stand mixers. Instead of a dough hook for kneading, it also includes a breaker bar. I’ve never used a stand mixer with a breaker bar before, and it’s not just a gimmick. </p><p>Beyond stopping the dough from climbing up the dough hook, the breaker bar creates a double-kneading action that builds stronger gluten strands, which Ooni says is essential for high-hydration pizza and bread dough. </p><p>Professional appliances have a permanently attached breaker bar, but Ooni’s can be removed so that you can use the appliance for other bakes, such as cakes and cookies. </p><div class="youtube-video" data-nosnippet ><div class="video-aspect-box"><iframe data-lazy-priority="high" data-lazy-src="https://www.youtube-nocookie.com/embed/oFnoOIq1U6o" allowfullscreen=""></iframe></div></div><p>You also need to know that the bowl doesn’t stay put. Traditional stand mixers work with an attachment around a fixed bowl, but with Ooni’s mixers, <strong>both the bowl and attachments rotate</strong>. It’s fun to watch! It's similar to how the <a href="https://www.tomsguide.com/home/home-appliances/i-made-cake-cookies-and-bread-in-the-ankarsrum-assistent-stand-mixer-and-its-worth-the-learning-curve">Ankarsrum mixer</a> works, with the base rotating above the attachments on its arm. </p><h3 class="article-body__section" id="section-ooni-halo-core-review-design"><span>Ooni Halo Core review: Design</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.20%;"><img id="t5ogtFJvvCASUtM8HBepQ7" name="Ooni's Halo Core stand mixer" alt="Ooni's Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/t5ogtFJvvCASUtM8HBepQ7-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1124" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Ooni)</span></figcaption></figure><p>The Ooni Halo Core looks like it means business. It doesn’t come in any shiny colorways like other domestic mixers, including KitchenAid’s extensive offering and <a href="https://www.tomsguide.com/home/smegs-newest-stand-mixer-gives-kitchenaid-a-run-for-its-money-heres-why-it-won-me-over">Smeg’s Retro stand mixer</a>. Still, you can choose <strong>Polar White</strong> or<strong> Foundry Black</strong>. I think it has a contemporary look, although it might not be your first choice if you want a stand mixer that looks pretty on your countertop.</p><p>The Halo Core isn’t as large as the Halo Pro, but it can still handle anything from <strong>1 lb to 5.5 lbs of dough </strong>(500g to 2.5kg) — the equivalent of two to ten 12-inch pizzas in a single batch. </p><h3 class="article-body__section" id="section-ooni-halo-core-review-ease-of-use"><span>Ooni Halo Core review: Ease of use</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5t8RT4LPphdDu7yV5yQdZD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/5t8RT4LPphdDu7yV5yQdZD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Apart from being the younger sibling, it’s also 25% smaller and 30% lighter than the Pro, and although it’s over 3 lbs lighter than Kitchen’s Artisan Plus, at <strong>18 lbs</strong> it still feels hefty.</p><p>The mixer has a <strong>tilt-head design</strong> and locks in place, releasing with a lever on the right side. You’ll find the<strong> control button on top of the mixer</strong>, making it easy to use whether you’re right- or left-handed. The <strong>20 speed settings </strong>aren't marked in numbers; instead, an interface lights up around the control dial at 10% increments. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5j49rkGXibn9bw4HG8qqVD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/5j49rkGXibn9bw4HG8qqVD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>To <strong>pause the machine</strong>, tap the control button; there’s no need to go back through the settings to zero. It’s an excellent feature if you want to pause your mix partway through, and then you can press the control dial again, and it will resume where it left off. I love this feature. <br /><br />Unlike other mixers I’ve tested, the <strong>splash guard</strong> attaches neatly to the mixer, not the bowl, so when you lift the mixer’s head, you don’t need to remove the cover to get a clear view into the bowl. It also has a small space to pour in liquid, and when using the dough hook and beater bar, the liquid goes straight to the bar — to the heart of the mix. </p><p>Plus, you always get a clear view of what’s happening inside the bowl, with <strong>two LED lights</strong> positioned on either side of where the beater bar attaches to the mixer. </p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/XyRmzFpiyY28hAPxB78PTd-1920-80.jpg" alt="Ooni Halo Core guard" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/FMLq8uhw9S3ArhC3uUGgtD-1920-80.jpg" alt="Ooni Halo Core stand mixer" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p>The<strong> attachments</strong> feel premium and heavyweight, with the <strong>dough hook and breaker bar </strong>used together, plus an <strong>angled silicone-edged beater</strong> designed to work deep in the bowl for a better mix while scraping ingredients off the side. It also includes a <strong>dual-motor whisk</strong> with an integrated gearbox to increase mixing speed for rapid, high-performance whipping. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="CKtigEdNkS3RLxrveeoowD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/CKtigEdNkS3RLxrveeoowD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><h3 class="article-body__section" id="section-ooni-halo-core-review-performance"><span>Ooni Halo Core review: Performance</span></h3><h2 id="cake">Cake</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="eBnYdPxJosZn5DkE2kuFEH" name="Ooni Halo Core cake battter" alt="Ooni Halo Core- Bread cake batter" src="https://cdn.mos.cms.futurecdn.net/eBnYdPxJosZn5DkE2kuFEH-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I used an all-in-one lemon cake recipe, and after attaching the flat beater, I added all the ingredients to the bowl. I used softened butter, but in hindsight, I would have softened it more. Unlike the KitchenAid stand mixers I’ve tested, the Ooni Halo Core struggled to beat in the butter. Even at 100% power, I found small bits of unblended butter in the mix, though from a distance it looked perfect. In fact, I found a large clump of butter left on the beater. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UBmpYsrHZzvv9FDEMkEYpM" name="Ooni Halo Core Cake" alt="Ooni Halo Core, cake" src="https://cdn.mos.cms.futurecdn.net/UBmpYsrHZzvv9FDEMkEYpM-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I have since used the mixer again to make cake, and I softened the butter even further to help it incorporate into the mix. But be warned, I didn’t find its performance quite up to the standard of a KitchenAid for cake batters.</p><p>However, the splash guard worked perfectly and stopped any mixture from dispersing from the bowl, and even on full power the mixer stayed steady on my countertop. </p><h2 id="whisking">Whisking</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="meZBSQFjrR6TbefkE39twD" name="Ooni Halo Core stand mixer" alt="Ooni Halo Core stand mixer" src="https://cdn.mos.cms.futurecdn.net/meZBSQFjrR6TbefkE39twD-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p><strong>Making butter</strong></p><p>I usually test a mixer’s whisk by whipping heavy cream or whisking egg whites, but following my colleague who tested the Ooni Halo Pro, I made butter. I’ve never had a reason to make butter before, and if you haven’t either, I’d recommend giving it a go. It’s fun to try, and the results were tasty.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="xHwDGuDr248Qqx3Atd4PY3" name="Ooni Halo Core--Making butter - Double cream" alt="Ooni Halo Core making butter and whisking full cream" src="https://cdn.mos.cms.futurecdn.net/xHwDGuDr248Qqx3Atd4PY3-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I added 10fl. oz. (300ml) of heavy cream to the bowl with a pinch of sea salt, attached the splashguard and set the speed to 50%. After a short while, I gradually increased the speed to full power, at which point it measured 74 dB, although the appliance wasn’t under any strain. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="C5pfYH35JpwZFzXdQJgCPi" name="Ooni Halo Core making butter - Buttermilk separating" alt="Ooni Halo Core making butter - Buttermilk separating" src="https://cdn.mos.cms.futurecdn.net/C5pfYH35JpwZFzXdQJgCPi-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>As soon as the cream started to look like overcooked scrambled eggs, I could see the buttermilk separating from the fat — it happens quickly! So beware: keep the splashguard in place instead of lifting the flap to peek inside.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="uksJekV3BFZN8do5AexC58" name="Ooni Halo Core making butter" alt="Ooni Halo Core making butter" src="https://cdn.mos.cms.futurecdn.net/uksJekV3BFZN8do5AexC58-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Once I was happy with how the buttermilk had separated, I strained away the liquid (I saved it for pancakes), squeezed the butter and ran it under cold water to remove any remaining buttermilk. I then shaped it and placed it on some baking parchment in a butter dish. </p><h2 id="bread-dough">Bread dough</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3MQomXp4TmRQJmhFT8ZnuB" name="Ooni Halo Core--Bread dough stuck on side of bowl, needs incorporating" alt="Ooni Halo Core, dough stuck on side of bowl" src="https://cdn.mos.cms.futurecdn.net/3MQomXp4TmRQJmhFT8ZnuB-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I started by making an easy white loaf in the Halo Core. It’s a standard recipe I turn to that uses 1.1 lb (500g) of strong white flour, and olive oil as the fat. </p><p>I attached the dough hook and the breaker bar. The breaker bar slides into place and needs to be tightened with a nut — this is slightly different from the other attachments, which are simply locked in place by twisting. I also attached the splash guard.</p><p>I added the dry ingredients to the bowl, started the mixer on low speed, and then poured in the liquid through the slot in the guard. You’ll see that the liquid is directed straight to the breaker bar.</p><p>I noticed it was taking a little while for the ingredients to pull in from the square edge of the bowl, so I increased the speed to 50% to help the remaining flour incorporate. With KitchenAid mixers, the bowls are narrower at the bottom, so there is less chance of dry ingredients getting stuck around the edges. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2500px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="ipKeRKmJPwwVkjzuLSLaVC" name="Ooni Halo Core stand mixer bread proving" alt="Ooni Halo Core stand mixer bread proving" src="https://cdn.mos.cms.futurecdn.net/ipKeRKmJPwwVkjzuLSLaVC-1920-80.png" mos="" align="middle" fullscreen="" width="2500" height="1406" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I set a timer for 10 minutes and left the dough hook and breaker bar to work the dough to form strong gluten strands. During the kneading phase I noticed how well the mixer handled the tough job; it didn't appear overworked and remained steady on my countertop, as it had done previously. </p><p>Once the kneading was complete, I removed the dough, which looked soft and smooth, knocked it back and waited for it to double in size. I then knocked it back again, shaped it into a round loaf, and placed it on a baking tray, leaving it to prove for an hour before baking. </p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/nwY3Sqe4DgyhDBCrNneZBi-1920-80.jpg" alt="Ooni Halo Core Bread" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/uMMBgCWXYaxyPUnjiocTZ3-1920-80.jpg" alt="Ooni Halo Core Sliced bread" /><figcaption><small role="credit">Future / Camilla Sharman</small></figcaption></figure></figure><p> The finished loaf had a lovely flavor with a light texture. In fact, my husband didn’t realize it was homemade, and he was even more surprised when we enjoyed it spread with homemade butter. </p><h2 id="pizza-dough">Pizza dough</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Pb6Z8X65bYx67RqUnwyrJE" name="Ooni Halo Core kneading dough" alt="Ooni Halo Core kneading dough" src="https://cdn.mos.cms.futurecdn.net/Pb6Z8X65bYx67RqUnwyrJE-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Ooni is known for its pizza ovens, so I wasn’t going to get away without making pizza dough in the Ooni Halo Core. I’d already discovered how good it is at making bread, so I expected to impress my family with homemade pizza and a perfect crust. </p><div class="youtube-video" data-nosnippet ><div class="video-aspect-box"><iframe data-lazy-priority="low" data-lazy-src="https://www.youtube-nocookie.com/embed/W0fm1bs4Xhw" allowfullscreen=""></iframe></div></div><p>I used a New York-style pizza dough recipe using 1.5 lbs (638 g) of flour, using a mix of 00 and bread flour. I set the speed to 20% and watched the ingredients come together as I slowly added the liquid. I kept the mixer on for 10 minutes, then removed it for cold proofing overnight in the fridge. </p><p>I loved watching the dough hook and breaker bar form an attractive pattern as it kneaded. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="jMJg82ZYisJEMfrgqeXZAM" name="Pizza dough proving" alt="Pizza dough proving" src="https://cdn.mos.cms.futurecdn.net/jMJg82ZYisJEMfrgqeXZAM-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>I could clearly see how the dough was developing, and then, two hours before baking, I removed it from the fridge to allow it to come back to room temperature. After that, I stretched out the dough and covered it with my favorite toppings. </p><p>I’m not the best at shaping pizza — I obviously need more practice — but the dough formed a beautiful crust. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="e4wKhqR8uUyJDw5umpNEoB" name="Ooni Halo Core spiral mixer pizza" alt="Ooni Halo Core spiral mixer pizza" src="https://cdn.mos.cms.futurecdn.net/e4wKhqR8uUyJDw5umpNEoB-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><h3 class="article-body__section" id="section-ooni-halo-core-review-verdict"><span>Ooni Halo Core review: Verdict</span></h3><p>The Ooni Halo Core spiral mixer is a real powerhouse when it comes to making dough — whether you want to make homemade pies or bake bread. The breaker bar is a real genius at double kneading and stopping the dough from climbing up the dough hook, destabilizing the mixer. Plus, it’s much more affordable than the Ooni Halo Pro and brings professional mastery into domestic kitchens.</p><p>I’m not convinced it’s as good as other stand mixers for making cake batters, particularly when dealing with butter, but if you make more dough than cakes and cookies, the Halo Core is a good choice. However, if you’re serious about sweet treats and only occasionally need extra power to knead dough, I’d stick with a KitchenAid. </p><p>There’s no doubt that it’s a premium appliance — if I had my choice I hold onto my KitchenAid Artisan Plus for cakes and use the Ooni Halo Core for breads.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Amazon is already discounting 21 best-selling kitchen appliances ahead of Prime Day — save up to 42% now ]]></title>
                                                                                                <dc:content><![CDATA[ <p><a href="https://www.tomsguide.com/sales-events/amazon-october-prime-big-deal-days-2026-best-sales-now">Prime Big Deal Days</a> kick off a week from today — but that hasn't stopped Amazon from rolling out early deals. One of the most impressive sales I've seen so far is on kitchen appliances. In fact, top brands like Ninja, Nespresso, Cuisinart and KitchenAid are slashing the prices on their best-selling appliances.</p><p>If you're in the market for a new air fryer, I highly suggest <a href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow">the Ninja Flip, which is sporting a $100 discount</a>. Need a new coffee maker? <a href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow">The Nespresso Vertuo Pop+ is down to $99</a>. Plus, <a href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow">the popular KitchenAid Deluxe 4.5 Qt. Tilt-head Stand Mixer is now $299</a>.</p><p>I've rounded up the best kitchen appliance deals from Amazon to shop ahead of October Prime Day. Plus, don't miss our <a href="https://www.tomsguide.com/coupons/amazon.com">Amazon promo codes</a> page for more ways to save.</p><h3 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h3><ul><li><a href="https://www.amazon.com/deals/?_encoding=UTF8" target="_blank" rel="nofollow"><strong>shop all Amazon kitchen appliance deals</strong></a></li><li><strong>Crock-Pot 7-Quart Slow Cooker: </strong><a href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow"><strong>was $59 now $44</strong></a></li><li><strong>Ninja Blast Max: </strong><a href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow"><strong>was $99 now $69</strong></a></li><li><strong>Keurig K-Express: </strong><a href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow"><strong>was $109 now $89</strong></a></li><li><strong>Nespresso Vertuo Pop+: </strong><a href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow"><strong>was $129 now $99</strong></a></li><li><strong>Ninja Flip Toaster Oven &amp; Air Fryer: </strong><a href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow"><strong>was $249 now $149</strong></a></li><li><strong>De'Longhi Dedica Duo Compact Espresso Machine: </strong><a href="https://www.amazon.com/DeLonghi-Dedica-Compact-Espresso-Machine/dp/B0F3RZZZF9?" target="_blank" rel="nofollow"><strong>was $299 now $199</strong></a></li><li><strong>Ninja Foodi XL Pro Air Fry Oven, 10-in-1: </strong><a href="https://www.amazon.com/Ninja-DT201-Countertop-Convection-Dehydrate/dp/B08BXX69K4" target="_blank" rel="nofollow"><strong>was $379 now $219</strong></a></li><li><strong>KitchenAid Deluxe 4.5 Qt. Tilt-head Stand Mixer: </strong><a href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow"><strong>was $399 now $299</strong></a></li><li><strong>Breville Barista Express: </strong><a href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow"><strong>was $699 now $499</strong></a></li></ul><h3 class="article-body__section" id="section-best-kitchen-appliance-deals"><span>Best Kitchen Appliance Deals</span></h3><div class="product"><a data-dimension112="e929b3a0-bc1b-11f1-8dc0-99d0b8befcda" data-action="Deal Block" data-label="7-Quart Slow Cooker" data-dimension48="7-Quart Slow Cooker" data-dimension25="$44" href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1080px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="xxEFYRjw4hJpt8rETUuaiH" name="Crock-Pot 7-Quart Slow Cooker" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xxEFYRjw4hJpt8rETUuaiH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>This 7-quart slow cooker is the perfect size to house a big batch of chili or queso to snack on all day. Or you can plan ahead and slow cook a melt-in-your-mouth roast with some carrots and potatoes for an easy dinner.<a class="view-deal button" href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow" data-dimension112="e929b3a0-bc1b-11f1-8dc0-99d0b8befcda" data-action="Deal Block" data-label="7-Quart Slow Cooker" data-dimension48="7-Quart Slow Cooker" data-dimension25="$44">View Deal</a></p></div><div class="product"><a data-dimension112="e929b468-bc1b-11f1-be26-f15d4bed2c21" data-action="Deal Block" data-label="Belgian Waffle Maker" data-dimension48="Belgian Waffle Maker" data-dimension25="$69" href="https://www.amazon.com/Ninja-BW1001-NeverStick-Precision-Pour-Chef-curated/dp/B0B358VDZJ/ref=" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1614px;"><p class="vanilla-image-block" style="padding-top:86.00%;"><img id="XofzJVhShmZ3kcVxuocQvB" name="Ninja Belgian Waffle Maker" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/XofzJVhShmZ3kcVxuocQvB-1920-80.png" mos="" align="middle" fullscreen="" width="1614" height="1388" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-BW1001-NeverStick-Precision-Pour-Chef-curated/dp/B0B358VDZJ/ref=" target="_blank" rel="nofollow" data-dimension112="e929b468-bc1b-11f1-be26-f15d4bed2c21" data-action="Deal Block" data-label="Belgian Waffle Maker" data-dimension48="Belgian Waffle Maker" data-dimension25="$69">Belgian Waffle Maker: was $99 now $69</a></strong><br />Weekend brunch just got an upgrade. This vertical waffle maker has five shade settings so everyone gets their waffle exactly how they like it, plus a specialty setting for high-sugar batters like brownies (yes, really). The precision-pour cup takes the guesswork out of measuring, and audible alerts mean no more burnt disasters. Pair it with the Ninja CREAMi for the ultimate breakfast-dessert combo. <a class="view-deal button" href="https://www.amazon.com/Ninja-BW1001-NeverStick-Precision-Pour-Chef-curated/dp/B0B358VDZJ/ref=" target="_blank" rel="nofollow" data-dimension112="e929b468-bc1b-11f1-be26-f15d4bed2c21" data-action="Deal Block" data-label="Belgian Waffle Maker" data-dimension48="Belgian Waffle Maker" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="e929b4e0-bc1b-11f1-a3c2-eb79cc7c29ee" data-action="Deal Block" data-label="Blast Max" data-dimension48="Blast Max" data-dimension25="$69" href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1216px;"><p class="vanilla-image-block" style="padding-top:123.36%;"><img id="9Q4QY399FaozAFUt4j8dTW" name="ninja-blast-max-portable-blender--twist--bb517479-54ce-4a77-974c-58e2f44dde33.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/9Q4QY399FaozAFUt4j8dTW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1216" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Ninja Blast Max is capable of taking on any challenge you throw at it, including crushing ice and blitzing berries to make yummy smoothies. It comes with multiple blend settings to make sure your blender is using the right level of power for the task at hand, and the compact size means it’s a great option for anyone with a small kitchen. <a class="view-deal button" href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow" data-dimension112="e929b4e0-bc1b-11f1-a3c2-eb79cc7c29ee" data-action="Deal Block" data-label="Blast Max" data-dimension48="Blast Max" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="e929b558-bc1b-11f1-a8b5-699d5ea2aeee" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$69" href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="EBqQHURi67ApM2ai2joGg6" name="_0007_CHEFMAN Multifunctional Digital Air Fryer+" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/EBqQHURi67ApM2ai2joGg6-1920-80.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow" data-dimension112="e929b558-bc1b-11f1-a8b5-699d5ea2aeee" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$69">Multifunctional Digital Air Fryer: was $139 now $69</a></strong><br />An extra large digital air fryer, this CHEFMAN model has 17 presets and an easy-to-use touch screen so you can get cooking immediately. It's big enough for family-sized meals, party-sized appetizers and has a window so you can check your cooking without opening it.<a class="view-deal button" href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow" data-dimension112="e929b558-bc1b-11f1-a8b5-699d5ea2aeee" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="e929b922-bc1b-11f1-ae2b-a1cc01080fde" data-action="Deal Block" data-label="Cordless Citrus Juicer" data-dimension48="Cordless Citrus Juicer" data-dimension25="$79" href="https://www.amazon.com/KitchenAid-Cordless-Citrus-Juicer-separately/dp/B0DN6RX5Q3" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:964px;"><p class="vanilla-image-block" style="padding-top:155.60%;"><img id="HmFhrr2KfXYEaCMCSBwkhL" name="KitchenAid Go Cordless Citrus Juicer" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HmFhrr2KfXYEaCMCSBwkhL-1920-80.jpg" mos="" align="middle" fullscreen="" width="964" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The KitchenAid Go Cordless Citrus Juicer makes it so simple to have fresh juice every morning with minimal mess. If you hate pulp in your juice, this won’t be for you. But if you’re looking for the fastest way to juice your citrus, this is the answer. It’s simple to clean too, since the top half of the appliance is dishwasher-friendly.<a class="view-deal button" href="https://www.amazon.com/KitchenAid-Cordless-Citrus-Juicer-separately/dp/B0DN6RX5Q3" target="_blank" rel="nofollow" data-dimension112="e929b922-bc1b-11f1-ae2b-a1cc01080fde" data-action="Deal Block" data-label="Cordless Citrus Juicer" data-dimension48="Cordless Citrus Juicer" data-dimension25="$79">View Deal</a></p></div><div class="product"><a data-dimension112="e929b9fe-bc1b-11f1-8f7d-850dc322ec45" data-action="Deal Block" data-label="Air Fryer" data-dimension48="Air Fryer" data-dimension25="$79" href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B07FDJMC9Q" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1168px;"><p class="vanilla-image-block" style="padding-top:128.42%;"><img id="ThfSLcj6qWSrgjihSvk2mW" name="Ninja Air Fryer 4QT.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ThfSLcj6qWSrgjihSvk2mW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1168" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>One of Ninja's first air fryers to hit the market, the AF101 does offer one slight advantage over the Pro. Its compact design makes it ideal for small kitchens, and it does still offer an impressive 05°F-400°F temperature range. <a class="view-deal button" href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B07FDJMC9Q" target="_blank" rel="nofollow" data-dimension112="e929b9fe-bc1b-11f1-8f7d-850dc322ec45" data-action="Deal Block" data-label="Air Fryer" data-dimension48="Air Fryer" data-dimension25="$79">View Deal</a></p></div><div class="product"><a data-dimension112="e929ba9e-bc1b-11f1-96e1-13218027a7b8" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$89" href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:230.93%;"><img id="SNGj6WoG25u9rj7PA3Zhre" name="Keurig K Express" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SNGj6WoG25u9rj7PA3Zhre-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="1568" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow" data-dimension112="e929ba9e-bc1b-11f1-96e1-13218027a7b8" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$89">K-Express: was $109 now $89</a></strong><br />The Keurig Express offers three cup sizes — 8, 10 and 12 oz and has a 42 oz detachable water reservoir, making it easy to remove, fill or clean. By removing the drip tray you can position a travel mug up to 7.4 inches tall under the brew stream. <a class="view-deal button" href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow" data-dimension112="e929ba9e-bc1b-11f1-96e1-13218027a7b8" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="e929bb16-bc1b-11f1-ae27-39b1205ed715" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99" href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:99.56%;"><img id="4uiaRXRKY8Go6F4ZpM7UdA" name="Ninja coffee" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4uiaRXRKY8Go6F4ZpM7UdA-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="676" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow" data-dimension112="e929bb16-bc1b-11f1-ae27-39b1205ed715" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99">Single Serve Coffee Maker with Pods and Grounds: was $129 now $99</a></strong><br />This stylish Ninja coffee maker comes in a gorgeous choice of colorways, including Sage Green, and is now on sale for $30 off. Whether you prefer pods or grounds, this device makes tasty brews in 7 sizes (6-oz. to 24-oz) and has a built-in, fold-away milk frother! The only problem you'll have is deciding which color to choose.<a class="view-deal button" href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow" data-dimension112="e929bb16-bc1b-11f1-ae27-39b1205ed715" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="e929bbd4-bc1b-11f1-b842-c5cdc0bf1866" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89" href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:717px;"><p class="vanilla-image-block" style="padding-top:163.18%;"><img id="LpQPvQCcU8GNALWdf2GLs4" name="51EcND+lspL._AC_SL1173_.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/LpQPvQCcU8GNALWdf2GLs4-1920-80.jpg" mos="" align="middle" fullscreen="" width="717" height="1170" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow" data-dimension112="e929bbd4-bc1b-11f1-b842-c5cdc0bf1866" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89">PerfecTemp Cordless Electric Kettle: was $129 now $89</a></strong><br />This sleek electric Kettle heats and boils your brews quickly. With six preset heating profiles to choose from, it can extract the most flavor out of your tea or morning coffee. We rank it as one of the <a href="https://www.tomsguide.com/best-picks/the-best-electric-kettles">best electric kettles</a>.<a class="view-deal button" href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow" data-dimension112="e929bbd4-bc1b-11f1-b842-c5cdc0bf1866" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="e929bc4c-bc1b-11f1-b82e-c10ff6c95471" data-action="Deal Block" data-label="Vertuo Pop+" data-dimension48="Vertuo Pop+" data-dimension25="$99" href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:82.73%;"><img id="fGSRj3582aRZDhrdn6pES5" name="Nespresso Vertuo Pop Plus Deluxe Coffee.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fGSRj3582aRZDhrdn6pES5-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1241" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow" data-dimension112="e929bc4c-bc1b-11f1-b82e-c10ff6c95471" data-action="Deal Block" data-label="Vertuo Pop+" data-dimension48="Vertuo Pop+" data-dimension25="$99">Vertuo Pop+: was $129 now $99</a></strong><br />The least-expensive machine in Amazon's sale is the Nespresso Vertuo Pop Plus Deluxe. In our <a href="https://www.tomsguide.com/opinion/nespressos-latest-pod-coffee-machine-was-my-wake-up-call-to-what-a-cuppa-can-be">Nespresso Vertuo Pop hands-on</a>, we said it's anything but entry level where performance is concerned. We like that it has an Expert Mode, which lets you customize your coffee, unveiling a plethora of new options in the process.<a class="view-deal button" href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow" data-dimension112="e929bc4c-bc1b-11f1-b82e-c10ff6c95471" data-action="Deal Block" data-label="Vertuo Pop+" data-dimension48="Vertuo Pop+" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="e929bcba-bc1b-11f1-8942-659219a59ca3" data-action="Deal Block" data-label="9 Cup Food Processor" data-dimension48="9 Cup Food Processor" data-dimension25="$99" href="https://www.amazon.com/KitchenAid-Cup-Food-Processor-KFP0921/dp/B09HSQ3TJG?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1530px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="VcxkbkauHkBKauGGNEYzun" name="KitchenAid 9 Cup Food Processor" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/VcxkbkauHkBKauGGNEYzun-1920-80.jpg" mos="" align="middle" fullscreen="" width="1530" height="1530" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/KitchenAid-Cup-Food-Processor-KFP0921/dp/B09HSQ3TJG?" target="_blank" rel="nofollow" data-dimension112="e929bcba-bc1b-11f1-8942-659219a59ca3" data-action="Deal Block" data-label="9 Cup Food Processor" data-dimension48="9 Cup Food Processor" data-dimension25="$99">9 Cup Food Processor: was $159 now $99</a></strong><br />This multi-functional power machine can chop, shred, mince, slice, knead, whip, mix and puree. And it can handle anything from meats and cheeses to vegetables and doughs. What's more, it's fast and can mince 1lb of chicken or beef in 10 seconds. It comes with a 9-cup bowl and lid, a multi-purpose four-blade, a reversible slicing and shredding disc, a whisk accessory, a refrigerator lid, and a dough blade.<a class="view-deal button" href="https://www.amazon.com/KitchenAid-Cup-Food-Processor-KFP0921/dp/B09HSQ3TJG?" target="_blank" rel="nofollow" data-dimension112="e929bcba-bc1b-11f1-8942-659219a59ca3" data-action="Deal Block" data-label="9 Cup Food Processor" data-dimension48="9 Cup Food Processor" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="e929bd50-bc1b-11f1-9332-9d0c2595c28d" data-action="Deal Block" data-label="NeverClog Cold Press Juicer" data-dimension48="NeverClog Cold Press Juicer" data-dimension25="$124" href="https://www.amazon.com/dp/B0DPXMTZ16?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1499px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="2WLwjdnMeBZu5mrkYrS2jH" name="Ninja NeverClog Cold Press Juicer" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/2WLwjdnMeBZu5mrkYrS2jH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1499" height="1499" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>Ninja's NeverClog Cold Press Juicer removes the hassle of juicing fruits and vegetables. The special filter pushes pulp through without clogging and lets you customize the amount of pulp in your juice with two interchangeable pulp filters. It comes with a 24-oz juice jug and a 36-oz pulp container, allowing you to make large batches of juice, rather than single servings.<a class="view-deal button" href="https://www.amazon.com/dp/B0DPXMTZ16?" target="_blank" rel="nofollow" data-dimension112="e929bd50-bc1b-11f1-9332-9d0c2595c28d" data-action="Deal Block" data-label="NeverClog Cold Press Juicer" data-dimension48="NeverClog Cold Press Juicer" data-dimension25="$124">View Deal</a></p></div><div class="product"><a data-dimension112="e929bdc8-bc1b-11f1-a926-6380885dbfa3" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149" href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1676px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="sWibiMn9jcqpLxyQRazy6f" name="Ninja Amazon 2.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/sWibiMn9jcqpLxyQRazy6f-1920-80.jpg" mos="" align="middle" fullscreen="" width="1676" height="1676" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow" data-dimension112="e929bdc8-bc1b-11f1-a926-6380885dbfa3" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149">Mega Kitchen System: was $219 now $149</a></strong><br />Leave all the multi-tasking in the kitchen to one appliance with this Ninja blender. With four functions for smoothies, processing, dough, drinks and more it will quickly become your go-to kitchen appliance. With this ultimate appliance, you’ll be enjoying fresh, healthy drinks, homemade bread and sweet bakes.<a class="view-deal button" href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow" data-dimension112="e929bdc8-bc1b-11f1-a926-6380885dbfa3" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149">View Deal</a></p></div><div class="product"><a data-dimension112="e929be36-bc1b-11f1-9f9d-e75833f64930" data-action="Deal Block" data-label="Flip Toaster Oven &amp; Air Fryer" data-dimension48="Flip Toaster Oven &amp; Air Fryer" data-dimension25="$149" href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:600px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="qey9zt42Hnq8ePgcaiiaR7" name="Ninja Flip" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/qey9zt42Hnq8ePgcaiiaR7-1920-80.jpg" mos="" align="middle" fullscreen="" width="600" height="600" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow" data-dimension112="e929be36-bc1b-11f1-9f9d-e75833f64930" data-action="Deal Block" data-label="Flip Toaster Oven &amp; Air Fryer" data-dimension48="Flip Toaster Oven &amp; Air Fryer" data-dimension25="$149">Flip Toaster Oven &amp; Air Fryer: was $249 now $149</a></strong><br />I've been using the Ninja Flip for over a year now and I can tell you that it is a total cooking game changer. It has 8 functions in one convenient and versatile machine: air fry, roast, bake, toast, and more. I've been able to use it for pretty much everything including toasting toast, baking chicken, roasting vegetable and more. One of my favorite things about it is the fact that when you're not using it, you can flip it up and away, which will give you 50% more counter space back.<a class="view-deal button" href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow" data-dimension112="e929be36-bc1b-11f1-9f9d-e75833f64930" data-action="Deal Block" data-label="Flip Toaster Oven &amp; Air Fryer" data-dimension48="Flip Toaster Oven &amp; Air Fryer" data-dimension25="$149">View Deal</a></p></div><div class="product"><a data-dimension112="e929beae-bc1b-11f1-b9e4-01175df1d823" data-action="Deal Block" data-label="Dedica Duo Compact Espresso Machine" data-dimension48="Dedica Duo Compact Espresso Machine" data-dimension25="$199" href="https://www.amazon.com/DeLonghi-Dedica-Compact-Espresso-Machine/dp/B0F3RZZZF9?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1080px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="ES3eY7aJDiE5T5dxnQUmA9" name="delonghi_dedica_duo_vanilla_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ES3eY7aJDiE5T5dxnQUmA9-1920-80.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/DeLonghi-Dedica-Compact-Espresso-Machine/dp/B0F3RZZZF9?" target="_blank" rel="nofollow" data-dimension112="e929beae-bc1b-11f1-b9e4-01175df1d823" data-action="Deal Block" data-label="Dedica Duo Compact Espresso Machine" data-dimension48="Dedica Duo Compact Espresso Machine" data-dimension25="$199">Dedica Duo Compact Espresso Machine: was $299 now $199</a></strong><br />The De’Longhi Dedica Duo is a dual-brew espresso machine that measures just 5.9 inches wide, so it won’t take up too much room on your countertop, making it perfect for smaller living quarters. There are three preset recipes, a professional pump, a digital touch display, and a commercial-style steam wand. It's so easy to use that anyone can make a perfect coffee with it.<a class="view-deal button" href="https://www.amazon.com/DeLonghi-Dedica-Compact-Espresso-Machine/dp/B0F3RZZZF9?" target="_blank" rel="nofollow" data-dimension112="e929beae-bc1b-11f1-b9e4-01175df1d823" data-action="Deal Block" data-label="Dedica Duo Compact Espresso Machine" data-dimension48="Dedica Duo Compact Espresso Machine" data-dimension25="$199">View Deal</a></p></div><div class="product"><a data-dimension112="e929bf1c-bc1b-11f1-b254-2faccc4cdda6" data-action="Deal Block" data-label="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension48="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension25="$219" href="https://www.amazon.com/Ninja-DT201-Countertop-Convection-Dehydrate/dp/B08BXX69K4" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:75.80%;"><img id="sFc44K8P9eTgsrZ4Kc25oB" name="Foodi XL Pro Air Fry Oven, 10-in-1" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/sFc44K8P9eTgsrZ4Kc25oB-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1137" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-DT201-Countertop-Convection-Dehydrate/dp/B08BXX69K4" target="_blank" rel="nofollow" data-dimension112="e929bf1c-bc1b-11f1-b254-2faccc4cdda6" data-action="Deal Block" data-label="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension48="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension25="$219">Foodi XL Pro Air Fry Oven, 10-in-1: was $379 now $219</a></strong><br />42% off is one of the biggest Ninja discounts you'll find right now. While this XL air fryer/oven takes up a lot of space, it offers plenty of cooking functions and perfect cooking results every time. <a class="view-deal button" href="https://www.amazon.com/Ninja-DT201-Countertop-Convection-Dehydrate/dp/B08BXX69K4" target="_blank" rel="nofollow" data-dimension112="e929bf1c-bc1b-11f1-b254-2faccc4cdda6" data-action="Deal Block" data-label="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension48="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension25="$219">View Deal</a></p></div><div class="product"><a data-dimension112="e929bf8a-bc1b-11f1-aa9b-f505d7dc4f4b" data-action="Deal Block" data-label="Crispi Pro" data-dimension48="Crispi Pro" data-dimension25="$249" href="https://www.amazon.com/Ninja-Crispi-Glass-Amethyst-AS101PU1/dp/B0GRJNMHBQ/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:96.00%;"><img id="CHukmWdqjDdNFwby3iRufB" name="Ninja Crispi Pro" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CHukmWdqjDdNFwby3iRufB-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1440" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-Crispi-Glass-Amethyst-AS101PU1/dp/B0GRJNMHBQ/" target="_blank" rel="nofollow" data-dimension112="e929bf8a-bc1b-11f1-aa9b-f505d7dc4f4b" data-action="Deal Block" data-label="Crispi Pro" data-dimension48="Crispi Pro" data-dimension25="$249">Crispi Pro: was $299 now $249</a></strong><br />Taking a step above the original <a href="https://www.tomsguide.com/home/air-fryers/ninja-crispi-air-fryer-review">Ninja Crispi</a>, the Pro offers 6 different functions, like Recrisp, Air Fry and Roast, and comes with three larger glass containers, making it the perfect size for families or meal prep. It comes with an interchangeable stand which allows you to fit everything from 2.5 quart to 10 quart containers to the cooking lid. Now discounted by $50 for Prime Day, this is a certified steal. <a class="view-deal button" href="https://www.amazon.com/Ninja-Crispi-Glass-Amethyst-AS101PU1/dp/B0GRJNMHBQ/" target="_blank" rel="nofollow" data-dimension112="e929bf8a-bc1b-11f1-aa9b-f505d7dc4f4b" data-action="Deal Block" data-label="Crispi Pro" data-dimension48="Crispi Pro" data-dimension25="$249">View Deal</a></p></div><div class="product"><a data-dimension112="e929c002-bc1b-11f1-a3a7-835bc2c2b276" data-action="Deal Block" data-label="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension48="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension25="$299" href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:97.94%;"><img id="82mWMKNvrtU6QZZpBYPy7m" name="KitchenAid Artisan Rose.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/82mWMKNvrtU6QZZpBYPy7m-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="665" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow" data-dimension112="e929c002-bc1b-11f1-a3a7-835bc2c2b276" data-action="Deal Block" data-label="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension48="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension25="$299">Deluxe 4.5 Qt. Tilt-head Stand Mixer: was $399 now $299</a></strong><br />If you want a stylish, tilt-head stand mixer to suit your kitchen, this is an excellent deal. With a 4.5 quart capacity, it's large enough to bake up to 8 dozen cookies in a single batch. A powerful mixer, it has 10 speeds to quickly whisk, mix, beat and whip up a storm. It also comes with silver coated flat beater, dough hook and 6-wire metal whip. Get baking with this great deal. <a class="view-deal button" href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow" data-dimension112="e929c002-bc1b-11f1-a3a7-835bc2c2b276" data-action="Deal Block" data-label="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension48="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension25="$299">View Deal</a></p></div><div class="product"><a data-dimension112="e929c070-bc1b-11f1-9314-c1284d328104" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379" href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:91.20%;"><img id="HPfDur99xHfhfWNbGej8ZE" name="KitchenAid Artisan Mixer.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HPfDur99xHfhfWNbGej8ZE-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1368" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow" data-dimension112="e929c070-bc1b-11f1-9314-c1284d328104" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379">Artisan Series 5 Quart: was $499 now $379</a></strong><br />A Tom's Guide favorite, in our <a href="https://www.tomsguide.com/opinion/the-kitchenaid-artisan-stand-mixer-is-my-best-kitchen-purchase-ever-heres-why">KitchenAid Artisan 5-Quart stand mixer review</a>, we dubbed it the "best kitchen purchase" you can ever make. It beats, whisks, and kneads at 10 different speeds, so you don't have to, reducing recipe times. The bowl is big enough to support 9 dozen cookies or 4 loaves of bread at a time. This machine also boasts a 59-point planetary mixing action — fancy words that translate into incredibly mixed ingredients. Plus, it ships with a flat beater, coated dough hook, 6-wire whip, and 1-piece pouring shield. <a class="view-deal button" href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow" data-dimension112="e929c070-bc1b-11f1-9314-c1284d328104" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379">View Deal</a></p></div><div class="product"><a data-dimension112="e929c0de-bc1b-11f1-9fdb-9fa7bc2f467a" data-action="Deal Block" data-label="Luxe Café" data-dimension48="Luxe Café" data-dimension25="$499" href="https://www.amazon.com/Ninja-Integrated-Hands-Free-Cappuccinos-ES601/dp/B0D45PK5V4/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:541px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="HcnQ36qmUJg5VJidxsJ76X" name="Ninja Luxe Cafe.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HcnQ36qmUJg5VJidxsJ76X-1920-80.jpg" mos="" align="middle" fullscreen="" width="541" height="541" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-Integrated-Hands-Free-Cappuccinos-ES601/dp/B0D45PK5V4/" target="_blank" rel="nofollow" data-dimension112="e929c0de-bc1b-11f1-9fdb-9fa7bc2f467a" data-action="Deal Block" data-label="Luxe Café" data-dimension48="Luxe Café" data-dimension25="$499">Luxe Café: was $599 now $499</a></strong><br />This deal gets you a 3-in-1 machine that makes espresso, drip coffee and rapid cold brew. It also has Barista Assist technology, an integrated grinder and weight-based dosing, plus hands-free frothing. <a class="view-deal button" href="https://www.amazon.com/Ninja-Integrated-Hands-Free-Cappuccinos-ES601/dp/B0D45PK5V4/" target="_blank" rel="nofollow" data-dimension112="e929c0de-bc1b-11f1-9fdb-9fa7bc2f467a" data-action="Deal Block" data-label="Luxe Café" data-dimension48="Luxe Café" data-dimension25="$499">View Deal</a></p></div><div class="product"><a data-dimension112="e929c156-bc1b-11f1-8fd7-0d1f657d5713" data-action="Deal Block" data-label="Barista Express" data-dimension48="Barista Express" data-dimension25="$499" href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1306px;"><p class="vanilla-image-block" style="padding-top:114.85%;"><img id="xqb7yApNa26xAkZLUbt3tW" name="breville barista express.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xqb7yApNa26xAkZLUbt3tW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1306" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Breville Barista Express is one of the most iconic and respected bean-to-cup espresso machines ever made. Although it's been out for around 6 years at this point, the Barista Express shows no signs of slowing down. Right now it's just $499, which is the same price as Breville's compact Bambino Plus. You basically get a free grinder.<a class="view-deal button" href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow" data-dimension112="e929c156-bc1b-11f1-8fd7-0d1f657d5713" data-action="Deal Block" data-label="Barista Express" data-dimension48="Barista Express" data-dimension25="$499">View Deal</a></p></div><h3 class="article-body__section" id="section-shop-more-deals"><span>Shop more deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=Everything&amp;retailer=Amazon&amp;rows=8&amp;view_mode=savings_squad&amp;widget_title=Top+Amazon+Deals+Handpicked+by+Our+Editors&amp;widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&amp;bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function getTimeAgo(dateString) {        if (!dateString) return '';        const date = new Date(dateString);        const now = new Date();        const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);        if (diffInSeconds < 60) return 'Just now';        const diffInMinutes = Math.floor(diffInSeconds / 60);        if (diffInMinutes < 60) return `${diffInMinutes} min${diffInMinutes > 1 ? 's' : ''} ago`;        const diffInHours = Math.floor(diffInMinutes / 60);        if (diffInHours < 24) return `${diffInHours} hr${diffInHours > 1 ? 's' : ''} ago`;        const diffInDays = Math.floor(diffInHours / 24);        if (diffInDays < 30) return `${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`;        const diffInMonths = Math.floor(diffInDays / 30);        if (diffInMonths < 12) return `${diffInMonths} mo${diffInMonths > 1 ? 's' : ''} ago`;        const diffInYears = Math.floor(diffInDays / 365);        return `${diffInYears} yr${diffInYears > 1 ? 's' : ''} ago`;      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;      position: relative;      z-index: 20;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      margin: 0 auto;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {      display: grid;      width: 100%;      grid-template-columns: repeat(4, 1fr);      gap: 12px;      margin: 0 auto;      max-width: 800px;    }                 .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;      width: 100%;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      width: 100%;      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }    @container tg-df (max-width: 768px) {      .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {        width: 100%;        margin: 0;        margin-bottom: -320px;        padding: 0 16px 320px 16px;        display: flex;        flex-wrap: nowrap;        gap: 8px;        overflow-x: auto;        overflow-y: hidden;        pointer-events: none;        scrollbar-width: none;        -webkit-overflow-scrolling: touch;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }      .tg-df-sort-wrapper {        pointer-events: auto;        flex: 0 0 auto;        width: 175px;        min-width: 175px;      }    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 120px;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 16px 16px 8px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }                  .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;        width: auto;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;      width: 100vw;      max-width: 1200px;      position: relative;      left: 50%;      transform: translateX(-50%);    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 14px;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    .tg-df-grid-wrapper { position: relative; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn {      display: inline-flex;      align-items: center;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.40);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #1f69ff; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #0056e0; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }    .tg-df-savings-squad-header { margin-bottom: 24px; text-align: center; display: none; }    .tg-df-banner-img-desktop { display: block; width: 100%; height: auto; margin-bottom: 32px; }    .tg-df-banner-img-mobile { display: none; width: 100%; height: auto; margin-bottom: 32px; }    @container tg-df (max-width: 600px) {      .tg-df-banner-img-desktop { display: none; }      .tg-df-banner-img-mobile { display: block; }    }    .tg-df-header-title { font-size: 28px; font-weight: 700; color: var(--tg-df-text); margin: 32px 0 12px 0; line-height: 1.3; }    .tg-df-header-subtitle { font-size: 16px; color: var(--tg-df-text-muted); margin: 0 0 32px 0; line-height: 1.5; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3Cdiv class="tg-df-savings-squad-header" id="tg-df-savings-squad-header">      \x3Cpicture>        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/xkh2og7m3d1778189998.png" alt="Deals Banner" class="tg-df-banner-img-desktop" />        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/gmak6rtdf41778245089.png" alt="Deals Banner Mobile" class="tg-df-banner-img-mobile" />      \x3C/picture>      \x3Cdiv class="tg-df-header-text">        \x3Ch2 class="tg-df-header-title" id="tg-df-header-title">Editor's Choice Deals\x3C/h2>        \x3Cp class="tg-df-header-subtitle" id="tg-df-header-subtitle">Discover the best discounts currently available, curated daily by the Tom's Guide Savings Squad.\x3C/p>      \x3C/div>    \x3C/div>    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Televisions" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/wcMxTsHgqu3roMbAx7RLnT-132-100.png" alt="TVs" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">TVs\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Phones" data-pr="over50">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/G3KGaRGzj24F6PUsw4bWpT-132-100.png" alt="Phones" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Phones\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Computing" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/znNvsLzx8NEgNkD9HSFSnT-132-100.png" alt="Computing" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Computing\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Gaming" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/Pgew8yaRQeZFHqHjTzvBnT-132-100.png" alt="Gaming" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Gaming\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Mattresses" data-pr="over500">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/cW7xsaLyesxkHFVSiC4kmT-132-100.png" alt="Mattresses" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Mattresses\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Audio" data-pr="over30">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/pCvBVHuhaQVjKt3VgCjbqT-132-100.png" alt="Audio" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Audio\x3C/span>            \x3C/div>                  \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E      \x3Cdiv class="tg-df-top-bar" id="tg-df-top-bar" style="position: relative; z-index: 100; margin: 0 auto 20px;">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>      \x3C/div>    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">              \x3Cdiv class="tg-df-filters-container" style="position: relative; width: 100%; max-width: 800px; margin: 0 auto;">          \x3Cbutton class="tg-df-scroll-btn left" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: -200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M15 18l-6-6 6-6"/>\x3C/svg>          \x3C/button>          \x3Cbutton class="tg-df-scroll-btn right" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: 200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M9 18l6-6-6-6"/>\x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-filters">          \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>          \x3C/div>        \x3C/div>        \x3C/div>      \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();        }        getViewMode() {          console.log("DEBUG getViewMode -> override:", this.viewModeOverride, "editorMode:", this.editorMode);          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          console.log("[DEBUG] applyLayoutMode CALLED! mode=", mode);          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          const showHeaderDetails = params.get('show_header_details') !== 'false';          const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          const topBarDiv = this.root.querySelector('#tg-df-top-bar');          const headerElement = this.root.querySelector('#tg-df-savings-squad-header');          if (headerElement) {             headerElement.style.display = (mode === 'savings_squad' && showHeaderDetails) ? 'block' : 'none';          }          if (mode === 'carousel') {             this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (topBarDiv) topBarDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.add('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (topBarDiv) topBarDiv.style.display = 'block';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!this.viewModeOverride && initialViewMode) {            this.viewModeOverride = initialViewMode;          }          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Gaming laptops';          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button, .tg-df-container .tg-df-card-cta { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover, .tg-df-container .tg-df-card-cta:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (this.viewModeSelect && params.has('view_mode')) {            this.viewModeSelect.value = params.get('view_mode');          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'date_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }          const headerTitleEl = this.root.querySelector('#tg-df-header-title');          const headerSubtitleEl = this.root.querySelector('#tg-df-header-subtitle');          if (params.has('widget_title') && headerTitleEl) {             headerTitleEl.textContent = params.get('widget_title');          }          if (params.has('widget_subtitle') && headerSubtitleEl) {             headerSubtitleEl.textContent = params.get('widget_subtitle');          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            if (this.getViewMode() === 'savings_squad') {              this.searchInput.value = '';            } else {              this.searchInput.value = this.currentQuery;            }          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'date_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const handleFiltersScroll = () => {            const filters = this.root.querySelector('.tg-df-filters');            const leftBtn = this.root.querySelector('.tg-df-scroll-btn.left');            const rightBtn = this.root.querySelector('.tg-df-scroll-btn.right');            if (filters && leftBtn && rightBtn) {              const { scrollLeft, scrollWidth, clientWidth } = filters;              leftBtn.style.display = scrollLeft > 0 ? 'flex' : 'none';              rightBtn.style.display = Math.ceil(scrollLeft + clientWidth) < scrollWidth - 5 ? 'flex' : 'none';            }          };          const filters = this.root.querySelector('.tg-df-filters');          if (filters) {            filters.addEventListener('scroll', handleFiltersScroll);            window.addEventListener('resize', handleFiltersScroll);            setTimeout(handleFiltersScroll, 100);                        // Also call after rendering dropdowns            const origRenderCategories = this.renderCategories;            if (origRenderCategories) {               this.renderCategories = (...args) => {                 origRenderCategories.apply(this, args);                 setTimeout(handleFiltersScroll, 50);               };            }          }                const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          const showAutocomplete = () => {             if (this.getViewMode() !== 'savings_squad' || !this.autocompleteDropdown || !this.airedaleTags) return;                          let terms = this.airedaleTags;             if (this.airedaleBrands) {                terms = terms.concat(this.airedaleBrands.map(b => b.formatted_value));             }             terms = [...new Set(terms)];                          const query = this.searchInput.value.trim();             let matches = [];             if (query.length > 0) {                 matches = terms.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase());             } else {                 matches = terms;             }                          if (matches.length > 0) {                 this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                 this.autocompleteDropdown.classList.add('active');             } else {                 this.autocompleteDropdown.classList.remove('active');             }          };          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('focus', showAutocomplete);            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              showAutocomplete();              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  if (this.getViewMode() === 'savings_squad') {                    this.activeDealTag = null;                    this.currentQuery = '';                    if (this.categoryFilter) this.categoryFilter.value = 'all';                    this.fetchDeals('');                  } else {                    this.deals = [];                    this.render();                  }                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                                let isTag = false;                if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;                if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;                this.activeDealTag = isTag ? query : null;                                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   if (query.length === 0 && this.getViewMode() === 'savings_squad') {                       if (this.categoryFilter) this.categoryFilter.value = 'all';                   }                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   if (this.categoryFilter && this.airedaleTags.includes(tag)) {                       this.categoryFilter.value = tag;                   }                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                            let isTag = false;              if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;              if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;              this.activeDealTag = isTag ? query : null;                            this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 if (query.length === 0 && this.getViewMode() === 'savings_squad') {                     if (this.categoryFilter) this.categoryFilter.value = 'all';                 }                 this.fetchDeals(query);              }            });          }          if(this.sortSelect && this.sortSelect.querySelector('option[value="date_desc"]') === null) {              const option = document.createElement('option');              option.value = "date_desc";              option.text = "Newest First";              this.sortSelect.insertBefore(option, this.sortSelect.firstChild);          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               if (val) {                 this.currentQuery = val;               } else {                 if (this.searchInput && this.currentQuery === document.querySelector('#tg-df-brand-trigger')?.getAttribute('data-active-brand')) {                     // don't clear current query if a brand is selected                 } else if (this.searchInput) {                     this.currentQuery = '';                     this.searchInput.value = '';                 }               }               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = 'date_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const finalHref = cardLink.href || cardLink.getAttribute('href') || '';                let actualRevenueId = cardLink.getAttribute('data-revenue-id');                const revMatch = finalHref.match(/(?:subId1|xcust|clickref|ascsubtag)=[^&]*?(\d{18,20})(?:&|$)/i);                if (revMatch && revMatch[1]) {                  actualRevenueId = revMatch[1];                }                const rewrittenLink = finalHref;                const revenueId = actualRevenueId;                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getRowsLimit() {          if (this.rowsSelect && this.rowsSelect.value) return parseInt(this.rowsSelect.value, 10);          let configSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {             configSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {             configSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(configSource);          if (params.has('rows')) return parseInt(params.get('rows'), 10) || 12;          return 12;        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }        async fetchDeals(query) {          this.showLoading();          this.deals = [];          this.displayLimit = this.getRowsLimit();                    try {            console.log("getViewMode returns:", this.getViewMode());            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad();            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query);               } else {                 await this.fetchHawkDeals(query);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const siteParam = this.website || 'tomsguide';            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=${siteParam}&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (!this.activeDealTag && this.currentQuery) {             const tagMatch = this.airedaleTags.find(t => t.toLowerCase() === this.currentQuery.toLowerCase());             if (tagMatch) {                this.activeDealTag = tagMatch;             }          }          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const siteParam = this.website || 'tomsguide';             const url = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let seenUrls = new Set();                    let overallBrandsCounts = {};                    // First pass: extract ALL brands from topArticles so the dropdown has all options          topArticles.forEach((article) => {             if (!article.articlepage) return;             let pageData = [];             try { pageData = JSON.parse(article.articlepage[0]); } catch(e){ console.warn(e); }             const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');             savingsSquad.forEach((block) => {                const data = block.data || {};                if (data.brand) {                   const cleanBrand = data.brand.replace(/^\d+\.\s*/, '').trim();                   overallBrandsCounts[cleanBrand] = (overallBrandsCounts[cleanBrand] || 0) + 1;                }             });          });          targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = this.decodeHTML(description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim());                summaryTitle = this.decodeHTML(summaryTitle);                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                if (externalUrl) {                   if (seenUrls.has(externalUrl)) return;                  seenUrls.add(externalUrl);                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || '',                   authorName: article.articleauthortext ? article.articleauthortext[0] : (article.articleauthor ? article.articleauthor[0] : ''),                   authorRole: article.articleauthorrole ? article.articleauthorrole[0] : '',                   authorImage: article.articleauthormedia ? article.articleauthormedia[0] : '',                   documentUrl: article.documenturl ? article.documenturl[0] : '',                   modifiedDate: article.contentmodifieddate || article.modifieddate || ''                });             });          });                    const airedaleBrandsList = Object.keys(overallBrandsCounts).map(b => ({              formatted_value: b,              count: overallBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    url.searchParams.append('rows', this.getRowsLimit().toString());          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = this.getRowsLimit();          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: this.decodeHTML(item.name || item.title || item.model_name || item.product_name || 'Unknown Product'),            brand: this.decodeHTML(item.brand || ''),            productName: this.decodeHTML(item.model_name || item.product_name || item.name || ''),            merchant: this.decodeHTML(item.merchant_name || item.merchant || item.retailer || 'Retailer'),            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : 'date_desc';          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                ${_div}              ${_div}              \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin:0; border-radius:0;">${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const finalHref = btn.href || btn.getAttribute('href') || '';                let actualRevenueId = btn.getAttribute('data-revenue-id');                const revMatch = finalHref.match(/(?:subId1|xcust|clickref|ascsubtag)=[^&]*?(\d{18,20})(?:&|$)/i);                if (revMatch && revMatch[1]) {                  actualRevenueId = revMatch[1];                }                const rewrittenLink = finalHref;                const revenueId = actualRevenueId;                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)}${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = 'View Deal';              if (isSavingsSquadMode) {                priceGroupHtml = ``;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = isSavingsSquadMode ? `` : `                \x3Cdiv class="tg-df-card-price-group">                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                          \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                          \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                            var c = this.parentNode;                            if (this.dataset.expanded === 'true') {                              var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                              if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                              pd.style.display = '-webkit-box';                              pd.style.webkitLineClamp = '3';                              this.textContent = 'READ MORE';                              this.style.position = 'absolute';                              this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                              this.style.paddingLeft = '16px';                              this.dataset.expanded = 'false';                            } else {                              var pd = this.previousElementSibling;                              pd.style.display = 'inline';                              pd.style.webkitLineClamp = 'unset';                              this.textContent = 'READ LESS';                              this.style.position = 'static';                              this.style.background = 'transparent';                              this.style.paddingLeft = '4px';                              this.dataset.expanded = 'true';                              pd.appendChild(this);                            }                          ">READ MORE${_button}                        \x3C/div>` : ''}                      ${_div}                    ${_div}                    ${deal.authorName ? `                      \x3Cdiv class="tg-df-author-line-mobile" style="padding: 0 0 12px 0; background: transparent;">                         \x3Cdiv style="display: flex; align-items: center; gap: 12px;">                            ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="40" height="40" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 40px; min-height: 40px;">` : ''}                            \x3Cdiv style="display: flex; flex-direction: column;">                               \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">\x3Cspan style="color: #FF6600;">${this.escapeHTML(deal.merchant)}${_span} deal recommended by:${_div}                               \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.3;">                                  \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                  ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                  ${deal.modifiedDate ? `\x3Cdiv style="color: var(--tg-df-text-muted); margin-top: 2px;">${getTimeAgo(deal.modifiedDate)}${_div}` : ''}                               ${_div}                            ${_div}                         ${_div}                      ${_div}                    ` : ''}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>View Deal${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                  \x3Cdiv class="tg-df-card-merchant-wrapper" style="position: absolute; bottom: 0; right: 0; background: transparent; padding: 8px 12px; z-index: 10;">                     \x3Cspan class="tg-df-card-merchant-pill" style="text-align: right; margin-bottom: 0;" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cdiv class="tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                    \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                    \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                      var c = this.parentNode;                      if (this.dataset.expanded === 'true') {                        var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                        if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                        pd.style.display = '-webkit-box';                        pd.style.webkitLineClamp = '3';                        this.textContent = 'READ MORE';                        this.style.position = 'absolute';                        this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                        this.style.paddingLeft = '16px';                        this.dataset.expanded = 'false';                      } else {                        var pd = this.previousElementSibling;                        pd.style.display = 'inline';                        pd.style.webkitLineClamp = 'unset';                        this.textContent = 'READ LESS';                        this.style.position = 'static';                        this.style.background = 'transparent';                        this.style.paddingLeft = '4px';                        this.dataset.expanded = 'true';                        pd.appendChild(this);                      }                    ">READ MORE${_button}                  \x3C/div>` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${deal.authorName ? `                    \x3Cdiv class="tg-df-author-line-desktop" style="padding: 0 0 ${isSavingsSquadMode ? 0 : 12}px 0;">                       \x3Cdiv style="display: flex; align-items: center; gap: 10px;">                          ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="36" height="36" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 36px; min-height: 36px;">` : ''}                          \x3Cdiv style="display: flex; flex-direction: column;">                             \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">Recommended by:${_div}                             \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.2;">                                \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                ${deal.modifiedDate ? `\x3Cspan style="color: var(--tg-df-text-muted);"> • ${getTimeAgo(deal.modifiedDate)}${_span}` : ''}                             ${_div}                          ${_div}                       ${_div}                    ${_div}                    ` : ''}                    ${priceGroupHtml}                  ${_div}                ${_div}                \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta" style="text-decoration: none; border-radius: 0;">${ctaText}${_a}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit) {            dealsHtml += `              \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer;">Load More${_button}              ${_div}            `;          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }          setTimeout(() => {            const contents = this.root.querySelectorAll('.tg-df-card-desc-content');            contents.forEach(p => {              if (p.scrollHeight > p.clientHeight || p.scrollHeight > 60) {                if (p.nextElementSibling) {                  p.nextElementSibling.style.display = 'block';                }              }            });                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));          }, 50);          const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              this.displayLimit += this.getRowsLimit();              this.render();            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/sales-events/amazon-is-already-discounting-21-best-selling-kitchen-appliances-ahead-of-prime-day-save-up-to-42-percent-now</link>
                                                                            <description>
                            <![CDATA[ Amazon is knocking up to 40% off top-rated kitchen appliances ahead of Prime Day. Here are my favorite deals to shop now. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">hAmqwdCBC7EwXq8k2eMkVj</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/hbrJPN9xYawo8dEAEeZteA-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 29 Sep 2026 16:39:38 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Sales Events]]></category>
                                                                                                                    <dc:creator><![CDATA[ Olivia Halevy ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/YAg7Fmh9dGKbg3hULBMWiU-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Olivia is a Deals Writer at Tom’s Guide. She loves all things lifestyle, shopping and sourcing the best deals from some of the top brands, retailers and websites around. From fashion and beauty to smart home and tech, she has an eye for finding practical, stylish, and reasonably-priced items that help make life simpler (and a little more aesthetically-pleasing).&amp;nbsp;Olivia has over five years of experience writing lifestyle, commerce, and branded content for &lt;a href=&quot;http://patch.com/&quot;&gt;Patch.com&lt;/a&gt;. She&#039;s covered major shopping holidays like Amazon Prime Day, Black Friday and Cyber Monday. In her free time, she enjoys trying out new exercise classes, binge-watching the latest viral TV shows, cooking, spending time with family and taking long walks with her dog, Gus.&amp;nbsp;&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/hbrJPN9xYawo8dEAEeZteA-1920-80.jpg">
                                                            <media:credit><![CDATA[Amazon / edited by Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Kitchen appliance deals]]></media:description>                                                            <media:text><![CDATA[Kitchen appliance deals]]></media:text>
                                <media:title type="plain"><![CDATA[Kitchen appliance deals]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/hbrJPN9xYawo8dEAEeZteA-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p><a href="https://www.tomsguide.com/sales-events/amazon-october-prime-big-deal-days-2026-best-sales-now">Prime Big Deal Days</a> kick off a week from today — but that hasn't stopped Amazon from rolling out early deals. One of the most impressive sales I've seen so far is on kitchen appliances. In fact, top brands like Ninja, Nespresso, Cuisinart and KitchenAid are slashing the prices on their best-selling appliances.</p><p>If you're in the market for a new air fryer, I highly suggest <a href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow">the Ninja Flip, which is sporting a $100 discount</a>. Need a new coffee maker? <a href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow">The Nespresso Vertuo Pop+ is down to $99</a>. Plus, <a href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow">the popular KitchenAid Deluxe 4.5 Qt. Tilt-head Stand Mixer is now $299</a>.</p><p>I've rounded up the best kitchen appliance deals from Amazon to shop ahead of October Prime Day. Plus, don't miss our <a href="https://www.tomsguide.com/coupons/amazon.com">Amazon promo codes</a> page for more ways to save.</p><h3 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h3><ul><li><a href="https://www.amazon.com/deals/?_encoding=UTF8" target="_blank" rel="nofollow"><strong>shop all Amazon kitchen appliance deals</strong></a></li><li><strong>Crock-Pot 7-Quart Slow Cooker: </strong><a href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow"><strong>was $59 now $44</strong></a></li><li><strong>Ninja Blast Max: </strong><a href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow"><strong>was $99 now $69</strong></a></li><li><strong>Keurig K-Express: </strong><a href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow"><strong>was $109 now $89</strong></a></li><li><strong>Nespresso Vertuo Pop+: </strong><a href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow"><strong>was $129 now $99</strong></a></li><li><strong>Ninja Flip Toaster Oven &amp; Air Fryer: </strong><a href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow"><strong>was $249 now $149</strong></a></li><li><strong>De'Longhi Dedica Duo Compact Espresso Machine: </strong><a href="https://www.amazon.com/DeLonghi-Dedica-Compact-Espresso-Machine/dp/B0F3RZZZF9?" target="_blank" rel="nofollow"><strong>was $299 now $199</strong></a></li><li><strong>Ninja Foodi XL Pro Air Fry Oven, 10-in-1: </strong><a href="https://www.amazon.com/Ninja-DT201-Countertop-Convection-Dehydrate/dp/B08BXX69K4" target="_blank" rel="nofollow"><strong>was $379 now $219</strong></a></li><li><strong>KitchenAid Deluxe 4.5 Qt. Tilt-head Stand Mixer: </strong><a href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow"><strong>was $399 now $299</strong></a></li><li><strong>Breville Barista Express: </strong><a href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow"><strong>was $699 now $499</strong></a></li></ul><h3 class="article-body__section" id="section-best-kitchen-appliance-deals"><span>Best Kitchen Appliance Deals</span></h3><div class="product"><a data-dimension112="e929b3a0-bc1b-11f1-8dc0-99d0b8befcda" data-action="Deal Block" data-label="7-Quart Slow Cooker" data-dimension48="7-Quart Slow Cooker" data-dimension25="$44" href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1080px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="xxEFYRjw4hJpt8rETUuaiH" name="Crock-Pot 7-Quart Slow Cooker" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xxEFYRjw4hJpt8rETUuaiH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>This 7-quart slow cooker is the perfect size to house a big batch of chili or queso to snack on all day. Or you can plan ahead and slow cook a melt-in-your-mouth roast with some carrots and potatoes for an easy dinner.<a class="view-deal button" href="https://www.amazon.com/Crock-Pot-SCV700SS-Stainless-7-Quart-Manual/dp/B003OAJGJO" target="_blank" rel="nofollow" data-dimension112="e929b3a0-bc1b-11f1-8dc0-99d0b8befcda" data-action="Deal Block" data-label="7-Quart Slow Cooker" data-dimension48="7-Quart Slow Cooker" data-dimension25="$44">View Deal</a></p></div><div class="product"><a data-dimension112="e929b468-bc1b-11f1-be26-f15d4bed2c21" data-action="Deal Block" data-label="Belgian Waffle Maker" data-dimension48="Belgian Waffle Maker" data-dimension25="$69" href="https://www.amazon.com/Ninja-BW1001-NeverStick-Precision-Pour-Chef-curated/dp/B0B358VDZJ/ref=" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1614px;"><p class="vanilla-image-block" style="padding-top:86.00%;"><img id="XofzJVhShmZ3kcVxuocQvB" name="Ninja Belgian Waffle Maker" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/XofzJVhShmZ3kcVxuocQvB-1920-80.png" mos="" align="middle" fullscreen="" width="1614" height="1388" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-BW1001-NeverStick-Precision-Pour-Chef-curated/dp/B0B358VDZJ/ref=" target="_blank" rel="nofollow" data-dimension112="e929b468-bc1b-11f1-be26-f15d4bed2c21" data-action="Deal Block" data-label="Belgian Waffle Maker" data-dimension48="Belgian Waffle Maker" data-dimension25="$69">Belgian Waffle Maker: was $99 now $69</a></strong><br />Weekend brunch just got an upgrade. This vertical waffle maker has five shade settings so everyone gets their waffle exactly how they like it, plus a specialty setting for high-sugar batters like brownies (yes, really). The precision-pour cup takes the guesswork out of measuring, and audible alerts mean no more burnt disasters. Pair it with the Ninja CREAMi for the ultimate breakfast-dessert combo. <a class="view-deal button" href="https://www.amazon.com/Ninja-BW1001-NeverStick-Precision-Pour-Chef-curated/dp/B0B358VDZJ/ref=" target="_blank" rel="nofollow" data-dimension112="e929b468-bc1b-11f1-be26-f15d4bed2c21" data-action="Deal Block" data-label="Belgian Waffle Maker" data-dimension48="Belgian Waffle Maker" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="e929b4e0-bc1b-11f1-a3c2-eb79cc7c29ee" data-action="Deal Block" data-label="Blast Max" data-dimension48="Blast Max" data-dimension25="$69" href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1216px;"><p class="vanilla-image-block" style="padding-top:123.36%;"><img id="9Q4QY399FaozAFUt4j8dTW" name="ninja-blast-max-portable-blender--twist--bb517479-54ce-4a77-974c-58e2f44dde33.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/9Q4QY399FaozAFUt4j8dTW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1216" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Ninja Blast Max is capable of taking on any challenge you throw at it, including crushing ice and blitzing berries to make yummy smoothies. It comes with multiple blend settings to make sure your blender is using the right level of power for the task at hand, and the compact size means it’s a great option for anyone with a small kitchen. <a class="view-deal button" href="https://www.amazon.com/Ninja-removable-Dishwasher-Leakproof-BC251NV/dp/B0DB8ZN253?" target="_blank" rel="nofollow" data-dimension112="e929b4e0-bc1b-11f1-a3c2-eb79cc7c29ee" data-action="Deal Block" data-label="Blast Max" data-dimension48="Blast Max" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="e929b558-bc1b-11f1-a8b5-699d5ea2aeee" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$69" href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="EBqQHURi67ApM2ai2joGg6" name="_0007_CHEFMAN Multifunctional Digital Air Fryer+" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/EBqQHURi67ApM2ai2joGg6-1920-80.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow" data-dimension112="e929b558-bc1b-11f1-a8b5-699d5ea2aeee" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$69">Multifunctional Digital Air Fryer: was $139 now $69</a></strong><br />An extra large digital air fryer, this CHEFMAN model has 17 presets and an easy-to-use touch screen so you can get cooking immediately. It's big enough for family-sized meals, party-sized appetizers and has a window so you can check your cooking without opening it.<a class="view-deal button" href="https://www.amazon.com/CHEFMAN-Multifunction-Rotisserie-Dehydrator-Convection/dp/B08DL8WH9V" target="_blank" rel="nofollow" data-dimension112="e929b558-bc1b-11f1-a8b5-699d5ea2aeee" data-action="Deal Block" data-label="Multifunctional Digital Air Fryer" data-dimension48="Multifunctional Digital Air Fryer" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="e929b922-bc1b-11f1-ae2b-a1cc01080fde" data-action="Deal Block" data-label="Cordless Citrus Juicer" data-dimension48="Cordless Citrus Juicer" data-dimension25="$79" href="https://www.amazon.com/KitchenAid-Cordless-Citrus-Juicer-separately/dp/B0DN6RX5Q3" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:964px;"><p class="vanilla-image-block" style="padding-top:155.60%;"><img id="HmFhrr2KfXYEaCMCSBwkhL" name="KitchenAid Go Cordless Citrus Juicer" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HmFhrr2KfXYEaCMCSBwkhL-1920-80.jpg" mos="" align="middle" fullscreen="" width="964" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The KitchenAid Go Cordless Citrus Juicer makes it so simple to have fresh juice every morning with minimal mess. If you hate pulp in your juice, this won’t be for you. But if you’re looking for the fastest way to juice your citrus, this is the answer. It’s simple to clean too, since the top half of the appliance is dishwasher-friendly.<a class="view-deal button" href="https://www.amazon.com/KitchenAid-Cordless-Citrus-Juicer-separately/dp/B0DN6RX5Q3" target="_blank" rel="nofollow" data-dimension112="e929b922-bc1b-11f1-ae2b-a1cc01080fde" data-action="Deal Block" data-label="Cordless Citrus Juicer" data-dimension48="Cordless Citrus Juicer" data-dimension25="$79">View Deal</a></p></div><div class="product"><a data-dimension112="e929b9fe-bc1b-11f1-8f7d-850dc322ec45" data-action="Deal Block" data-label="Air Fryer" data-dimension48="Air Fryer" data-dimension25="$79" href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B07FDJMC9Q" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1168px;"><p class="vanilla-image-block" style="padding-top:128.42%;"><img id="ThfSLcj6qWSrgjihSvk2mW" name="Ninja Air Fryer 4QT.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ThfSLcj6qWSrgjihSvk2mW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1168" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>One of Ninja's first air fryers to hit the market, the AF101 does offer one slight advantage over the Pro. Its compact design makes it ideal for small kitchens, and it does still offer an impressive 05°F-400°F temperature range. <a class="view-deal button" href="https://www.amazon.com/Ninja-AF101-Fryer-Black-gray/dp/B07FDJMC9Q" target="_blank" rel="nofollow" data-dimension112="e929b9fe-bc1b-11f1-8f7d-850dc322ec45" data-action="Deal Block" data-label="Air Fryer" data-dimension48="Air Fryer" data-dimension25="$79">View Deal</a></p></div><div class="product"><a data-dimension112="e929ba9e-bc1b-11f1-96e1-13218027a7b8" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$89" href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:230.93%;"><img id="SNGj6WoG25u9rj7PA3Zhre" name="Keurig K Express" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SNGj6WoG25u9rj7PA3Zhre-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="1568" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow" data-dimension112="e929ba9e-bc1b-11f1-96e1-13218027a7b8" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$89">K-Express: was $109 now $89</a></strong><br />The Keurig Express offers three cup sizes — 8, 10 and 12 oz and has a 42 oz detachable water reservoir, making it easy to remove, fill or clean. By removing the drip tray you can position a travel mug up to 7.4 inches tall under the brew stream. <a class="view-deal button" href="https://www.amazon.com/Keurig-K-Express-Coffee-Single-Brewer/dp/B0D3MR4M4C?" target="_blank" rel="nofollow" data-dimension112="e929ba9e-bc1b-11f1-96e1-13218027a7b8" data-action="Deal Block" data-label="K-Express" data-dimension48="K-Express" data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="e929bb16-bc1b-11f1-ae27-39b1205ed715" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99" href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:99.56%;"><img id="4uiaRXRKY8Go6F4ZpM7UdA" name="Ninja coffee" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4uiaRXRKY8Go6F4ZpM7UdA-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="676" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow" data-dimension112="e929bb16-bc1b-11f1-ae27-39b1205ed715" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99">Single Serve Coffee Maker with Pods and Grounds: was $129 now $99</a></strong><br />This stylish Ninja coffee maker comes in a gorgeous choice of colorways, including Sage Green, and is now on sale for $30 off. Whether you prefer pods or grounds, this device makes tasty brews in 7 sizes (6-oz. to 24-oz) and has a built-in, fold-away milk frother! The only problem you'll have is deciding which color to choose.<a class="view-deal button" href="https://www.amazon.com/dp/B0C25Y15TL?" target="_blank" rel="nofollow" data-dimension112="e929bb16-bc1b-11f1-ae27-39b1205ed715" data-action="Deal Block" data-label="Single Serve Coffee Maker with Pods and Grounds" data-dimension48="Single Serve Coffee Maker with Pods and Grounds" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="e929bbd4-bc1b-11f1-b842-c5cdc0bf1866" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89" href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:717px;"><p class="vanilla-image-block" style="padding-top:163.18%;"><img id="LpQPvQCcU8GNALWdf2GLs4" name="51EcND+lspL._AC_SL1173_.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/LpQPvQCcU8GNALWdf2GLs4-1920-80.jpg" mos="" align="middle" fullscreen="" width="717" height="1170" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow" data-dimension112="e929bbd4-bc1b-11f1-b842-c5cdc0bf1866" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89">PerfecTemp Cordless Electric Kettle: was $129 now $89</a></strong><br />This sleek electric Kettle heats and boils your brews quickly. With six preset heating profiles to choose from, it can extract the most flavor out of your tea or morning coffee. We rank it as one of the <a href="https://www.tomsguide.com/best-picks/the-best-electric-kettles">best electric kettles</a>.<a class="view-deal button" href="https://www.amazon.com/Cuisinart-CPK-17-PerfecTemp-1-7-Liter-Stainless/dp/B003KYSLNQ" target="_blank" rel="nofollow" data-dimension112="e929bbd4-bc1b-11f1-b842-c5cdc0bf1866" data-action="Deal Block" data-label="PerfecTemp Cordless Electric Kettle" data-dimension48="PerfecTemp Cordless Electric Kettle" data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="e929bc4c-bc1b-11f1-b82e-c10ff6c95471" data-action="Deal Block" data-label="Vertuo Pop+" data-dimension48="Vertuo Pop+" data-dimension25="$99" href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:82.73%;"><img id="fGSRj3582aRZDhrdn6pES5" name="Nespresso Vertuo Pop Plus Deluxe Coffee.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fGSRj3582aRZDhrdn6pES5-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1241" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow" data-dimension112="e929bc4c-bc1b-11f1-b82e-c10ff6c95471" data-action="Deal Block" data-label="Vertuo Pop+" data-dimension48="Vertuo Pop+" data-dimension25="$99">Vertuo Pop+: was $129 now $99</a></strong><br />The least-expensive machine in Amazon's sale is the Nespresso Vertuo Pop Plus Deluxe. In our <a href="https://www.tomsguide.com/opinion/nespressos-latest-pod-coffee-machine-was-my-wake-up-call-to-what-a-cuppa-can-be">Nespresso Vertuo Pop hands-on</a>, we said it's anything but entry level where performance is concerned. We like that it has an Expert Mode, which lets you customize your coffee, unveiling a plethora of new options in the process.<a class="view-deal button" href="https://www.amazon.com/Nespresso-Vertuo-POP-Breville-White/dp/B0CS71J3GP" target="_blank" rel="nofollow" data-dimension112="e929bc4c-bc1b-11f1-b82e-c10ff6c95471" data-action="Deal Block" data-label="Vertuo Pop+" data-dimension48="Vertuo Pop+" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="e929bcba-bc1b-11f1-8942-659219a59ca3" data-action="Deal Block" data-label="9 Cup Food Processor" data-dimension48="9 Cup Food Processor" data-dimension25="$99" href="https://www.amazon.com/KitchenAid-Cup-Food-Processor-KFP0921/dp/B09HSQ3TJG?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1530px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="VcxkbkauHkBKauGGNEYzun" name="KitchenAid 9 Cup Food Processor" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/VcxkbkauHkBKauGGNEYzun-1920-80.jpg" mos="" align="middle" fullscreen="" width="1530" height="1530" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/KitchenAid-Cup-Food-Processor-KFP0921/dp/B09HSQ3TJG?" target="_blank" rel="nofollow" data-dimension112="e929bcba-bc1b-11f1-8942-659219a59ca3" data-action="Deal Block" data-label="9 Cup Food Processor" data-dimension48="9 Cup Food Processor" data-dimension25="$99">9 Cup Food Processor: was $159 now $99</a></strong><br />This multi-functional power machine can chop, shred, mince, slice, knead, whip, mix and puree. And it can handle anything from meats and cheeses to vegetables and doughs. What's more, it's fast and can mince 1lb of chicken or beef in 10 seconds. It comes with a 9-cup bowl and lid, a multi-purpose four-blade, a reversible slicing and shredding disc, a whisk accessory, a refrigerator lid, and a dough blade.<a class="view-deal button" href="https://www.amazon.com/KitchenAid-Cup-Food-Processor-KFP0921/dp/B09HSQ3TJG?" target="_blank" rel="nofollow" data-dimension112="e929bcba-bc1b-11f1-8942-659219a59ca3" data-action="Deal Block" data-label="9 Cup Food Processor" data-dimension48="9 Cup Food Processor" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="e929bd50-bc1b-11f1-9332-9d0c2595c28d" data-action="Deal Block" data-label="NeverClog Cold Press Juicer" data-dimension48="NeverClog Cold Press Juicer" data-dimension25="$124" href="https://www.amazon.com/dp/B0DPXMTZ16?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1499px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="2WLwjdnMeBZu5mrkYrS2jH" name="Ninja NeverClog Cold Press Juicer" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/2WLwjdnMeBZu5mrkYrS2jH-1920-80.jpg" mos="" align="middle" fullscreen="" width="1499" height="1499" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>Ninja's NeverClog Cold Press Juicer removes the hassle of juicing fruits and vegetables. The special filter pushes pulp through without clogging and lets you customize the amount of pulp in your juice with two interchangeable pulp filters. It comes with a 24-oz juice jug and a 36-oz pulp container, allowing you to make large batches of juice, rather than single servings.<a class="view-deal button" href="https://www.amazon.com/dp/B0DPXMTZ16?" target="_blank" rel="nofollow" data-dimension112="e929bd50-bc1b-11f1-9332-9d0c2595c28d" data-action="Deal Block" data-label="NeverClog Cold Press Juicer" data-dimension48="NeverClog Cold Press Juicer" data-dimension25="$124">View Deal</a></p></div><div class="product"><a data-dimension112="e929bdc8-bc1b-11f1-a926-6380885dbfa3" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149" href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1676px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="sWibiMn9jcqpLxyQRazy6f" name="Ninja Amazon 2.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/sWibiMn9jcqpLxyQRazy6f-1920-80.jpg" mos="" align="middle" fullscreen="" width="1676" height="1676" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow" data-dimension112="e929bdc8-bc1b-11f1-a926-6380885dbfa3" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149">Mega Kitchen System: was $219 now $149</a></strong><br />Leave all the multi-tasking in the kitchen to one appliance with this Ninja blender. With four functions for smoothies, processing, dough, drinks and more it will quickly become your go-to kitchen appliance. With this ultimate appliance, you’ll be enjoying fresh, healthy drinks, homemade bread and sweet bakes.<a class="view-deal button" href="https://www.amazon.com/dp/B00939I7EK" target="_blank" rel="nofollow" data-dimension112="e929bdc8-bc1b-11f1-a926-6380885dbfa3" data-action="Deal Block" data-label="Mega Kitchen System" data-dimension48="Mega Kitchen System" data-dimension25="$149">View Deal</a></p></div><div class="product"><a data-dimension112="e929be36-bc1b-11f1-9f9d-e75833f64930" data-action="Deal Block" data-label="Flip Toaster Oven &amp; Air Fryer" data-dimension48="Flip Toaster Oven &amp; Air Fryer" data-dimension25="$149" href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:600px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="qey9zt42Hnq8ePgcaiiaR7" name="Ninja Flip" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/qey9zt42Hnq8ePgcaiiaR7-1920-80.jpg" mos="" align="middle" fullscreen="" width="600" height="600" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow" data-dimension112="e929be36-bc1b-11f1-9f9d-e75833f64930" data-action="Deal Block" data-label="Flip Toaster Oven &amp; Air Fryer" data-dimension48="Flip Toaster Oven &amp; Air Fryer" data-dimension25="$149">Flip Toaster Oven &amp; Air Fryer: was $249 now $149</a></strong><br />I've been using the Ninja Flip for over a year now and I can tell you that it is a total cooking game changer. It has 8 functions in one convenient and versatile machine: air fry, roast, bake, toast, and more. I've been able to use it for pretty much everything including toasting toast, baking chicken, roasting vegetable and more. One of my favorite things about it is the fact that when you're not using it, you can flip it up and away, which will give you 50% more counter space back.<a class="view-deal button" href="https://www.amazon.com/Ninja-Functionality-Capability-Removable-SP151/dp/B0D1CXL52G?" target="_blank" rel="nofollow" data-dimension112="e929be36-bc1b-11f1-9f9d-e75833f64930" data-action="Deal Block" data-label="Flip Toaster Oven &amp; Air Fryer" data-dimension48="Flip Toaster Oven &amp; Air Fryer" data-dimension25="$149">View Deal</a></p></div><div class="product"><a data-dimension112="e929beae-bc1b-11f1-b9e4-01175df1d823" data-action="Deal Block" data-label="Dedica Duo Compact Espresso Machine" data-dimension48="Dedica Duo Compact Espresso Machine" data-dimension25="$199" href="https://www.amazon.com/DeLonghi-Dedica-Compact-Espresso-Machine/dp/B0F3RZZZF9?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1080px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="ES3eY7aJDiE5T5dxnQUmA9" name="delonghi_dedica_duo_vanilla_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ES3eY7aJDiE5T5dxnQUmA9-1920-80.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/DeLonghi-Dedica-Compact-Espresso-Machine/dp/B0F3RZZZF9?" target="_blank" rel="nofollow" data-dimension112="e929beae-bc1b-11f1-b9e4-01175df1d823" data-action="Deal Block" data-label="Dedica Duo Compact Espresso Machine" data-dimension48="Dedica Duo Compact Espresso Machine" data-dimension25="$199">Dedica Duo Compact Espresso Machine: was $299 now $199</a></strong><br />The De’Longhi Dedica Duo is a dual-brew espresso machine that measures just 5.9 inches wide, so it won’t take up too much room on your countertop, making it perfect for smaller living quarters. There are three preset recipes, a professional pump, a digital touch display, and a commercial-style steam wand. It's so easy to use that anyone can make a perfect coffee with it.<a class="view-deal button" href="https://www.amazon.com/DeLonghi-Dedica-Compact-Espresso-Machine/dp/B0F3RZZZF9?" target="_blank" rel="nofollow" data-dimension112="e929beae-bc1b-11f1-b9e4-01175df1d823" data-action="Deal Block" data-label="Dedica Duo Compact Espresso Machine" data-dimension48="Dedica Duo Compact Espresso Machine" data-dimension25="$199">View Deal</a></p></div><div class="product"><a data-dimension112="e929bf1c-bc1b-11f1-b254-2faccc4cdda6" data-action="Deal Block" data-label="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension48="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension25="$219" href="https://www.amazon.com/Ninja-DT201-Countertop-Convection-Dehydrate/dp/B08BXX69K4" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:75.80%;"><img id="sFc44K8P9eTgsrZ4Kc25oB" name="Foodi XL Pro Air Fry Oven, 10-in-1" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/sFc44K8P9eTgsrZ4Kc25oB-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1137" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-DT201-Countertop-Convection-Dehydrate/dp/B08BXX69K4" target="_blank" rel="nofollow" data-dimension112="e929bf1c-bc1b-11f1-b254-2faccc4cdda6" data-action="Deal Block" data-label="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension48="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension25="$219">Foodi XL Pro Air Fry Oven, 10-in-1: was $379 now $219</a></strong><br />42% off is one of the biggest Ninja discounts you'll find right now. While this XL air fryer/oven takes up a lot of space, it offers plenty of cooking functions and perfect cooking results every time. <a class="view-deal button" href="https://www.amazon.com/Ninja-DT201-Countertop-Convection-Dehydrate/dp/B08BXX69K4" target="_blank" rel="nofollow" data-dimension112="e929bf1c-bc1b-11f1-b254-2faccc4cdda6" data-action="Deal Block" data-label="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension48="Foodi XL Pro Air Fry Oven, 10-in-1" data-dimension25="$219">View Deal</a></p></div><div class="product"><a data-dimension112="e929bf8a-bc1b-11f1-aa9b-f505d7dc4f4b" data-action="Deal Block" data-label="Crispi Pro" data-dimension48="Crispi Pro" data-dimension25="$249" href="https://www.amazon.com/Ninja-Crispi-Glass-Amethyst-AS101PU1/dp/B0GRJNMHBQ/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:96.00%;"><img id="CHukmWdqjDdNFwby3iRufB" name="Ninja Crispi Pro" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CHukmWdqjDdNFwby3iRufB-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1440" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-Crispi-Glass-Amethyst-AS101PU1/dp/B0GRJNMHBQ/" target="_blank" rel="nofollow" data-dimension112="e929bf8a-bc1b-11f1-aa9b-f505d7dc4f4b" data-action="Deal Block" data-label="Crispi Pro" data-dimension48="Crispi Pro" data-dimension25="$249">Crispi Pro: was $299 now $249</a></strong><br />Taking a step above the original <a href="https://www.tomsguide.com/home/air-fryers/ninja-crispi-air-fryer-review">Ninja Crispi</a>, the Pro offers 6 different functions, like Recrisp, Air Fry and Roast, and comes with three larger glass containers, making it the perfect size for families or meal prep. It comes with an interchangeable stand which allows you to fit everything from 2.5 quart to 10 quart containers to the cooking lid. Now discounted by $50 for Prime Day, this is a certified steal. <a class="view-deal button" href="https://www.amazon.com/Ninja-Crispi-Glass-Amethyst-AS101PU1/dp/B0GRJNMHBQ/" target="_blank" rel="nofollow" data-dimension112="e929bf8a-bc1b-11f1-aa9b-f505d7dc4f4b" data-action="Deal Block" data-label="Crispi Pro" data-dimension48="Crispi Pro" data-dimension25="$249">View Deal</a></p></div><div class="product"><a data-dimension112="e929c002-bc1b-11f1-a3a7-835bc2c2b276" data-action="Deal Block" data-label="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension48="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension25="$299" href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:97.94%;"><img id="82mWMKNvrtU6QZZpBYPy7m" name="KitchenAid Artisan Rose.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/82mWMKNvrtU6QZZpBYPy7m-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="665" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow" data-dimension112="e929c002-bc1b-11f1-a3a7-835bc2c2b276" data-action="Deal Block" data-label="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension48="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension25="$299">Deluxe 4.5 Qt. Tilt-head Stand Mixer: was $399 now $299</a></strong><br />If you want a stylish, tilt-head stand mixer to suit your kitchen, this is an excellent deal. With a 4.5 quart capacity, it's large enough to bake up to 8 dozen cookies in a single batch. A powerful mixer, it has 10 speeds to quickly whisk, mix, beat and whip up a storm. It also comes with silver coated flat beater, dough hook and 6-wire metal whip. Get baking with this great deal. <a class="view-deal button" href="https://www.amazon.com/KitchenAid-Classic-Quart-Tilt-Head-K45SSOB/dp/B003OXNBYC" target="_blank" rel="nofollow" data-dimension112="e929c002-bc1b-11f1-a3a7-835bc2c2b276" data-action="Deal Block" data-label="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension48="Deluxe 4.5 Qt. Tilt-head Stand Mixer" data-dimension25="$299">View Deal</a></p></div><div class="product"><a data-dimension112="e929c070-bc1b-11f1-9314-c1284d328104" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379" href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:91.20%;"><img id="HPfDur99xHfhfWNbGej8ZE" name="KitchenAid Artisan Mixer.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HPfDur99xHfhfWNbGej8ZE-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1368" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow" data-dimension112="e929c070-bc1b-11f1-9314-c1284d328104" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379">Artisan Series 5 Quart: was $499 now $379</a></strong><br />A Tom's Guide favorite, in our <a href="https://www.tomsguide.com/opinion/the-kitchenaid-artisan-stand-mixer-is-my-best-kitchen-purchase-ever-heres-why">KitchenAid Artisan 5-Quart stand mixer review</a>, we dubbed it the "best kitchen purchase" you can ever make. It beats, whisks, and kneads at 10 different speeds, so you don't have to, reducing recipe times. The bowl is big enough to support 9 dozen cookies or 4 loaves of bread at a time. This machine also boasts a 59-point planetary mixing action — fancy words that translate into incredibly mixed ingredients. Plus, it ships with a flat beater, coated dough hook, 6-wire whip, and 1-piece pouring shield. <a class="view-deal button" href="https://www.amazon.com/KitchenAid-KSM150PSOB-Artisan-Pouring-Shield/dp/B00005UP2L" target="_blank" rel="nofollow" data-dimension112="e929c070-bc1b-11f1-9314-c1284d328104" data-action="Deal Block" data-label="Artisan Series 5 Quart" data-dimension48="Artisan Series 5 Quart" data-dimension25="$379">View Deal</a></p></div><div class="product"><a data-dimension112="e929c0de-bc1b-11f1-9fdb-9fa7bc2f467a" data-action="Deal Block" data-label="Luxe Café" data-dimension48="Luxe Café" data-dimension25="$499" href="https://www.amazon.com/Ninja-Integrated-Hands-Free-Cappuccinos-ES601/dp/B0D45PK5V4/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:541px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="HcnQ36qmUJg5VJidxsJ76X" name="Ninja Luxe Cafe.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HcnQ36qmUJg5VJidxsJ76X-1920-80.jpg" mos="" align="middle" fullscreen="" width="541" height="541" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Ninja-Integrated-Hands-Free-Cappuccinos-ES601/dp/B0D45PK5V4/" target="_blank" rel="nofollow" data-dimension112="e929c0de-bc1b-11f1-9fdb-9fa7bc2f467a" data-action="Deal Block" data-label="Luxe Café" data-dimension48="Luxe Café" data-dimension25="$499">Luxe Café: was $599 now $499</a></strong><br />This deal gets you a 3-in-1 machine that makes espresso, drip coffee and rapid cold brew. It also has Barista Assist technology, an integrated grinder and weight-based dosing, plus hands-free frothing. <a class="view-deal button" href="https://www.amazon.com/Ninja-Integrated-Hands-Free-Cappuccinos-ES601/dp/B0D45PK5V4/" target="_blank" rel="nofollow" data-dimension112="e929c0de-bc1b-11f1-9fdb-9fa7bc2f467a" data-action="Deal Block" data-label="Luxe Café" data-dimension48="Luxe Café" data-dimension25="$499">View Deal</a></p></div><div class="product"><a data-dimension112="e929c156-bc1b-11f1-8fd7-0d1f657d5713" data-action="Deal Block" data-label="Barista Express" data-dimension48="Barista Express" data-dimension25="$499" href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1306px;"><p class="vanilla-image-block" style="padding-top:114.85%;"><img id="xqb7yApNa26xAkZLUbt3tW" name="breville barista express.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xqb7yApNa26xAkZLUbt3tW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1306" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Breville Barista Express is one of the most iconic and respected bean-to-cup espresso machines ever made. Although it's been out for around 6 years at this point, the Barista Express shows no signs of slowing down. Right now it's just $499, which is the same price as Breville's compact Bambino Plus. You basically get a free grinder.<a class="view-deal button" href="https://www.amazon.com/Breville-BES870XL-Barista-Express-Espresso/dp/B00CH9QWOU" target="_blank" rel="nofollow" data-dimension112="e929c156-bc1b-11f1-8fd7-0d1f657d5713" data-action="Deal Block" data-label="Barista Express" data-dimension48="Barista Express" data-dimension25="$499">View Deal</a></p></div><h3 class="article-body__section" id="section-shop-more-deals"><span>Shop more deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=Everything&amp;retailer=Amazon&amp;rows=8&amp;view_mode=savings_squad&amp;widget_title=Top+Amazon+Deals+Handpicked+by+Our+Editors&amp;widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&amp;bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function getTimeAgo(dateString) {        if (!dateString) return '';        const date = new Date(dateString);        const now = new Date();        const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);        if (diffInSeconds < 60) return 'Just now';        const diffInMinutes = Math.floor(diffInSeconds / 60);        if (diffInMinutes < 60) return `${diffInMinutes} min${diffInMinutes > 1 ? 's' : ''} ago`;        const diffInHours = Math.floor(diffInMinutes / 60);        if (diffInHours < 24) return `${diffInHours} hr${diffInHours > 1 ? 's' : ''} ago`;        const diffInDays = Math.floor(diffInHours / 24);        if (diffInDays < 30) return `${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`;        const diffInMonths = Math.floor(diffInDays / 30);        if (diffInMonths < 12) return `${diffInMonths} mo${diffInMonths > 1 ? 's' : ''} ago`;        const diffInYears = Math.floor(diffInDays / 365);        return `${diffInYears} yr${diffInYears > 1 ? 's' : ''} ago`;      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;      position: relative;      z-index: 20;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      margin: 0 auto;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {      display: grid;      width: 100%;      grid-template-columns: repeat(4, 1fr);      gap: 12px;      margin: 0 auto;      max-width: 800px;    }                 .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;      width: 100%;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      width: 100%;      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }    @container tg-df (max-width: 768px) {      .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {        width: 100%;        margin: 0;        margin-bottom: -320px;        padding: 0 16px 320px 16px;        display: flex;        flex-wrap: nowrap;        gap: 8px;        overflow-x: auto;        overflow-y: hidden;        pointer-events: none;        scrollbar-width: none;        -webkit-overflow-scrolling: touch;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }      .tg-df-sort-wrapper {        pointer-events: auto;        flex: 0 0 auto;        width: 175px;        min-width: 175px;      }    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 120px;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 16px 16px 8px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }                  .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;        width: auto;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;      width: 100vw;      max-width: 1200px;      position: relative;      left: 50%;      transform: translateX(-50%);    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 14px;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    .tg-df-grid-wrapper { position: relative; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn {      display: inline-flex;      align-items: center;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.40);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #1f69ff; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #0056e0; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }    .tg-df-savings-squad-header { margin-bottom: 24px; text-align: center; display: none; }    .tg-df-banner-img-desktop { display: block; width: 100%; height: auto; margin-bottom: 32px; }    .tg-df-banner-img-mobile { display: none; width: 100%; height: auto; margin-bottom: 32px; }    @container tg-df (max-width: 600px) {      .tg-df-banner-img-desktop { display: none; }      .tg-df-banner-img-mobile { display: block; }    }    .tg-df-header-title { font-size: 28px; font-weight: 700; color: var(--tg-df-text); margin: 32px 0 12px 0; line-height: 1.3; }    .tg-df-header-subtitle { font-size: 16px; color: var(--tg-df-text-muted); margin: 0 0 32px 0; line-height: 1.5; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3Cdiv class="tg-df-savings-squad-header" id="tg-df-savings-squad-header">      \x3Cpicture>        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/xkh2og7m3d1778189998.png" alt="Deals Banner" class="tg-df-banner-img-desktop" />        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/gmak6rtdf41778245089.png" alt="Deals Banner Mobile" class="tg-df-banner-img-mobile" />      \x3C/picture>      \x3Cdiv class="tg-df-header-text">        \x3Ch2 class="tg-df-header-title" id="tg-df-header-title">Editor's Choice Deals\x3C/h2>        \x3Cp class="tg-df-header-subtitle" id="tg-df-header-subtitle">Discover the best discounts currently available, curated daily by the Tom's Guide Savings Squad.\x3C/p>      \x3C/div>    \x3C/div>    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Televisions" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/wcMxTsHgqu3roMbAx7RLnT-132-100.png" alt="TVs" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">TVs\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Phones" data-pr="over50">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/G3KGaRGzj24F6PUsw4bWpT-132-100.png" alt="Phones" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Phones\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Computing" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/znNvsLzx8NEgNkD9HSFSnT-132-100.png" alt="Computing" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Computing\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Gaming" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/Pgew8yaRQeZFHqHjTzvBnT-132-100.png" alt="Gaming" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Gaming\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Mattresses" data-pr="over500">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/cW7xsaLyesxkHFVSiC4kmT-132-100.png" alt="Mattresses" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Mattresses\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Audio" data-pr="over30">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/pCvBVHuhaQVjKt3VgCjbqT-132-100.png" alt="Audio" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Audio\x3C/span>            \x3C/div>                  \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E      \x3Cdiv class="tg-df-top-bar" id="tg-df-top-bar" style="position: relative; z-index: 100; margin: 0 auto 20px;">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>      \x3C/div>    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">              \x3Cdiv class="tg-df-filters-container" style="position: relative; width: 100%; max-width: 800px; margin: 0 auto;">          \x3Cbutton class="tg-df-scroll-btn left" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: -200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M15 18l-6-6 6-6"/>\x3C/svg>          \x3C/button>          \x3Cbutton class="tg-df-scroll-btn right" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: 200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M9 18l6-6-6-6"/>\x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-filters">          \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>          \x3C/div>        \x3C/div>        \x3C/div>      \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();        }        getViewMode() {          console.log("DEBUG getViewMode -> override:", this.viewModeOverride, "editorMode:", this.editorMode);          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          console.log("[DEBUG] applyLayoutMode CALLED! mode=", mode);          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          const showHeaderDetails = params.get('show_header_details') !== 'false';          const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          const topBarDiv = this.root.querySelector('#tg-df-top-bar');          const headerElement = this.root.querySelector('#tg-df-savings-squad-header');          if (headerElement) {             headerElement.style.display = (mode === 'savings_squad' && showHeaderDetails) ? 'block' : 'none';          }          if (mode === 'carousel') {             this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (topBarDiv) topBarDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.add('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (topBarDiv) topBarDiv.style.display = 'block';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!this.viewModeOverride && initialViewMode) {            this.viewModeOverride = initialViewMode;          }          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Gaming laptops';          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button, .tg-df-container .tg-df-card-cta { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover, .tg-df-container .tg-df-card-cta:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (this.viewModeSelect && params.has('view_mode')) {            this.viewModeSelect.value = params.get('view_mode');          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'date_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }          const headerTitleEl = this.root.querySelector('#tg-df-header-title');          const headerSubtitleEl = this.root.querySelector('#tg-df-header-subtitle');          if (params.has('widget_title') && headerTitleEl) {             headerTitleEl.textContent = params.get('widget_title');          }          if (params.has('widget_subtitle') && headerSubtitleEl) {             headerSubtitleEl.textContent = params.get('widget_subtitle');          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            if (this.getViewMode() === 'savings_squad') {              this.searchInput.value = '';            } else {              this.searchInput.value = this.currentQuery;            }          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'date_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const handleFiltersScroll = () => {            const filters = this.root.querySelector('.tg-df-filters');            const leftBtn = this.root.querySelector('.tg-df-scroll-btn.left');            const rightBtn = this.root.querySelector('.tg-df-scroll-btn.right');            if (filters && leftBtn && rightBtn) {              const { scrollLeft, scrollWidth, clientWidth } = filters;              leftBtn.style.display = scrollLeft > 0 ? 'flex' : 'none';              rightBtn.style.display = Math.ceil(scrollLeft + clientWidth) < scrollWidth - 5 ? 'flex' : 'none';            }          };          const filters = this.root.querySelector('.tg-df-filters');          if (filters) {            filters.addEventListener('scroll', handleFiltersScroll);            window.addEventListener('resize', handleFiltersScroll);            setTimeout(handleFiltersScroll, 100);                        // Also call after rendering dropdowns            const origRenderCategories = this.renderCategories;            if (origRenderCategories) {               this.renderCategories = (...args) => {                 origRenderCategories.apply(this, args);                 setTimeout(handleFiltersScroll, 50);               };            }          }                const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          const showAutocomplete = () => {             if (this.getViewMode() !== 'savings_squad' || !this.autocompleteDropdown || !this.airedaleTags) return;                          let terms = this.airedaleTags;             if (this.airedaleBrands) {                terms = terms.concat(this.airedaleBrands.map(b => b.formatted_value));             }             terms = [...new Set(terms)];                          const query = this.searchInput.value.trim();             let matches = [];             if (query.length > 0) {                 matches = terms.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase());             } else {                 matches = terms;             }                          if (matches.length > 0) {                 this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                 this.autocompleteDropdown.classList.add('active');             } else {                 this.autocompleteDropdown.classList.remove('active');             }          };          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('focus', showAutocomplete);            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              showAutocomplete();              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  if (this.getViewMode() === 'savings_squad') {                    this.activeDealTag = null;                    this.currentQuery = '';                    if (this.categoryFilter) this.categoryFilter.value = 'all';                    this.fetchDeals('');                  } else {                    this.deals = [];                    this.render();                  }                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                                let isTag = false;                if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;                if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;                this.activeDealTag = isTag ? query : null;                                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   if (query.length === 0 && this.getViewMode() === 'savings_squad') {                       if (this.categoryFilter) this.categoryFilter.value = 'all';                   }                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   if (this.categoryFilter && this.airedaleTags.includes(tag)) {                       this.categoryFilter.value = tag;                   }                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                            let isTag = false;              if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;              if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;              this.activeDealTag = isTag ? query : null;                            this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 if (query.length === 0 && this.getViewMode() === 'savings_squad') {                     if (this.categoryFilter) this.categoryFilter.value = 'all';                 }                 this.fetchDeals(query);              }            });          }          if(this.sortSelect && this.sortSelect.querySelector('option[value="date_desc"]') === null) {              const option = document.createElement('option');              option.value = "date_desc";              option.text = "Newest First";              this.sortSelect.insertBefore(option, this.sortSelect.firstChild);          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               if (val) {                 this.currentQuery = val;               } else {                 if (this.searchInput && this.currentQuery === document.querySelector('#tg-df-brand-trigger')?.getAttribute('data-active-brand')) {                     // don't clear current query if a brand is selected                 } else if (this.searchInput) {                     this.currentQuery = '';                     this.searchInput.value = '';                 }               }               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = 'date_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const finalHref = cardLink.href || cardLink.getAttribute('href') || '';                let actualRevenueId = cardLink.getAttribute('data-revenue-id');                const revMatch = finalHref.match(/(?:subId1|xcust|clickref|ascsubtag)=[^&]*?(\d{18,20})(?:&|$)/i);                if (revMatch && revMatch[1]) {                  actualRevenueId = revMatch[1];                }                const rewrittenLink = finalHref;                const revenueId = actualRevenueId;                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getRowsLimit() {          if (this.rowsSelect && this.rowsSelect.value) return parseInt(this.rowsSelect.value, 10);          let configSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {             configSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {             configSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(configSource);          if (params.has('rows')) return parseInt(params.get('rows'), 10) || 12;          return 12;        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }        async fetchDeals(query) {          this.showLoading();          this.deals = [];          this.displayLimit = this.getRowsLimit();                    try {            console.log("getViewMode returns:", this.getViewMode());            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad();            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query);               } else {                 await this.fetchHawkDeals(query);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const siteParam = this.website || 'tomsguide';            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=${siteParam}&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (!this.activeDealTag && this.currentQuery) {             const tagMatch = this.airedaleTags.find(t => t.toLowerCase() === this.currentQuery.toLowerCase());             if (tagMatch) {                this.activeDealTag = tagMatch;             }          }          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const siteParam = this.website || 'tomsguide';             const url = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let seenUrls = new Set();                    let overallBrandsCounts = {};                    // First pass: extract ALL brands from topArticles so the dropdown has all options          topArticles.forEach((article) => {             if (!article.articlepage) return;             let pageData = [];             try { pageData = JSON.parse(article.articlepage[0]); } catch(e){ console.warn(e); }             const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');             savingsSquad.forEach((block) => {                const data = block.data || {};                if (data.brand) {                   const cleanBrand = data.brand.replace(/^\d+\.\s*/, '').trim();                   overallBrandsCounts[cleanBrand] = (overallBrandsCounts[cleanBrand] || 0) + 1;                }             });          });          targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = this.decodeHTML(description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim());                summaryTitle = this.decodeHTML(summaryTitle);                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                if (externalUrl) {                   if (seenUrls.has(externalUrl)) return;                  seenUrls.add(externalUrl);                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || '',                   authorName: article.articleauthortext ? article.articleauthortext[0] : (article.articleauthor ? article.articleauthor[0] : ''),                   authorRole: article.articleauthorrole ? article.articleauthorrole[0] : '',                   authorImage: article.articleauthormedia ? article.articleauthormedia[0] : '',                   documentUrl: article.documenturl ? article.documenturl[0] : '',                   modifiedDate: article.contentmodifieddate || article.modifieddate || ''                });             });          });                    const airedaleBrandsList = Object.keys(overallBrandsCounts).map(b => ({              formatted_value: b,              count: overallBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    url.searchParams.append('rows', this.getRowsLimit().toString());          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = this.getRowsLimit();          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.getFilteredDeals().slice(0, this.displayLimit), this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: this.decodeHTML(item.name || item.title || item.model_name || item.product_name || 'Unknown Product'),            brand: this.decodeHTML(item.brand || ''),            productName: this.decodeHTML(item.model_name || item.product_name || item.name || ''),            merchant: this.decodeHTML(item.merchant_name || item.merchant || item.retailer || 'Retailer'),            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : 'date_desc';          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                ${_div}              ${_div}              \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin:0; border-radius:0;">${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const finalHref = btn.href || btn.getAttribute('href') || '';                let actualRevenueId = btn.getAttribute('data-revenue-id');                const revMatch = finalHref.match(/(?:subId1|xcust|clickref|ascsubtag)=[^&]*?(\d{18,20})(?:&|$)/i);                if (revMatch && revMatch[1]) {                  actualRevenueId = revMatch[1];                }                const rewrittenLink = finalHref;                const revenueId = actualRevenueId;                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)}${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = 'View Deal';              if (isSavingsSquadMode) {                priceGroupHtml = ``;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = isSavingsSquadMode ? `` : `                \x3Cdiv class="tg-df-card-price-group">                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                          \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                          \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                            var c = this.parentNode;                            if (this.dataset.expanded === 'true') {                              var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                              if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                              pd.style.display = '-webkit-box';                              pd.style.webkitLineClamp = '3';                              this.textContent = 'READ MORE';                              this.style.position = 'absolute';                              this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                              this.style.paddingLeft = '16px';                              this.dataset.expanded = 'false';                            } else {                              var pd = this.previousElementSibling;                              pd.style.display = 'inline';                              pd.style.webkitLineClamp = 'unset';                              this.textContent = 'READ LESS';                              this.style.position = 'static';                              this.style.background = 'transparent';                              this.style.paddingLeft = '4px';                              this.dataset.expanded = 'true';                              pd.appendChild(this);                            }                          ">READ MORE${_button}                        \x3C/div>` : ''}                      ${_div}                    ${_div}                    ${deal.authorName ? `                      \x3Cdiv class="tg-df-author-line-mobile" style="padding: 0 0 12px 0; background: transparent;">                         \x3Cdiv style="display: flex; align-items: center; gap: 12px;">                            ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="40" height="40" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 40px; min-height: 40px;">` : ''}                            \x3Cdiv style="display: flex; flex-direction: column;">                               \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">\x3Cspan style="color: #FF6600;">${this.escapeHTML(deal.merchant)}${_span} deal recommended by:${_div}                               \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.3;">                                  \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                  ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                  ${deal.modifiedDate ? `\x3Cdiv style="color: var(--tg-df-text-muted); margin-top: 2px;">${getTimeAgo(deal.modifiedDate)}${_div}` : ''}                               ${_div}                            ${_div}                         ${_div}                      ${_div}                    ` : ''}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>View Deal${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                  \x3Cdiv class="tg-df-card-merchant-wrapper" style="position: absolute; bottom: 0; right: 0; background: transparent; padding: 8px 12px; z-index: 10;">                     \x3Cspan class="tg-df-card-merchant-pill" style="text-align: right; margin-bottom: 0;" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cdiv class="tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                    \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                    \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                      var c = this.parentNode;                      if (this.dataset.expanded === 'true') {                        var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                        if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                        pd.style.display = '-webkit-box';                        pd.style.webkitLineClamp = '3';                        this.textContent = 'READ MORE';                        this.style.position = 'absolute';                        this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                        this.style.paddingLeft = '16px';                        this.dataset.expanded = 'false';                      } else {                        var pd = this.previousElementSibling;                        pd.style.display = 'inline';                        pd.style.webkitLineClamp = 'unset';                        this.textContent = 'READ LESS';                        this.style.position = 'static';                        this.style.background = 'transparent';                        this.style.paddingLeft = '4px';                        this.dataset.expanded = 'true';                        pd.appendChild(this);                      }                    ">READ MORE${_button}                  \x3C/div>` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${deal.authorName ? `                    \x3Cdiv class="tg-df-author-line-desktop" style="padding: 0 0 ${isSavingsSquadMode ? 0 : 12}px 0;">                       \x3Cdiv style="display: flex; align-items: center; gap: 10px;">                          ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="36" height="36" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 36px; min-height: 36px;">` : ''}                          \x3Cdiv style="display: flex; flex-direction: column;">                             \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">Recommended by:${_div}                             \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.2;">                                \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                ${deal.modifiedDate ? `\x3Cspan style="color: var(--tg-df-text-muted);"> • ${getTimeAgo(deal.modifiedDate)}${_span}` : ''}                             ${_div}                          ${_div}                       ${_div}                    ${_div}                    ` : ''}                    ${priceGroupHtml}                  ${_div}                ${_div}                \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta" style="text-decoration: none; border-radius: 0;">${ctaText}${_a}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit) {            dealsHtml += `              \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer;">Load More${_button}              ${_div}            `;          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }          setTimeout(() => {            const contents = this.root.querySelectorAll('.tg-df-card-desc-content');            contents.forEach(p => {              if (p.scrollHeight > p.clientHeight || p.scrollHeight > 60) {                if (p.nextElementSibling) {                  p.nextElementSibling.style.display = 'block';                }              }            });                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));          }, 50);          const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              this.displayLimit += this.getRowsLimit();              this.render();            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Shark just launched its latest 2-in-1 robot vac that could put our current best budget pick on notice ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Shark is well-versed in making robot vacuums. Its even made one of the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuums</a> we've ever tested, the <a href="https://www.tomsguide.com/home/smart-home/shark-powerdetect-uv-reveal-robot-vacuum-review">Shark PowerDetect UV Reveal</a>. But, that doesn't mean it's resting on its laurels.</p><p>While you may have already heard of the Shark Navigator, an existing range with both an upright vacuum and robot vacuum in its collection, it's Shark's latest release that takes the Navigator to the next level.</p><p>The newest product in the lineup is the Shark Navigator 2-in-1 Robot Vacuum and Mop. Yes, it's a mouthful, but it's also a declaration of exactly <em>what</em> this new robot vacuum is capable of, cleaning up household messes left, right and center.</p><p>And while the <a href="https://www.tomsguide.com/home/smart-home/the-us-government-just-banned-almost-all-robot-vacuums-heres-why">US government is considering bans on almost all robot vacuums</a>, SharkNinja was happy to tell us at the time: "Regarding future models, we are evaluating our best options, but as a U.S.-based company we believe we are well positioned to navigate the process to continue to launch new models at competitive prices as we always have." And it turns out, they were right. Here's what's pretty cool about its newest model.</p><div class="product"><a data-dimension112="f8cd8284-bb38-11f1-b940-75fb13bf0031" data-action="Deal Block" data-label="Navigator 2-in-1 Robot Vacuum and Mop" data-dimension48="Navigator 2-in-1 Robot Vacuum and Mop" data-dimension25="$499.99" href="https://www.sharkninja.com/shark-navigator-2-in-1-robot-vacuum-mop/RVA120E2.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="puqW4S7qwCDucpaTKvYtCW" name="shark_navigator_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/puqW4S7qwCDucpaTKvYtCW-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Shark Navigator 2-in-1 Robot Vacuum and Mop aims to make cleaning up your home as easy and smooth as possible. With a simple setup, it'll vacuum, mop and even clean itself up when its done, thanks to a self-empty, bagless base. But, what's most impressive about the Shark Navigator is what the name suggests, its onboard navigational tech, meaning it can make its way around your home like never before.<a class="view-deal button" href="https://www.sharkninja.com/shark-navigator-2-in-1-robot-vacuum-mop/RVA120E2.html" target="_blank" rel="nofollow" data-dimension112="f8cd8284-bb38-11f1-b940-75fb13bf0031" data-action="Deal Block" data-label="Navigator 2-in-1 Robot Vacuum and Mop" data-dimension48="Navigator 2-in-1 Robot Vacuum and Mop" data-dimension25="$499.99">View Deal</a></p></div><h2 id="meet-the-new-shark-navigator">Meet the new Shark Navigator </h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="dsksibeQhdCA6XYswwMdNN" name="shark_navigator_2" alt="The Shark Navigator 2-in-1 Robot Vacuum and Mop" src="https://cdn.mos.cms.futurecdn.net/dsksibeQhdCA6XYswwMdNN-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shark)</span></figcaption></figure><p>Of course, you want to know how well the Shark Navigator 2-in-1 Robot Vacuum and Mop <em>cleans</em>, but before I get to that, I think it's important to talk about how it makes its way around your home.</p><p>It's a hard task for any robot vacuum to navigate the changing landscapes, tangled up wires, sudden corners and the day-to-day mess across your home. But, the Shark Navigator is capable of cleaning after just one click, which means you can use it pretty much straight out of the box.</p><p>How? Well, it uses 360-degree LiDAR mapping alongside Shark's very own SmartPath Max Navigation to guide methodically, row by row across your home. You can even check out the maps on the SharkClean app, setting no-go zones and scheduling cleans without having to lift a finger. Okay, one finger, to press the app.</p><p>As Alex Forman, Director of Marketing at SharkNinja puts it: "People want a cleaner home with less effort, and that's what Navigator is all about. It brings powerful Shark vacuuming and mopping performance together with simple setup and automatic emptying, making it easier to let a robot take on the daily cleaning."</p><p>That powerful vacuuming has 4x the suction of one of our favorite budget robot vacuums, the <a href="https://www.tomsguide.com/home/dreame-d10-plus-gen-2-review">Dreame D10 Plus Gen 2</a> and mopping that'll deliver 2x better stain cleaning than the Roomba 105 Combo (so SharkNinja says — we'll need to test to find out). It'll even automatically avoid carpets and rugs when in mop mode to keep them dry, as well as cleaning up hairs with a self-cleaning brush roll.</p><p>And, like I said, once its cleaned your home, it'll clean itself by emptying into a bagless base that'll hold debris for 30 or 60 days. I'm certainly up for a robot cleaning my home with little effort from me, but I'll wait to pass my full judgment until we get our hands on one for a review.</p><h2 id="availability-2">Availability</h2><p>The Shark Navigator 2-in-1 Robot Vacuum and Mop is available now, <a href="https://www.sharkninja.com/shark-navigator-2-in-1-robot-vacuum-mop/RVA120E2.html" target="_blank" rel="nofollow">starting at $499.99 from SharkNinja.com</a>. and will be available soon on Amazon, Costco, and Sam's Club. </p><p>Surprisingly, if you just get the Shark Navigator Robot Vacuum (no mopping), it'll only cost you $50 less at just $449.99. </p><p>The Shark Navigator® 2-in-1 Robot Vacuum and Mop with a 60-day bagless base ($599 model) launched today on <a href="https://www.sharkninja.com/shark-navigator-2-in-1-robot-vacuum-mop/RVA120E2.html" target="_blank" rel="nofollow">SharkNinja.com</a> and will be coming soon to Amazon. </p><p>The Shark Navigator range is clearly the budget-friendly option amongst Shark's robot vacuum lineup, with the other three options costing between $999.99 and $1299.99. And, when it comes to other 2-in-1 robot vacuums we've tested, its competitively priced amongst Dreame, iRobot, Roborock and more.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eGRoEX"></div>                            </div>                            <script src="https://kwizly.com/embed/eGRoEX.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/smart-home/i-just-tried-the-new-shark-powerdetect-robot-vacuum-and-this-one-upgrade-changes-everything">I just tried the new Shark PowerDetect robot vacuum — and this one upgrade changes everything</a></li><li><a href="https://www.tomsguide.com/home/which-shark-robot-vacuum-should-i-buy-how-to-pick-the-best-model-for-your-needs-and-budget">Which Shark robot vacuum should I buy? How to pick the best model for your needs and budget</a></li><li><a href="https://www.tomsguide.com/home/i-tried-sharks-new-misting-and-cooling-handheld-fan-but-is-the-chillpill-worth-the-hype">I tried Shark's new misting and cooling handheld fan, but is the ‘ChillPill’ worth the hype?</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/home-appliances/shark-just-launched-its-latest-2-in-1-robot-vac-that-could-put-our-current-best-budget-pick-on-notice</link>
                                                                            <description>
                            <![CDATA[ The Shark Navigator 2-in-1 Robot Vacuum and Mop is the brand's fifth addition to its robot vacuum line-up – but here's what's different about it. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">VRnrh5KadwJxZue7QnxUHn</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/qW3j4JYvRr7j5oZjSBaANN-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 29 Sep 2026 12:30:00 +0000</pubDate>                                                                                                                                <updated>Tue, 29 Sep 2026 16:23:11 +0000</updated>
                                                                                                                                            <category><![CDATA[Home Appliances]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/qW3j4JYvRr7j5oZjSBaANN-1920-80.jpg">
                                                            <media:credit><![CDATA[Shark]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Shark Navigator 2-in-1 Robot Vacuum and Mop]]></media:description>                                                            <media:text><![CDATA[The Shark Navigator 2-in-1 Robot Vacuum and Mop]]></media:text>
                                <media:title type="plain"><![CDATA[The Shark Navigator 2-in-1 Robot Vacuum and Mop]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/qW3j4JYvRr7j5oZjSBaANN-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Shark is well-versed in making robot vacuums. Its even made one of the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuums</a> we've ever tested, the <a href="https://www.tomsguide.com/home/smart-home/shark-powerdetect-uv-reveal-robot-vacuum-review">Shark PowerDetect UV Reveal</a>. But, that doesn't mean it's resting on its laurels.</p><p>While you may have already heard of the Shark Navigator, an existing range with both an upright vacuum and robot vacuum in its collection, it's Shark's latest release that takes the Navigator to the next level.</p><p>The newest product in the lineup is the Shark Navigator 2-in-1 Robot Vacuum and Mop. Yes, it's a mouthful, but it's also a declaration of exactly <em>what</em> this new robot vacuum is capable of, cleaning up household messes left, right and center.</p><p>And while the <a href="https://www.tomsguide.com/home/smart-home/the-us-government-just-banned-almost-all-robot-vacuums-heres-why">US government is considering bans on almost all robot vacuums</a>, SharkNinja was happy to tell us at the time: "Regarding future models, we are evaluating our best options, but as a U.S.-based company we believe we are well positioned to navigate the process to continue to launch new models at competitive prices as we always have." And it turns out, they were right. Here's what's pretty cool about its newest model.</p><div class="product"><a data-dimension112="f8cd8284-bb38-11f1-b940-75fb13bf0031" data-action="Deal Block" data-label="Navigator 2-in-1 Robot Vacuum and Mop" data-dimension48="Navigator 2-in-1 Robot Vacuum and Mop" data-dimension25="$499.99" href="https://www.sharkninja.com/shark-navigator-2-in-1-robot-vacuum-mop/RVA120E2.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="puqW4S7qwCDucpaTKvYtCW" name="shark_navigator_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/puqW4S7qwCDucpaTKvYtCW-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Shark Navigator 2-in-1 Robot Vacuum and Mop aims to make cleaning up your home as easy and smooth as possible. With a simple setup, it'll vacuum, mop and even clean itself up when its done, thanks to a self-empty, bagless base. But, what's most impressive about the Shark Navigator is what the name suggests, its onboard navigational tech, meaning it can make its way around your home like never before.<a class="view-deal button" href="https://www.sharkninja.com/shark-navigator-2-in-1-robot-vacuum-mop/RVA120E2.html" target="_blank" rel="nofollow" data-dimension112="f8cd8284-bb38-11f1-b940-75fb13bf0031" data-action="Deal Block" data-label="Navigator 2-in-1 Robot Vacuum and Mop" data-dimension48="Navigator 2-in-1 Robot Vacuum and Mop" data-dimension25="$499.99">View Deal</a></p></div><h2 id="meet-the-new-shark-navigator">Meet the new Shark Navigator </h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="dsksibeQhdCA6XYswwMdNN" name="shark_navigator_2" alt="The Shark Navigator 2-in-1 Robot Vacuum and Mop" src="https://cdn.mos.cms.futurecdn.net/dsksibeQhdCA6XYswwMdNN-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shark)</span></figcaption></figure><p>Of course, you want to know how well the Shark Navigator 2-in-1 Robot Vacuum and Mop <em>cleans</em>, but before I get to that, I think it's important to talk about how it makes its way around your home.</p><p>It's a hard task for any robot vacuum to navigate the changing landscapes, tangled up wires, sudden corners and the day-to-day mess across your home. But, the Shark Navigator is capable of cleaning after just one click, which means you can use it pretty much straight out of the box.</p><p>How? Well, it uses 360-degree LiDAR mapping alongside Shark's very own SmartPath Max Navigation to guide methodically, row by row across your home. You can even check out the maps on the SharkClean app, setting no-go zones and scheduling cleans without having to lift a finger. Okay, one finger, to press the app.</p><p>As Alex Forman, Director of Marketing at SharkNinja puts it: "People want a cleaner home with less effort, and that's what Navigator is all about. It brings powerful Shark vacuuming and mopping performance together with simple setup and automatic emptying, making it easier to let a robot take on the daily cleaning."</p><p>That powerful vacuuming has 4x the suction of one of our favorite budget robot vacuums, the <a href="https://www.tomsguide.com/home/dreame-d10-plus-gen-2-review">Dreame D10 Plus Gen 2</a> and mopping that'll deliver 2x better stain cleaning than the Roomba 105 Combo (so SharkNinja says — we'll need to test to find out). It'll even automatically avoid carpets and rugs when in mop mode to keep them dry, as well as cleaning up hairs with a self-cleaning brush roll.</p><p>And, like I said, once its cleaned your home, it'll clean itself by emptying into a bagless base that'll hold debris for 30 or 60 days. I'm certainly up for a robot cleaning my home with little effort from me, but I'll wait to pass my full judgment until we get our hands on one for a review.</p><h2 id="availability-2">Availability</h2><p>The Shark Navigator 2-in-1 Robot Vacuum and Mop is available now, <a href="https://www.sharkninja.com/shark-navigator-2-in-1-robot-vacuum-mop/RVA120E2.html" target="_blank" rel="nofollow">starting at $499.99 from SharkNinja.com</a>. and will be available soon on Amazon, Costco, and Sam's Club. </p><p>Surprisingly, if you just get the Shark Navigator Robot Vacuum (no mopping), it'll only cost you $50 less at just $449.99. </p><p>The Shark Navigator® 2-in-1 Robot Vacuum and Mop with a 60-day bagless base ($599 model) launched today on <a href="https://www.sharkninja.com/shark-navigator-2-in-1-robot-vacuum-mop/RVA120E2.html" target="_blank" rel="nofollow">SharkNinja.com</a> and will be coming soon to Amazon. </p><p>The Shark Navigator range is clearly the budget-friendly option amongst Shark's robot vacuum lineup, with the other three options costing between $999.99 and $1299.99. And, when it comes to other 2-in-1 robot vacuums we've tested, its competitively priced amongst Dreame, iRobot, Roborock and more.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eGRoEX"></div>                            </div>                            <script src="https://kwizly.com/embed/eGRoEX.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/smart-home/i-just-tried-the-new-shark-powerdetect-robot-vacuum-and-this-one-upgrade-changes-everything">I just tried the new Shark PowerDetect robot vacuum — and this one upgrade changes everything</a></li><li><a href="https://www.tomsguide.com/home/which-shark-robot-vacuum-should-i-buy-how-to-pick-the-best-model-for-your-needs-and-budget">Which Shark robot vacuum should I buy? How to pick the best model for your needs and budget</a></li><li><a href="https://www.tomsguide.com/home/i-tried-sharks-new-misting-and-cooling-handheld-fan-but-is-the-chillpill-worth-the-hype">I tried Shark's new misting and cooling handheld fan, but is the ‘ChillPill’ worth the hype?</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The real reason hummingbirds fight at your feeder (and how to bring peace to your yard) ]]></title>
                                                                                                <dc:content><![CDATA[ <p>One second, a tiny ruby-throated hummingbird is peacefully sipping nectar at your window. The next, a flash of iridescent feathers dives out of nowhere, chasing the innocent visitor out of the yard like an angry jet fighter.</p><p>If your backyard hummingbird station feels more like a miniature aerial battleground than a tranquil garden retreat, you aren't alone. Watching these tiny creatures bully each other can feel alarming, but understanding <em>why</em> they fight is the key to creating a calm, welcoming space for every bird in your neighborhood.</p><p>Here is the territorial instinct driving hummingbird feuds — and the smart feeder setup that restores peace to your backyard. </p><h3 class="article-body__section" id="section-why-hummingbirds-fight-over-sugar-water"><span>Why hummingbirds fight over sugar water</span></h3><p>Despite weighing less than a coin, hummingbirds are among the most intensely aggressive creatures in the avian world. Their territorial hostility isn't personal, it is a survival instinct driven by three core factors:</p><section class="howto-block">                    <h3>1. Burn-it-all metabolisms</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/gLRRPW6tMpzSrpSkNKBeHR.jpg"                                        alt="Hummingbird on red valerian plant"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/gLRRPW6tMpzSrpSkNKBeHR.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>A hummingbird's heart beats up to 1,200 times per minute, requiring them to consume vast amounts of nectar daily just to survive. Because energy is a constant life-or-death priority, securing a reliable food source is vital. When a bird spots a rich nectar source, its brain views that area as a high-value asset worth defending at all costs.</p></p>                </section><section class="howto-block">                    <h3>2. The "single flower" delusion </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/jyfqJzPybUx5W8CPbFEXsU.jpg"                                        alt="Hummingbird and feeder"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/jyfqJzPybUx5W8CPbFEXsU.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>In nature, wild nectar sources are scattered across fields and patches of tubular flowers. A garden feeder, however, represents a massive, concentrated bounty of food sitting in one exact spot. </p><p>Male hummingbirds naturally treat a single feeder the way they would treat a prized patch of wild blossoms: a clear territory boundary that must be aggressively guarded from rivals.</p></p>                </section><div class="product"><a data-dimension112="231a4364-b82e-11f1-929f-2d8bb56bcdd1" data-action="Deal Block" data-label="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension48="Hummingbird nectar feeders: from $9 @ Amazon" href="https://www.amazon.com/s?k=hummingbird+nectar+feeder" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1458px;"><p class="vanilla-image-block" style="padding-top:102.88%;"><img id="ogW9bnqBs2aZzviXhZJ7bT" name="Hummingbird feeder" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ogW9bnqBs2aZzviXhZJ7bT-1920-80.jpg" mos="" align="middle" fullscreen="" width="1458" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong>Hummingbird nectar feeders: </strong><a href="https://www.amazon.com/s?k=hummingbird+nectar+feeder" target="_blank" rel="nofollow" data-dimension112="231a4364-b82e-11f1-929f-2d8bb56bcdd1" data-action="Deal Block" data-label="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension48="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension25=""><strong>from $9 @ Amazon</strong></a><br />Amazon has a wide selection of hanging bird feeders that are easy to hang/reposition and durable. Prices start as low as $7 for feeders with five feeding ports and more.<a class="view-deal button" href="https://www.amazon.com/s?k=hummingbird+nectar+feeder" target="_blank" rel="nofollow" data-dimension112="231a4364-b82e-11f1-929f-2d8bb56bcdd1" data-action="Deal Block" data-label="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension48="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension25="">View Deal</a></p></div><section class="howto-block">                    <h3>3. Species temperament</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/8myAukCyP3zoJuyMthiAyQ.jpg"                                        alt="Hummingbird enjoying water fountain"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/8myAukCyP3zoJuyMthiAyQ.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>While all species exhibit territorial traits, certain birds (like Rufous and Allen's hummingbirds) are notoriously combative. Individual temperaments vary, but a single dominant bully will often park on a high perch nearby, spending all day watching a feeder just to attack any bird brave enough to take a drink.</p></p>                </section><h3 class="article-body__section" id="section-how-to-stop-feeder-feuds-without-chasing-away-the-birds"><span>How to stop feeder feuds (without chasing away the birds)</span></h3><p>Trying to shoo away a dominant bully or moving your feeder around every time a fight breaks out will only stress out the birds. Instead, the real solution comes down to visual obstruction and strategic layout.</p><section class="howto-block">                    <h3>Break line of sight between feeders</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/X5HkpvaHeR595HnnvzeSNJ.jpg"                                        alt="Red ribbon around feeder"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/X5HkpvaHeR595HnnvzeSNJ.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>The biggest mistake homeowners make is hanging two or three feeders on the same porch or shepherd's hook. A bully bird can easily guard every port at once if they are grouped together.</p><p>Instead,<strong> spread multiple feeders across your property in spots where they cannot see each other</strong>. </p><p>If a territorial bird is perching on a branch watching Feeder A, place Feeder B around the corner of your house, behind a shed, or on the opposite side of a dense bush. A bully cannot defend what it cannot see.</p></p>                </section><section class="howto-block">                    <h3>Plant native tubular flowers</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/MLfMKiv3hk8fynyB2aNnwF.png"                                        alt="Hummingbirds feeding from tubular flowers"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/MLfMKiv3hk8fynyB2aNnwF.png"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>The most effective way to take pressure off your artificial feeders is to offer natural alternatives throughout your yard. <strong>Planting native nectar-rich flowers spreads out feeding opportunities</strong>. This disperses the birds across the garden, making it impossible for one dominant bully to hoard all the food.</p></p>                </section><section class="howto-block">                    <h3>Tuck feeders into shady, dense foliage</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/agdtUiiJ9qrmUeVwCN9AmF.jpg"                                        alt="Hummingbird feeder"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/agdtUiiJ9qrmUeVwCN9AmF.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Hanging a feeder out in the open middle of a flat lawn makes it an easy target for aerial patrols.<strong> </strong></p><p><strong>Tucking feeders near or inside native shrubs, leafy trees, or dense garden beds gives submissive birds natural cover</strong> to sneak in for a quick drink undetected. Shade also prevents sugar water from heating up and spoiling rapidly.</p></p>                </section><p>While territorial chasing is largely harmless, improper feeder setup and maintenance pose severe threats to hummingbirds. </p><p>Prevent fatal window collisions by <strong>placing feeders within 3 feet or beyond 30 feet of glass</strong>, avoiding clear visual "tunnels" through the home. Protect against fatal infections by <strong>feeding only a simple </strong><a href="https://www.tomsguide.com/home/outdoors/how-to-feed-hummingbirds-the-right-way-according-to-experts"><strong>1:4 white sugar to water ratio</strong></a> — never red dyes or honey. </p><p>And prevent toxic mold by <strong>cleaning feeders every 1 to 3 days,</strong> replacing extra feeders with low-maintenance native perennials if upkeep becomes overwhelming.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-W0EvNO"></div>                            </div>                            <script src="https://kwizly.com/embed/W0EvNO.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/hummingbirds-are-getting-ready-to-migrate-3-things-you-must-do-in-your-yard-right-now">How to help hummingbirds prepare for fall migration — 3 essential yard tweaks to do right now</a></li><li><a href="https://www.tomsguide.com/home/gardening/never-use-bleach-in-your-birdbath-this-usd1-pantry-staple-is-safer-and-more-effective">Never use bleach in your birdbath — this cheap pantry staple is safer and more effective</a></li><li><a href="https://www.tomsguide.com/home/want-more-hummingbirds-7-tips-for-attracting-them-to-your-yard">Want more hummingbirds? 7 tips for attracting them to your yard</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/the-real-reason-hummingbirds-fight-at-your-feeder-and-how-to-bring-peace-to-your-yard</link>
                                                                            <description>
                            <![CDATA[ Why hummingbirds chase each other away from feeders, and how to fix it. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">mkXni2NGQKdPToEqVytPG8</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/5osssoEKuX8A7LDLLPng9L-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 27 Sep 2026 12:30:00 +0000</pubDate>                                                                                                                                <updated>Mon, 28 Sep 2026 10:15:55 +0000</updated>
                                                                                                                                            <category><![CDATA[Home]]></category>
                                                                                                <author><![CDATA[ kaycee.hill@futurenet.com (Kaycee Hill) ]]></author>                    <dc:creator><![CDATA[ Kaycee Hill ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/xHn6RmpEqg87cvtLwrBu9G-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/5osssoEKuX8A7LDLLPng9L-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                        <media:description><![CDATA[Hummingbird and lilac flower]]></media:description>                                                            <media:text><![CDATA[Hummingbirds at feeder]]></media:text>
                                <media:title type="plain"><![CDATA[Hummingbirds at feeder]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/5osssoEKuX8A7LDLLPng9L-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>One second, a tiny ruby-throated hummingbird is peacefully sipping nectar at your window. The next, a flash of iridescent feathers dives out of nowhere, chasing the innocent visitor out of the yard like an angry jet fighter.</p><p>If your backyard hummingbird station feels more like a miniature aerial battleground than a tranquil garden retreat, you aren't alone. Watching these tiny creatures bully each other can feel alarming, but understanding <em>why</em> they fight is the key to creating a calm, welcoming space for every bird in your neighborhood.</p><p>Here is the territorial instinct driving hummingbird feuds — and the smart feeder setup that restores peace to your backyard. </p><h3 class="article-body__section" id="section-why-hummingbirds-fight-over-sugar-water"><span>Why hummingbirds fight over sugar water</span></h3><p>Despite weighing less than a coin, hummingbirds are among the most intensely aggressive creatures in the avian world. Their territorial hostility isn't personal, it is a survival instinct driven by three core factors:</p><section class="howto-block">                    <h3>1. Burn-it-all metabolisms</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/gLRRPW6tMpzSrpSkNKBeHR.jpg"                                        alt="Hummingbird on red valerian plant"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/gLRRPW6tMpzSrpSkNKBeHR.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>A hummingbird's heart beats up to 1,200 times per minute, requiring them to consume vast amounts of nectar daily just to survive. Because energy is a constant life-or-death priority, securing a reliable food source is vital. When a bird spots a rich nectar source, its brain views that area as a high-value asset worth defending at all costs.</p></p>                </section><section class="howto-block">                    <h3>2. The "single flower" delusion </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/jyfqJzPybUx5W8CPbFEXsU.jpg"                                        alt="Hummingbird and feeder"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/jyfqJzPybUx5W8CPbFEXsU.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>In nature, wild nectar sources are scattered across fields and patches of tubular flowers. A garden feeder, however, represents a massive, concentrated bounty of food sitting in one exact spot. </p><p>Male hummingbirds naturally treat a single feeder the way they would treat a prized patch of wild blossoms: a clear territory boundary that must be aggressively guarded from rivals.</p></p>                </section><div class="product"><a data-dimension112="231a4364-b82e-11f1-929f-2d8bb56bcdd1" data-action="Deal Block" data-label="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension48="Hummingbird nectar feeders: from $9 @ Amazon" href="https://www.amazon.com/s?k=hummingbird+nectar+feeder" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1458px;"><p class="vanilla-image-block" style="padding-top:102.88%;"><img id="ogW9bnqBs2aZzviXhZJ7bT" name="Hummingbird feeder" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ogW9bnqBs2aZzviXhZJ7bT-1920-80.jpg" mos="" align="middle" fullscreen="" width="1458" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong>Hummingbird nectar feeders: </strong><a href="https://www.amazon.com/s?k=hummingbird+nectar+feeder" target="_blank" rel="nofollow" data-dimension112="231a4364-b82e-11f1-929f-2d8bb56bcdd1" data-action="Deal Block" data-label="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension48="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension25=""><strong>from $9 @ Amazon</strong></a><br />Amazon has a wide selection of hanging bird feeders that are easy to hang/reposition and durable. Prices start as low as $7 for feeders with five feeding ports and more.<a class="view-deal button" href="https://www.amazon.com/s?k=hummingbird+nectar+feeder" target="_blank" rel="nofollow" data-dimension112="231a4364-b82e-11f1-929f-2d8bb56bcdd1" data-action="Deal Block" data-label="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension48="Hummingbird nectar feeders: from $9 @ Amazon" data-dimension25="">View Deal</a></p></div><section class="howto-block">                    <h3>3. Species temperament</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/8myAukCyP3zoJuyMthiAyQ.jpg"                                        alt="Hummingbird enjoying water fountain"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/8myAukCyP3zoJuyMthiAyQ.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>While all species exhibit territorial traits, certain birds (like Rufous and Allen's hummingbirds) are notoriously combative. Individual temperaments vary, but a single dominant bully will often park on a high perch nearby, spending all day watching a feeder just to attack any bird brave enough to take a drink.</p></p>                </section><h3 class="article-body__section" id="section-how-to-stop-feeder-feuds-without-chasing-away-the-birds"><span>How to stop feeder feuds (without chasing away the birds)</span></h3><p>Trying to shoo away a dominant bully or moving your feeder around every time a fight breaks out will only stress out the birds. Instead, the real solution comes down to visual obstruction and strategic layout.</p><section class="howto-block">                    <h3>Break line of sight between feeders</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/X5HkpvaHeR595HnnvzeSNJ.jpg"                                        alt="Red ribbon around feeder"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/X5HkpvaHeR595HnnvzeSNJ.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>The biggest mistake homeowners make is hanging two or three feeders on the same porch or shepherd's hook. A bully bird can easily guard every port at once if they are grouped together.</p><p>Instead,<strong> spread multiple feeders across your property in spots where they cannot see each other</strong>. </p><p>If a territorial bird is perching on a branch watching Feeder A, place Feeder B around the corner of your house, behind a shed, or on the opposite side of a dense bush. A bully cannot defend what it cannot see.</p></p>                </section><section class="howto-block">                    <h3>Plant native tubular flowers</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/MLfMKiv3hk8fynyB2aNnwF.png"                                        alt="Hummingbirds feeding from tubular flowers"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/MLfMKiv3hk8fynyB2aNnwF.png"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>The most effective way to take pressure off your artificial feeders is to offer natural alternatives throughout your yard. <strong>Planting native nectar-rich flowers spreads out feeding opportunities</strong>. This disperses the birds across the garden, making it impossible for one dominant bully to hoard all the food.</p></p>                </section><section class="howto-block">                    <h3>Tuck feeders into shady, dense foliage</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/agdtUiiJ9qrmUeVwCN9AmF.jpg"                                        alt="Hummingbird feeder"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/agdtUiiJ9qrmUeVwCN9AmF.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Hanging a feeder out in the open middle of a flat lawn makes it an easy target for aerial patrols.<strong> </strong></p><p><strong>Tucking feeders near or inside native shrubs, leafy trees, or dense garden beds gives submissive birds natural cover</strong> to sneak in for a quick drink undetected. Shade also prevents sugar water from heating up and spoiling rapidly.</p></p>                </section><p>While territorial chasing is largely harmless, improper feeder setup and maintenance pose severe threats to hummingbirds. </p><p>Prevent fatal window collisions by <strong>placing feeders within 3 feet or beyond 30 feet of glass</strong>, avoiding clear visual "tunnels" through the home. Protect against fatal infections by <strong>feeding only a simple </strong><a href="https://www.tomsguide.com/home/outdoors/how-to-feed-hummingbirds-the-right-way-according-to-experts"><strong>1:4 white sugar to water ratio</strong></a> — never red dyes or honey. </p><p>And prevent toxic mold by <strong>cleaning feeders every 1 to 3 days,</strong> replacing extra feeders with low-maintenance native perennials if upkeep becomes overwhelming.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-W0EvNO"></div>                            </div>                            <script src="https://kwizly.com/embed/W0EvNO.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/hummingbirds-are-getting-ready-to-migrate-3-things-you-must-do-in-your-yard-right-now">How to help hummingbirds prepare for fall migration — 3 essential yard tweaks to do right now</a></li><li><a href="https://www.tomsguide.com/home/gardening/never-use-bleach-in-your-birdbath-this-usd1-pantry-staple-is-safer-and-more-effective">Never use bleach in your birdbath — this cheap pantry staple is safer and more effective</a></li><li><a href="https://www.tomsguide.com/home/want-more-hummingbirds-7-tips-for-attracting-them-to-your-yard">Want more hummingbirds? 7 tips for attracting them to your yard</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Fall into a fresher home — 5 easy ways to reset your home this season ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Undoubtedly you've heard about doing a spring clean, but what about fall? Sure, spring is a great time of year to give your house a clean up ready for the warmer months ahead – and yes, it's definitely a catchier phrase than a fall clean. </p><p>But we're missing a trick. Fall cleaning should be just as important.</p><p>In fact, I'd argue that fall cleaning is even more pressing than spring cleaning. After a busy summer, our homes are begging for a deep clean (at least mine certainly is), and it's also just the perfect time to prepare your house for longer, cozy nights in, as well as setting up for all that Thanksgiving and Christmas hosting.</p><p>I also love to fall clean, declutter, and tidy up my busy household, ready for any new items that might arrive over the festive period. </p><p>Ultimately, adding fall cleaning to my seasonal list of chores has been a game-changer, and I recommend it to anyone who wants to hear it. </p><p>As a homes writer, I've found <em>a lot</em> of handy tips over the years that I now put into action specifically in fall. Here are my top 5 tips I want to share to make your fall clean the ultimate reset.</p><h2 id="1-39-chaos-decluttering-39">1. 'Chaos decluttering'</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="nAmUFdvDYszbcvqatkivpc" name="chaos_declutter_2" alt="A pile of clothes, towels and bags" src="https://cdn.mos.cms.futurecdn.net/nAmUFdvDYszbcvqatkivpc-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Earlier this year, I tried<a href="https://www.tomsguide.com/home/i-tried-chaos-decluttering-for-the-ultimate-spring-clean-and-heres-why-i-wish-id-done-it-sooner"> 'chaos decluttering' to spring clean my home</a> – and I liked it so much, I'm using it for fall. </p><p>Essentially, as Kim Jones of <a href="https://www.lkhomeorganization.com/" target="_blank">Lock and Key Home</a> coined the method, you create chaos in your home by pulling everything out of a messy area (and I mean <em>everything)</em> before sorting, organizing, and putting it away.</p><p>The idea of making more mess might make you cringe, but trust me, it works wonders when you face your clutter head-on. </p><p>You don't have to carry out this method for your entire house, but I'm using it to tidy up my baking cupboard and my wardrobe to sort through the summer clothes I know I didn't wear this year and won't wear next.</p><h2 id="2-clean-your-hallway">2. Clean your hallway</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3200px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="h22xDbagZWcvoGH7444nrU" name="shutterstock_2161764785 cluttered hallway" alt="Hallway clutter" src="https://cdn.mos.cms.futurecdn.net/h22xDbagZWcvoGH7444nrU-1920-80.jpg" mos="" align="middle" fullscreen="" width="3200" height="1800" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Fall is a popular time for hosting, whether it's Thanksgiving with all the family or a cozy night-in with friends. But, with more people coming and going, there's also a lot more muddy boots from the fall weather and a lot more clutter – especially in one area of your home, the hallway. </p><p>While I've previously encouraged Toms Guide readers on <a href="https://www.tomsguide.com/home/if-you-clean-one-area-this-new-year-make-it-your-hallway-decluttering-experts-share-the-5-things-you-should-get-rid-of-in-january">why you should clean your hallway in January</a> to begin the New Year with a fresh start, it's definitely ready for another deep scrub in fall.</p><p>First, I tackle the amount of shoes that have gathered over the year, then the bags and coats ready to accommodate the larger, bulkier coats for the winter and then I streamline the amount of general clutter and overwhelming storage.</p><p>It might seem like a good idea to have boxes of items in your hallway for you to grab from, but it'll quickly turn into piles of mess meaning guests haven't got anywhere to put their things.</p><h2 id="3-deep-clean-your-oven">3. Deep clean your oven</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UC5UBbmdmqNxKrEeBVgBhF" name="oven_cleaning_hack_2" alt="Rubber gloves, Cif and cling wrap on a surface" src="https://cdn.mos.cms.futurecdn.net/UC5UBbmdmqNxKrEeBVgBhF-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Alongside a good clean of your entire kitchen (and home) during fall, you should pay close attention to your oven. </p><p>It's going to get a lot more use over the fall period, especially for making hot meals to enjoy during the colder weather. But you may have accidentally neglected cleaning it over a busy summer.</p><p>Fortunately, <a href="https://www.tomsguide.com/home/kitchen-dining/i-tried-this-oven-cleaning-hack-using-two-household-items-i-already-own-and-i-was-surprised-by-the-results">I tried an oven cleaning hack using two household items I already own,</a> and it worked wonders. Not only is it really simple, but it's also super budget-friendly. All you need is a bottle of Cif Cream and some cling wrap. </p><p>You apply the Cif Cream to your oven door, leaving it open and covering it in cling wrap. Then, leave it for around an hour (though I had to leave it a fair while longer for stubborn stains) and wipe it off.</p><p>Then, popping all those finger foods for hosting and those tasty leftovers for an easy fall night meal can all happen in a lovely clean oven.</p><h2 id="4-try-the-39-moving-out-39-decluttering-method">4. Try the 'moving out' decluttering method</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3600px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="m3EqjFxJ85h33Q3RdYbrZk" name="shutterstock_2273745883 moving boxes in a wooden hallway" alt="moving boxes in a wooden hallway" src="https://cdn.mos.cms.futurecdn.net/m3EqjFxJ85h33Q3RdYbrZk-1920-80.jpg" mos="" align="middle" fullscreen="" width="3600" height="2025" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>If you've found you've given your house a lovely clean, but you're still concerned about the amount of clutter filling the rooms, you might need to get a little more ruthless – and that's where the <a href="https://www.tomsguide.com/home/i-tried-the-moving-out-decluttering-method-and-it-brought-the-ultimate-cleaning-clarity">'moving out' decluttering method</a> comes in.</p><p>I moved last fall, and I wouldn't want to do it again anytime soon, but it was a really excellent way to make me cull my household items and something I'd seriously recommend incorporating into any fall cleaning routine.</p><p>You go from room to room looking at what you own and asking yourself whether you'd box up certain items if it was time for you to move. </p><p>If the answer is no, then it's not something you need to keep. It basically asks you to reframe your mind rather than just living with something because you're used to having it around.</p><h2 id="5-make-your-home-smell-like-fall">5. Make your home smell like fall</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@elnazhamai/video/7267999039998725419" data-video-id="7267999039998725419" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@elnazhamai" href="https://www.tiktok.com/@elnazhamai">@elnazhamai</a>                            <p></p><a target="_blank" title="♬ original sound - Elnaz Hamai" href="https://www.tiktok.com/music/original-sound-7267999033854102314">♬ original sound - Elnaz Hamai</a></section>                    </blockquote></div>                <p>Finally, while I'm a sucker for the pine-scented candles of the festive period, I also like to make my home smell like fall – and it's super simple and cost-effective.</p><p>Thanks to <a href="https://www.tiktok.com/@elnazhamai" target="_blank" rel="nofollow">@elnazhamai</a> on TikTok, I've been following one of the many amazing hacks she shared to her over 500k followers for the last few years to make the ultimate fall home deodorizers.</p><p>All you need to do is mix two cups of baking soda with 3/4 cup of water. Then, scoop this mixture into cupcake cases on a baking tray. Bake at 350°F for 20 minutes. </p><p>After they're fully cooled, add drops of essential oils to the ones you want to use. Each one lasts around three months, and you can keep the others in an airtight container. You can also reapply the oils to boost the scent.</p><p>Essential oils I like to choose for fall include cinnamon, cedarwood, ginger, vanilla, and blood orange, but you can use whatever scents you like. And then your home will be clean for fall and also smell just like it.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/avoid-the-fall-mold-trap-an-expert-shares-what-you-need-to-know-in-september-to-protect-your-home">Avoid the fall mold trap: An expert shares what you need to know in September to protect your home</a></li><li><a href="https://www.tomsguide.com/home/experts-say-you-should-declutter-these-7-things-in-october">Experts say you should declutter these 7 things in October</a></li><li><a href="https://www.tomsguide.com/home/stop-scrubbing-this-one-common-kitchen-item-is-all-your-toilet-needs-to-clean-itself">Stop scrubbing — this one common kitchen item is all your toilet needs to clean itself</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/fall-into-a-fresher-home-5-easy-ways-to-reset-your-home-this-season</link>
                                                                            <description>
                            <![CDATA[ Fall is the perfect time to get cozy indoors, but not if your home is feeling cluttered and messy. Here's the 5 top tips I follow every year for giving my house the ultimate fall reset. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">wsSdiYKKQuqynoaPzSVn3Z</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/NiXK8j4aaY9qMeUmxGheBC-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 24 Sep 2026 07:30:00 +0000</pubDate>                                                                                                                                <updated>Thu, 24 Sep 2026 18:12:25 +0000</updated>
                                                                                                                                            <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/NiXK8j4aaY9qMeUmxGheBC-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Fall decor in living room]]></media:description>                                                            <media:text><![CDATA[Fall decor in living room]]></media:text>
                                <media:title type="plain"><![CDATA[Fall decor in living room]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/NiXK8j4aaY9qMeUmxGheBC-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Undoubtedly you've heard about doing a spring clean, but what about fall? Sure, spring is a great time of year to give your house a clean up ready for the warmer months ahead – and yes, it's definitely a catchier phrase than a fall clean. </p><p>But we're missing a trick. Fall cleaning should be just as important.</p><p>In fact, I'd argue that fall cleaning is even more pressing than spring cleaning. After a busy summer, our homes are begging for a deep clean (at least mine certainly is), and it's also just the perfect time to prepare your house for longer, cozy nights in, as well as setting up for all that Thanksgiving and Christmas hosting.</p><p>I also love to fall clean, declutter, and tidy up my busy household, ready for any new items that might arrive over the festive period. </p><p>Ultimately, adding fall cleaning to my seasonal list of chores has been a game-changer, and I recommend it to anyone who wants to hear it. </p><p>As a homes writer, I've found <em>a lot</em> of handy tips over the years that I now put into action specifically in fall. Here are my top 5 tips I want to share to make your fall clean the ultimate reset.</p><h2 id="1-39-chaos-decluttering-39">1. 'Chaos decluttering'</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="nAmUFdvDYszbcvqatkivpc" name="chaos_declutter_2" alt="A pile of clothes, towels and bags" src="https://cdn.mos.cms.futurecdn.net/nAmUFdvDYszbcvqatkivpc-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Earlier this year, I tried<a href="https://www.tomsguide.com/home/i-tried-chaos-decluttering-for-the-ultimate-spring-clean-and-heres-why-i-wish-id-done-it-sooner"> 'chaos decluttering' to spring clean my home</a> – and I liked it so much, I'm using it for fall. </p><p>Essentially, as Kim Jones of <a href="https://www.lkhomeorganization.com/" target="_blank">Lock and Key Home</a> coined the method, you create chaos in your home by pulling everything out of a messy area (and I mean <em>everything)</em> before sorting, organizing, and putting it away.</p><p>The idea of making more mess might make you cringe, but trust me, it works wonders when you face your clutter head-on. </p><p>You don't have to carry out this method for your entire house, but I'm using it to tidy up my baking cupboard and my wardrobe to sort through the summer clothes I know I didn't wear this year and won't wear next.</p><h2 id="2-clean-your-hallway">2. Clean your hallway</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3200px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="h22xDbagZWcvoGH7444nrU" name="shutterstock_2161764785 cluttered hallway" alt="Hallway clutter" src="https://cdn.mos.cms.futurecdn.net/h22xDbagZWcvoGH7444nrU-1920-80.jpg" mos="" align="middle" fullscreen="" width="3200" height="1800" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Fall is a popular time for hosting, whether it's Thanksgiving with all the family or a cozy night-in with friends. But, with more people coming and going, there's also a lot more muddy boots from the fall weather and a lot more clutter – especially in one area of your home, the hallway. </p><p>While I've previously encouraged Toms Guide readers on <a href="https://www.tomsguide.com/home/if-you-clean-one-area-this-new-year-make-it-your-hallway-decluttering-experts-share-the-5-things-you-should-get-rid-of-in-january">why you should clean your hallway in January</a> to begin the New Year with a fresh start, it's definitely ready for another deep scrub in fall.</p><p>First, I tackle the amount of shoes that have gathered over the year, then the bags and coats ready to accommodate the larger, bulkier coats for the winter and then I streamline the amount of general clutter and overwhelming storage.</p><p>It might seem like a good idea to have boxes of items in your hallway for you to grab from, but it'll quickly turn into piles of mess meaning guests haven't got anywhere to put their things.</p><h2 id="3-deep-clean-your-oven">3. Deep clean your oven</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UC5UBbmdmqNxKrEeBVgBhF" name="oven_cleaning_hack_2" alt="Rubber gloves, Cif and cling wrap on a surface" src="https://cdn.mos.cms.futurecdn.net/UC5UBbmdmqNxKrEeBVgBhF-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Alongside a good clean of your entire kitchen (and home) during fall, you should pay close attention to your oven. </p><p>It's going to get a lot more use over the fall period, especially for making hot meals to enjoy during the colder weather. But you may have accidentally neglected cleaning it over a busy summer.</p><p>Fortunately, <a href="https://www.tomsguide.com/home/kitchen-dining/i-tried-this-oven-cleaning-hack-using-two-household-items-i-already-own-and-i-was-surprised-by-the-results">I tried an oven cleaning hack using two household items I already own,</a> and it worked wonders. Not only is it really simple, but it's also super budget-friendly. All you need is a bottle of Cif Cream and some cling wrap. </p><p>You apply the Cif Cream to your oven door, leaving it open and covering it in cling wrap. Then, leave it for around an hour (though I had to leave it a fair while longer for stubborn stains) and wipe it off.</p><p>Then, popping all those finger foods for hosting and those tasty leftovers for an easy fall night meal can all happen in a lovely clean oven.</p><h2 id="4-try-the-39-moving-out-39-decluttering-method">4. Try the 'moving out' decluttering method</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3600px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="m3EqjFxJ85h33Q3RdYbrZk" name="shutterstock_2273745883 moving boxes in a wooden hallway" alt="moving boxes in a wooden hallway" src="https://cdn.mos.cms.futurecdn.net/m3EqjFxJ85h33Q3RdYbrZk-1920-80.jpg" mos="" align="middle" fullscreen="" width="3600" height="2025" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>If you've found you've given your house a lovely clean, but you're still concerned about the amount of clutter filling the rooms, you might need to get a little more ruthless – and that's where the <a href="https://www.tomsguide.com/home/i-tried-the-moving-out-decluttering-method-and-it-brought-the-ultimate-cleaning-clarity">'moving out' decluttering method</a> comes in.</p><p>I moved last fall, and I wouldn't want to do it again anytime soon, but it was a really excellent way to make me cull my household items and something I'd seriously recommend incorporating into any fall cleaning routine.</p><p>You go from room to room looking at what you own and asking yourself whether you'd box up certain items if it was time for you to move. </p><p>If the answer is no, then it's not something you need to keep. It basically asks you to reframe your mind rather than just living with something because you're used to having it around.</p><h2 id="5-make-your-home-smell-like-fall">5. Make your home smell like fall</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@elnazhamai/video/7267999039998725419" data-video-id="7267999039998725419" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@elnazhamai" href="https://www.tiktok.com/@elnazhamai">@elnazhamai</a>                            <p></p><a target="_blank" title="♬ original sound - Elnaz Hamai" href="https://www.tiktok.com/music/original-sound-7267999033854102314">♬ original sound - Elnaz Hamai</a></section>                    </blockquote></div>                <p>Finally, while I'm a sucker for the pine-scented candles of the festive period, I also like to make my home smell like fall – and it's super simple and cost-effective.</p><p>Thanks to <a href="https://www.tiktok.com/@elnazhamai" target="_blank" rel="nofollow">@elnazhamai</a> on TikTok, I've been following one of the many amazing hacks she shared to her over 500k followers for the last few years to make the ultimate fall home deodorizers.</p><p>All you need to do is mix two cups of baking soda with 3/4 cup of water. Then, scoop this mixture into cupcake cases on a baking tray. Bake at 350°F for 20 minutes. </p><p>After they're fully cooled, add drops of essential oils to the ones you want to use. Each one lasts around three months, and you can keep the others in an airtight container. You can also reapply the oils to boost the scent.</p><p>Essential oils I like to choose for fall include cinnamon, cedarwood, ginger, vanilla, and blood orange, but you can use whatever scents you like. And then your home will be clean for fall and also smell just like it.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/avoid-the-fall-mold-trap-an-expert-shares-what-you-need-to-know-in-september-to-protect-your-home">Avoid the fall mold trap: An expert shares what you need to know in September to protect your home</a></li><li><a href="https://www.tomsguide.com/home/experts-say-you-should-declutter-these-7-things-in-october">Experts say you should declutter these 7 things in October</a></li><li><a href="https://www.tomsguide.com/home/stop-scrubbing-this-one-common-kitchen-item-is-all-your-toilet-needs-to-clean-itself">Stop scrubbing — this one common kitchen item is all your toilet needs to clean itself</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ No plastic, just coffee — how Caraway's first-ever coffee maker breaks the mold ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Caraway is well-known for its iconic non-toxic cookware, bakeware, utensils and even trash cans. But, what it's not so well-known for is its coffee makers. Why? Well, because it's never made one before. Until now.</p><p>And while that's big news in itself, what's <em>really</em> special about Caraway's first-ever entry into a busy<a href="https://www.tomsguide.com/home/coffee-makers/best-coffee-makers"> coffee maker</a> world is that it's taking its non-toxic ethos and planting it firmly into the brewing process. </p><p>In fact, the Caraway 10-Cup Coffee Maker has eliminated plastic from the brew path altogether. </p><p>Using a 'first-of-its-kind Clean Brew System', this coffee maker uses stainless steel and glass, meaning your coffee is brewed entirely plastic-free.  </p><p>For a drip coffee maker, that's a <em>pretty</em> big deal, unless you're planning to brew it all manually (which I'm certainly not).</p><div class="product"><a data-dimension112="efae4bea-b73f-11f1-9cd2-adf3a8a3deb1" data-action="Deal Block" data-label="10-Cup Coffee Maker" data-dimension48="10-Cup Coffee Maker" data-dimension25="$495" href="https://www.carawayhome.com/products/coffee-maker?Color=Cream" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="uiXAA9yAS9rPsU8enECVNh" name="caraway_coffee_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/uiXAA9yAS9rPsU8enECVNh-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.carawayhome.com/products/coffee-maker?Color=Cream" target="_blank" rel="nofollow" data-dimension112="efae4bea-b73f-11f1-9cd2-adf3a8a3deb1" data-action="Deal Block" data-label="10-Cup Coffee Maker" data-dimension48="10-Cup Coffee Maker" data-dimension25="$495">10-Cup Coffee Maker: $495</a></strong><br />Caraway's drip coffee maker is focused on offering you plastic-free brews whilst still maintaining an incredibly stylish look. With a clean brew system, 90-minutes of warming, one-dial control and a thoughtful design, it's a coffee maker that's built to impress. Available in Cream, Stone, Clay and Midnight.<a class="view-deal button" href="https://www.carawayhome.com/products/coffee-maker?Color=Cream" target="_blank" rel="nofollow" data-dimension112="efae4bea-b73f-11f1-9cd2-adf3a8a3deb1" data-action="Deal Block" data-label="10-Cup Coffee Maker" data-dimension48="10-Cup Coffee Maker" data-dimension25="$495">View Deal</a></p></div><h2 id="why-i-39-ll-be-picking-one-up">Why I'll be picking one up</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="JpsMHSb5BCBUywVKd2asFQ" name="caraway_coffee_2" alt="The Caraway 10-Cup Coffee Maker in a home" src="https://cdn.mos.cms.futurecdn.net/JpsMHSb5BCBUywVKd2asFQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Caraway)</span></figcaption></figure><p>It's hard to ask for a coffee maker that's entirely plastic-free when the market is saturated with options that use plastics for internal components. </p><p>But everything in Caraway's coffee maker is focused on eliminating their use.</p><p>From the water path, shower head, brew basket, and even the reusable coffee filter, each part of the brewing process is made from stainless steel – and it all leads to a durable glass carafe for a cleaner-tasting cup all the way from brew to pour. </p><p>It's clear Caraway has really focused in on this plastic-free innovation (and I heard it has spent 5 years doing just that), but plenty of thought has also gone into its design. </p><p>I'm a huge fan of the clean lines and minimalist, yet stylish design of Caraway's cookware. Seeing this translated into a coffee maker is a dreamy countertop addition. </p><p>Plus, it's available in four colors; Cream, Midnight, Stone, and Clay, which all integrate nicely with the rest of Caraway's range, in keeping with its iconic muted palette.</p><p>And, there are <em>plenty</em> more features to enjoy with the 10-Cup Coffee Maker, including precise temperature control, the ability to brew 2-10 cups, a keep-warm function for up to 90 minutes, and a lovely compact and quiet footprint.</p><p>It also includes a built-in cleaning and descaling cycle, plus dishwasher-safe removable components. Coffee lovers may be intrigued by the one-dial control, too, that switches between brewing and cleaning. </p><p>If you're looking for a more detailed and in-depth coffee brewing system, there's no big screen with options here. But for me, that's not a deal-breaker.</p><h2 id="availability-3">Availability</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ofknmZnjsPnamCbcsGbFGQ" name="caraway_coffee_3" alt="The Caraway 10-Cup Coffee Maker in a home" src="https://cdn.mos.cms.futurecdn.net/ofknmZnjsPnamCbcsGbFGQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">A splash of color </span><span class="credit" itemprop="copyrightHolder">(Image credit: Caraway)</span></figcaption></figure><p>Caraway's 10-Cup Coffee Maker is now available to buy exclusively for <a href="https://www.carawayhome.com/products/coffee-maker?Color=Cream" target="_blank" rel="nofollow">$495 at CarawayHome.com</a> and Crate &amp; Barrel stores and online. Caraway states that shipping commences 10/30, though "quantities are limited".</p><p>Whether it makes its way into our <a href="https://www.tomsguide.com/home/coffee-makers/best-coffee-makers">best coffee makers</a>, we'll have to wait until we get our hands on one for a full review.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-ways-to-create-a-barista-style-coffee-bar-in-your-kitchen">7 ways to create a barista-style coffee bar in your kitchen</a></li><li><a href="https://www.tomsguide.com/home/coffee-doesnt-have-to-be-an-expensive-hobby-heres-my-favorite-cheap-accessories">Coffee doesn’t have to be an expensive hobby — here’s my 5 favorite cheap accessories</a></li><li><a href="https://www.tomsguide.com/home/how-to-make-coffee-without-a-coffee-maker">How to make coffee without a coffee maker — 5 easy techniques</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/coffee-makers/no-plastic-just-coffee-how-caraways-first-ever-coffee-maker-breaks-the-mold</link>
                                                                            <description>
                            <![CDATA[ Introducing Caraway's first-ever coffee maker, committed to making sure no plastics ever touch your water. Here's what to expect. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">mg8BZGwtT5WCCv2ftDXrek</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/u6RBuYUcrfZKfCg8peofyP-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 23 Sep 2026 14:23:45 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Coffee Makers]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                    <category><![CDATA[Kitchen & Dining]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/u6RBuYUcrfZKfCg8peofyP-1920-80.jpg">
                                                            <media:credit><![CDATA[Caraway]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Caraway 10-Cup Coffee Maker in a home]]></media:description>                                                            <media:text><![CDATA[The Caraway 10-Cup Coffee Maker in a home]]></media:text>
                                <media:title type="plain"><![CDATA[The Caraway 10-Cup Coffee Maker in a home]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/u6RBuYUcrfZKfCg8peofyP-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Caraway is well-known for its iconic non-toxic cookware, bakeware, utensils and even trash cans. But, what it's not so well-known for is its coffee makers. Why? Well, because it's never made one before. Until now.</p><p>And while that's big news in itself, what's <em>really</em> special about Caraway's first-ever entry into a busy<a href="https://www.tomsguide.com/home/coffee-makers/best-coffee-makers"> coffee maker</a> world is that it's taking its non-toxic ethos and planting it firmly into the brewing process. </p><p>In fact, the Caraway 10-Cup Coffee Maker has eliminated plastic from the brew path altogether. </p><p>Using a 'first-of-its-kind Clean Brew System', this coffee maker uses stainless steel and glass, meaning your coffee is brewed entirely plastic-free.  </p><p>For a drip coffee maker, that's a <em>pretty</em> big deal, unless you're planning to brew it all manually (which I'm certainly not).</p><div class="product"><a data-dimension112="efae4bea-b73f-11f1-9cd2-adf3a8a3deb1" data-action="Deal Block" data-label="10-Cup Coffee Maker" data-dimension48="10-Cup Coffee Maker" data-dimension25="$495" href="https://www.carawayhome.com/products/coffee-maker?Color=Cream" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="uiXAA9yAS9rPsU8enECVNh" name="caraway_coffee_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/uiXAA9yAS9rPsU8enECVNh-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.carawayhome.com/products/coffee-maker?Color=Cream" target="_blank" rel="nofollow" data-dimension112="efae4bea-b73f-11f1-9cd2-adf3a8a3deb1" data-action="Deal Block" data-label="10-Cup Coffee Maker" data-dimension48="10-Cup Coffee Maker" data-dimension25="$495">10-Cup Coffee Maker: $495</a></strong><br />Caraway's drip coffee maker is focused on offering you plastic-free brews whilst still maintaining an incredibly stylish look. With a clean brew system, 90-minutes of warming, one-dial control and a thoughtful design, it's a coffee maker that's built to impress. Available in Cream, Stone, Clay and Midnight.<a class="view-deal button" href="https://www.carawayhome.com/products/coffee-maker?Color=Cream" target="_blank" rel="nofollow" data-dimension112="efae4bea-b73f-11f1-9cd2-adf3a8a3deb1" data-action="Deal Block" data-label="10-Cup Coffee Maker" data-dimension48="10-Cup Coffee Maker" data-dimension25="$495">View Deal</a></p></div><h2 id="why-i-39-ll-be-picking-one-up">Why I'll be picking one up</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="JpsMHSb5BCBUywVKd2asFQ" name="caraway_coffee_2" alt="The Caraway 10-Cup Coffee Maker in a home" src="https://cdn.mos.cms.futurecdn.net/JpsMHSb5BCBUywVKd2asFQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Caraway)</span></figcaption></figure><p>It's hard to ask for a coffee maker that's entirely plastic-free when the market is saturated with options that use plastics for internal components. </p><p>But everything in Caraway's coffee maker is focused on eliminating their use.</p><p>From the water path, shower head, brew basket, and even the reusable coffee filter, each part of the brewing process is made from stainless steel – and it all leads to a durable glass carafe for a cleaner-tasting cup all the way from brew to pour. </p><p>It's clear Caraway has really focused in on this plastic-free innovation (and I heard it has spent 5 years doing just that), but plenty of thought has also gone into its design. </p><p>I'm a huge fan of the clean lines and minimalist, yet stylish design of Caraway's cookware. Seeing this translated into a coffee maker is a dreamy countertop addition. </p><p>Plus, it's available in four colors; Cream, Midnight, Stone, and Clay, which all integrate nicely with the rest of Caraway's range, in keeping with its iconic muted palette.</p><p>And, there are <em>plenty</em> more features to enjoy with the 10-Cup Coffee Maker, including precise temperature control, the ability to brew 2-10 cups, a keep-warm function for up to 90 minutes, and a lovely compact and quiet footprint.</p><p>It also includes a built-in cleaning and descaling cycle, plus dishwasher-safe removable components. Coffee lovers may be intrigued by the one-dial control, too, that switches between brewing and cleaning. </p><p>If you're looking for a more detailed and in-depth coffee brewing system, there's no big screen with options here. But for me, that's not a deal-breaker.</p><h2 id="availability-3">Availability</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ofknmZnjsPnamCbcsGbFGQ" name="caraway_coffee_3" alt="The Caraway 10-Cup Coffee Maker in a home" src="https://cdn.mos.cms.futurecdn.net/ofknmZnjsPnamCbcsGbFGQ-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">A splash of color </span><span class="credit" itemprop="copyrightHolder">(Image credit: Caraway)</span></figcaption></figure><p>Caraway's 10-Cup Coffee Maker is now available to buy exclusively for <a href="https://www.carawayhome.com/products/coffee-maker?Color=Cream" target="_blank" rel="nofollow">$495 at CarawayHome.com</a> and Crate &amp; Barrel stores and online. Caraway states that shipping commences 10/30, though "quantities are limited".</p><p>Whether it makes its way into our <a href="https://www.tomsguide.com/home/coffee-makers/best-coffee-makers">best coffee makers</a>, we'll have to wait until we get our hands on one for a full review.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/how-to/7-ways-to-create-a-barista-style-coffee-bar-in-your-kitchen">7 ways to create a barista-style coffee bar in your kitchen</a></li><li><a href="https://www.tomsguide.com/home/coffee-doesnt-have-to-be-an-expensive-hobby-heres-my-favorite-cheap-accessories">Coffee doesn’t have to be an expensive hobby — here’s my 5 favorite cheap accessories</a></li><li><a href="https://www.tomsguide.com/home/how-to-make-coffee-without-a-coffee-maker">How to make coffee without a coffee maker — 5 easy techniques</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just found this $8 door hack that could stop heat escaping and cut my energy bills this fall ]]></title>
                                                                                                <dc:content><![CDATA[ <p>As we enter the colder months of the year, it's time to seriously think about getting our homes ready to battle the crisp weather. </p><p>While there's <a href="https://www.tomsguide.com/home/from-tape-to-bubble-wrap-5-cheap-ways-to-weatherize-your-windows-for-winter-storm-fern-and-keep-the-cold-out">5 cheap ways to weatherize your windows</a> that I use every fall, I've realized I also need to focus on my doors.</p><p>Fortunately, there's a simple $8 hack that I've just found that should stop the heat from escaping and keep the cold out in the process. </p><p>So, instead of spending money on an additional heater or paying out more on energy bills, you can save that extra cash for a rainy day (of which there will be many in fall).</p><h2 id="check-your-doors-first">Check your doors first</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="zSAEccKwyfJC3mscNhpgYn" name="Living room with door open" alt="Living room with door open" src="https://cdn.mos.cms.futurecdn.net/zSAEccKwyfJC3mscNhpgYn-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future/Camilla Sharman)</span></figcaption></figure><p>Before you carry out this hack, you'll want to check the doors around your home to identify where any potential draft problems are. Fortunately, we asked an expert for their advice on how best to check.</p><p>Ilja Medvedevs, director of internal door supplies at <a href="https://www.doorsuppliesonline.co.uk/products/deanta-dalston-black-prefinished-clear-glazed" target="_blank" rel="nofollow">Door Supplies Online</a>, reveals: "Close the door and run your hand slowly around the frame, particularly along the sides and top. </p><p>"You can also hold a thin piece of tissue paper near the edges. If it moves when there's no obvious breeze, check that area more closely."</p><p>She adds: "Then look underneath. If you can see daylight when the door is closed or feel cold air coming through, you've found somewhere worth investigating."</p><p>Once you've identified a problem, then you can move on to the simple $8 hack to fix it.</p><h2 id="how-it-works">How it works</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="qx5jinXjfeNEpFWBLmfyhb" name="shutterstock_2706936397" alt="Gap under doorway" src="https://cdn.mos.cms.futurecdn.net/qx5jinXjfeNEpFWBLmfyhb-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>If you've identified drafts underneath any doors in your home, you'll want to find something to prevent them. But, understandably, you won't want to pay a lot of money to do so. </p><p>While you may have a suitable draft excluder in your home already, it can make opening and closing the door a little tricky. </p><p>That's where this affordable item comes in. DIY draft-proofing strips can be picked up from just $8 at Amazon (as shown below) and they'll seal off the bottom of your door with ease, taking about 2 minutes to install. </p><p>They can be cut to size, attached with the strong adhesive already attached, and will effectively stop heat and cold drifting in and out of the room.</p><p>"For a small gap around the edge of an older external door, a suitable self-adhesive strip can be enough,"  Medvedevs advises. "Measure the gap first, as something too thick can make the door difficult to close."</p><div class="product"><a data-dimension112="ebf7940e-b021-11f1-bb13-a17bbdbeb71a" data-action="Deal Block" data-label="Door Draft Strip" data-dimension48="Door Draft Strip" data-dimension25="$7.99" href="https://www.amazon.com/Holikme-Stopper-Insulator-Stripping-Adhesive/dp/B07MSM6G9R" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="4Gd2F955g23jzyUF6MpREo" name="draft_strip_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4Gd2F955g23jzyUF6MpREo-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>This simple door draft strip is perfect for blocking any gaps you find on interior or exterior doors. With almost 50k reviews on Amazon, it's a popular and affordable buy that can be easily installed to the bottom of any doors in your home. In cold weather, it's recommended to use a hair dryer to heat the stopper for a minute before applying it to your door. <a class="view-deal button" href="https://www.amazon.com/Holikme-Stopper-Insulator-Stripping-Adhesive/dp/B07MSM6G9R" target="_blank" rel="nofollow" data-dimension112="ebf7940e-b021-11f1-bb13-a17bbdbeb71a" data-action="Deal Block" data-label="Door Draft Strip" data-dimension48="Door Draft Strip" data-dimension25="$7.99">View Deal</a></p></div><h2 id="extra-money-saving-tips">Extra money-saving tips</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="gWoW8UhSG7R78YpMZFCbYT" name="GettyImages-78486862edit.jpg" alt="Letter posted through the letterbox" src="https://cdn.mos.cms.futurecdn.net/gWoW8UhSG7R78YpMZFCbYT-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Getty Images)</span></figcaption></figure><p>The edges of your doors might not be the only thing letting heat escape or inviting cold air in though. </p><p>Medvedev also suggests checking for smaller openings: "Look at the letterbox and make sure the flap closes properly and any seal or brush is still in good condition." </p><p>It may even be an issue with the door itself not hanging correctly that even the $8 draft-proofing strip won't be able to fix: "If the door has dropped, is difficult to close or there's a large uneven gap around the frame, a draft strip may not solve the problem. That's when you need to look at why the door isn't sitting properly first."</p><p>And any draft-proofing you do now will benefit you all year round. While in the fall and winter it'll hopefully save you money on your energy bills, it'll also keep excessive heat out during the summer when you're trying to embrace the <a href="https://www.tomsguide.com/home/experts-recommend-the-caveman-method-for-keeping-your-house-cool-in-a-heatwave-heres-how-it-works">'caveman method'</a> for a comfortable home.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/the-towel-trick-every-homeowner-should-use-to-block-door-drafts-this-week">Fed up with a cold home? Here’s how I used the ‘towel trick’ to keep in the heat</a></li><li><a href="https://www.tomsguide.com/home/i-tried-this-easy-hack-to-check-for-drafts-in-my-home-and-keep-the-cold-out-all-you-need-is-a-sheet-of-paper">Another major winter storm is coming — here's how to check for drafts right now</a></li><li><a href="https://www.tomsguide.com/home/5-ways-to-winterize-your-home-and-save-money-on-your-energy-bills">5 ways to winterize your home and save money on your energy bills</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/ive-just-found-this-usd8-door-hack-that-could-stop-heat-escaping-and-cut-my-energy-bills-this-fall</link>
                                                                            <description>
                            <![CDATA[ The cold weather is descending, and with that, our heating bills shoot up. Here's a simple and affordable hack that could help keep those costs low while still keeping your home warm. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">pV3Ffj2jziu8dwLfoCq9zj</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/xw9VYXtM3Ewby5xRBLANTF-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 16 Sep 2026 05:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/xw9VYXtM3Ewby5xRBLANTF-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Man closing a door]]></media:description>                                                            <media:text><![CDATA[Man closing a door]]></media:text>
                                <media:title type="plain"><![CDATA[Man closing a door]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/xw9VYXtM3Ewby5xRBLANTF-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As we enter the colder months of the year, it's time to seriously think about getting our homes ready to battle the crisp weather. </p><p>While there's <a href="https://www.tomsguide.com/home/from-tape-to-bubble-wrap-5-cheap-ways-to-weatherize-your-windows-for-winter-storm-fern-and-keep-the-cold-out">5 cheap ways to weatherize your windows</a> that I use every fall, I've realized I also need to focus on my doors.</p><p>Fortunately, there's a simple $8 hack that I've just found that should stop the heat from escaping and keep the cold out in the process. </p><p>So, instead of spending money on an additional heater or paying out more on energy bills, you can save that extra cash for a rainy day (of which there will be many in fall).</p><h2 id="check-your-doors-first">Check your doors first</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="zSAEccKwyfJC3mscNhpgYn" name="Living room with door open" alt="Living room with door open" src="https://cdn.mos.cms.futurecdn.net/zSAEccKwyfJC3mscNhpgYn-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future/Camilla Sharman)</span></figcaption></figure><p>Before you carry out this hack, you'll want to check the doors around your home to identify where any potential draft problems are. Fortunately, we asked an expert for their advice on how best to check.</p><p>Ilja Medvedevs, director of internal door supplies at <a href="https://www.doorsuppliesonline.co.uk/products/deanta-dalston-black-prefinished-clear-glazed" target="_blank" rel="nofollow">Door Supplies Online</a>, reveals: "Close the door and run your hand slowly around the frame, particularly along the sides and top. </p><p>"You can also hold a thin piece of tissue paper near the edges. If it moves when there's no obvious breeze, check that area more closely."</p><p>She adds: "Then look underneath. If you can see daylight when the door is closed or feel cold air coming through, you've found somewhere worth investigating."</p><p>Once you've identified a problem, then you can move on to the simple $8 hack to fix it.</p><h2 id="how-it-works">How it works</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="qx5jinXjfeNEpFWBLmfyhb" name="shutterstock_2706936397" alt="Gap under doorway" src="https://cdn.mos.cms.futurecdn.net/qx5jinXjfeNEpFWBLmfyhb-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>If you've identified drafts underneath any doors in your home, you'll want to find something to prevent them. But, understandably, you won't want to pay a lot of money to do so. </p><p>While you may have a suitable draft excluder in your home already, it can make opening and closing the door a little tricky. </p><p>That's where this affordable item comes in. DIY draft-proofing strips can be picked up from just $8 at Amazon (as shown below) and they'll seal off the bottom of your door with ease, taking about 2 minutes to install. </p><p>They can be cut to size, attached with the strong adhesive already attached, and will effectively stop heat and cold drifting in and out of the room.</p><p>"For a small gap around the edge of an older external door, a suitable self-adhesive strip can be enough,"  Medvedevs advises. "Measure the gap first, as something too thick can make the door difficult to close."</p><div class="product"><a data-dimension112="ebf7940e-b021-11f1-bb13-a17bbdbeb71a" data-action="Deal Block" data-label="Door Draft Strip" data-dimension48="Door Draft Strip" data-dimension25="$7.99" href="https://www.amazon.com/Holikme-Stopper-Insulator-Stripping-Adhesive/dp/B07MSM6G9R" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="4Gd2F955g23jzyUF6MpREo" name="draft_strip_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4Gd2F955g23jzyUF6MpREo-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>This simple door draft strip is perfect for blocking any gaps you find on interior or exterior doors. With almost 50k reviews on Amazon, it's a popular and affordable buy that can be easily installed to the bottom of any doors in your home. In cold weather, it's recommended to use a hair dryer to heat the stopper for a minute before applying it to your door. <a class="view-deal button" href="https://www.amazon.com/Holikme-Stopper-Insulator-Stripping-Adhesive/dp/B07MSM6G9R" target="_blank" rel="nofollow" data-dimension112="ebf7940e-b021-11f1-bb13-a17bbdbeb71a" data-action="Deal Block" data-label="Door Draft Strip" data-dimension48="Door Draft Strip" data-dimension25="$7.99">View Deal</a></p></div><h2 id="extra-money-saving-tips">Extra money-saving tips</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="gWoW8UhSG7R78YpMZFCbYT" name="GettyImages-78486862edit.jpg" alt="Letter posted through the letterbox" src="https://cdn.mos.cms.futurecdn.net/gWoW8UhSG7R78YpMZFCbYT-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Getty Images)</span></figcaption></figure><p>The edges of your doors might not be the only thing letting heat escape or inviting cold air in though. </p><p>Medvedev also suggests checking for smaller openings: "Look at the letterbox and make sure the flap closes properly and any seal or brush is still in good condition." </p><p>It may even be an issue with the door itself not hanging correctly that even the $8 draft-proofing strip won't be able to fix: "If the door has dropped, is difficult to close or there's a large uneven gap around the frame, a draft strip may not solve the problem. That's when you need to look at why the door isn't sitting properly first."</p><p>And any draft-proofing you do now will benefit you all year round. While in the fall and winter it'll hopefully save you money on your energy bills, it'll also keep excessive heat out during the summer when you're trying to embrace the <a href="https://www.tomsguide.com/home/experts-recommend-the-caveman-method-for-keeping-your-house-cool-in-a-heatwave-heres-how-it-works">'caveman method'</a> for a comfortable home.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/the-towel-trick-every-homeowner-should-use-to-block-door-drafts-this-week">Fed up with a cold home? Here’s how I used the ‘towel trick’ to keep in the heat</a></li><li><a href="https://www.tomsguide.com/home/i-tried-this-easy-hack-to-check-for-drafts-in-my-home-and-keep-the-cold-out-all-you-need-is-a-sheet-of-paper">Another major winter storm is coming — here's how to check for drafts right now</a></li><li><a href="https://www.tomsguide.com/home/5-ways-to-winterize-your-home-and-save-money-on-your-energy-bills">5 ways to winterize your home and save money on your energy bills</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The Tom's Guide Awards 2026 ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Welcome to the 2026 Tom's Guide Awards! Our annual awards celebrate the best tech, tools, gear, and services we've used over the past year, culminating with our Hero awards, which celebrate the very best innovation, company, and product design, among others.</p><p>Without further ado, here are all the winners of this year's Tom's Guide Awards.</p><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/tech-events/toms-guide-hero-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/cDMdRfidYEwszGb7xdjmLE.jpg" alt="Tom's Guide Awards 2026" /></p></div><div class="card__content"><h3 class="card__title">TG Hero Awards</h3><div class="card__description-wrapper"><div class="card__description"><p><strong>The brands, innovations and products that excite us most</strong></p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/phones/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/tRjsMHd8hKNf5Se3YPveFg.jpg" alt="Tom's Guide Awards 2026 Phones" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Phones</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite phones of the year </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/tvs/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/PKDeUngVQpQwehWohuZnJL.jpg" alt="Tom's Guide Awards 2026 TVs" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: TVs</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite OLED, Mini-LED, RGB TVs and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/wellness/fitness/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/DsS3VdzYDMuYEU9QcvW6pi.jpg" alt="Tom's Guide Awards 2026 Active Life" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Active Life</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite fitness trackers, workout headphones, recovery tools and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/computing/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/gwuJB7VbT78fdzR6ELkpCe.jpg" alt="Tom's Guide Awards 2026 Computing" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Computing</h3><div class="card__description-wrapper"><div class="card__description"><p>All our favorite laptops, tablets, AR glasses and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/audio/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/whkD8Gh5uHn8bPNnG2rM2M.jpg" alt="Tom's Guide Awards 2026 Audio" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Audio</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite headphones, earbuds, speakers and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/ai/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/k6rknMfVrBs6eK8KtzQFRE.jpg" alt="Tom's Guide Awards 2026 AI" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: AI</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite AI tools, devices and features </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/gaming/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/8fBXAu3nU9FhPKZsswNDDa.jpg" alt="Tom's Guide Awards 2026 Gaming" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Gaming</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite gaming accessories, consoles, controllers and more</p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/home/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/zGZFHNMWutFoAVjdYGosXF.jpg" alt="Tom's Guide Awards 2026 logo and winning products for the Homes category" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Homes</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite robot vacuums, coffee machines, air fryers and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/wellness/sleep/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/KTLabKKQnNuTnmmfTBtfX5.jpg" alt="TG Awards 2026 Sleep" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Sleep</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite mattresses, toppers, pillows and more for getting a good night's sleep </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/vehicle-tech/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/9g6QHtxVQVmYLGPvEXiLPT.jpg" alt="Tom's Guide Awards 2026 Automotive" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Autos</h3><div class="card__description-wrapper"><div class="card__description"><p>All our favorite cars of the year from EVs to hybrids and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/cameras-photography/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/BaG3gmjXLA8coeFauDjmd5.jpg" alt="Tom's Guide Awards 2026 Photography" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Photography</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite action cameras, film cameras, drones and more </p></div></div></div></a> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/tech-events/the-toms-guide-awards-2026</link>
                                                                            <description>
                            <![CDATA[ The Tom's Guide Awards are back and here you'll find all the winners across 12 categories from phones and TVs to sleep and cars. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">ksVD8heDw8UVHxoshvrqWo</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/keLgtGYJF7E4DVX8PcRWZV-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 15 Sep 2026 21:02:31 +0000</pubDate>                                                                                                                                <updated>Thu, 17 Sep 2026 14:22:58 +0000</updated>
                                                                                                                                            <category><![CDATA[Tech Events]]></category>
                                                                                                                    <dc:creator><![CDATA[ Tom&#039;s Guide ]]></dc:creator>                                                                                                        <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/keLgtGYJF7E4DVX8PcRWZV-1920-80.jpg">
                                                            <media:credit><![CDATA[Tom&amp;#39;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tom&#039;s Guide Awards 2026 logo on a glowing blue background]]></media:description>                                                            <media:text><![CDATA[Tom&#039;s Guide Awards 2026 logo on a glowing blue background]]></media:text>
                                <media:title type="plain"><![CDATA[Tom&#039;s Guide Awards 2026 logo on a glowing blue background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/keLgtGYJF7E4DVX8PcRWZV-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Welcome to the 2026 Tom's Guide Awards! Our annual awards celebrate the best tech, tools, gear, and services we've used over the past year, culminating with our Hero awards, which celebrate the very best innovation, company, and product design, among others.</p><p>Without further ado, here are all the winners of this year's Tom's Guide Awards.</p><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/tech-events/toms-guide-hero-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/cDMdRfidYEwszGb7xdjmLE.jpg" alt="Tom's Guide Awards 2026" /></p></div><div class="card__content"><h3 class="card__title">TG Hero Awards</h3><div class="card__description-wrapper"><div class="card__description"><p><strong>The brands, innovations and products that excite us most</strong></p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/phones/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/tRjsMHd8hKNf5Se3YPveFg.jpg" alt="Tom's Guide Awards 2026 Phones" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Phones</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite phones of the year </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/tvs/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/PKDeUngVQpQwehWohuZnJL.jpg" alt="Tom's Guide Awards 2026 TVs" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: TVs</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite OLED, Mini-LED, RGB TVs and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/wellness/fitness/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/DsS3VdzYDMuYEU9QcvW6pi.jpg" alt="Tom's Guide Awards 2026 Active Life" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Active Life</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite fitness trackers, workout headphones, recovery tools and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/computing/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/gwuJB7VbT78fdzR6ELkpCe.jpg" alt="Tom's Guide Awards 2026 Computing" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Computing</h3><div class="card__description-wrapper"><div class="card__description"><p>All our favorite laptops, tablets, AR glasses and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/audio/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/whkD8Gh5uHn8bPNnG2rM2M.jpg" alt="Tom's Guide Awards 2026 Audio" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Audio</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite headphones, earbuds, speakers and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/ai/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/k6rknMfVrBs6eK8KtzQFRE.jpg" alt="Tom's Guide Awards 2026 AI" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: AI</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite AI tools, devices and features </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/gaming/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/8fBXAu3nU9FhPKZsswNDDa.jpg" alt="Tom's Guide Awards 2026 Gaming" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Gaming</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite gaming accessories, consoles, controllers and more</p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/home/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/zGZFHNMWutFoAVjdYGosXF.jpg" alt="Tom's Guide Awards 2026 logo and winning products for the Homes category" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Homes</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite robot vacuums, coffee machines, air fryers and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/wellness/sleep/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/KTLabKKQnNuTnmmfTBtfX5.jpg" alt="TG Awards 2026 Sleep" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Sleep</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite mattresses, toppers, pillows and more for getting a good night's sleep </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/vehicle-tech/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/9g6QHtxVQVmYLGPvEXiLPT.jpg" alt="Tom's Guide Awards 2026 Automotive" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Autos</h3><div class="card__description-wrapper"><div class="card__description"><p>All our favorite cars of the year from EVs to hybrids and more </p></div></div></div></a><a class="card card--standard card--rows-3 card--align-inline" href="https://www.tomsguide.com/cameras-photography/toms-guide-awards-2026"><div class="card-image-widthsetter"><p class="vanilla-image-block"  style="padding-top:56.25%;"><img style="width: 100%" class="card__image" src="https://cdn.mos.cms.futurecdn.net/BaG3gmjXLA8coeFauDjmd5.jpg" alt="Tom's Guide Awards 2026 Photography" /></p></div><div class="card__content"><h3 class="card__title">TG Awards 2026: Photography</h3><div class="card__description-wrapper"><div class="card__description"><p>Our favorite action cameras, film cameras, drones and more </p></div></div></div></a>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ KitchenAid just launched its new Luminaire stand mixer, and it has the one feature I’ve been waiting for ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Whether you’re a master baker or an amateur, owning one of the <a href="https://www.tomsguide.com/best-picks/best-stand-mixers">best stand mixers </a>is an absolute essential — and KitchenAid remains the gold standard of mixers.</p><p>Known for its versatile design and stunning color options, I always get excited about every new launch — and KitchenAid's Luminaire design series doesn’t disappoint.</p><p>KitchenAid's latest <a href="https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire" target="_blank" rel="nofollow">Luminaire tilt-head stand mixer </a>features a stunning fluted glass bowl, gorgeous polished details, and an eye-catching peppercorn blue crinkle finish that shimmers under the lights. But that’s not all.</p><p>It features an integrated bowl light so you can see each stage clearly — a game-changing addition I’ve always wanted to see on a mixer. Here’s why this will be a welcome addition to my kitchen. </p><div class="product"><a data-dimension112="16f6a04a-b0f5-11f1-b127-85c222e96faa" data-action="Deal Block" data-label="Design Series Luminaire Tilt-Head Stand Mixer" data-dimension48="Design Series Luminaire Tilt-Head Stand Mixer" data-dimension25="$699" href="https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="ktYcMrAnn2kxJvcuD3NzqT" name="KitchenAid Luminaire stand mixer product" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ktYcMrAnn2kxJvcuD3NzqT-1920-80.jpg" mos="" align="middle" fullscreen="" width="2500" height="2500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The KitchenAid Design Series Luminaire Tilt-Head stand mixer is designed to be a 'sculptural centerpiece,' and it shows. With its trademark power and precise speed control, it also includes an integrated glass bowl light to help you see with ease. Available for $699.99, it's well-designed and crafted to last.<a class="view-deal button" href="https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire" target="_blank" rel="nofollow" data-dimension112="16f6a04a-b0f5-11f1-b127-85c222e96faa" data-action="Deal Block" data-label="Design Series Luminaire Tilt-Head Stand Mixer" data-dimension48="Design Series Luminaire Tilt-Head Stand Mixer" data-dimension25="$699">View Deal</a></p></div><h2 id="here-39-s-what-you-need-to-know">Here's what you need to know</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2560px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="SAxgvJkUCSuxvZs4e56d5Y" name="KitchenAid® Design Series Luminaire Tilt-Head Stand Mixer" alt="KitchenAid® Design Series Luminaire Tilt-HeadStand Mixer on countertop" src="https://cdn.mos.cms.futurecdn.net/SAxgvJkUCSuxvZs4e56d5Y-1920-80.jpg" mos="" align="middle" fullscreen="" width="2560" height="1440" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Precision control for your desired texture </span><span class="credit" itemprop="copyrightHolder">(Image credit: KitchenAid)</span></figcaption></figure><p>The first thing that caught my eye was its Italian-crafted design and striking 'dried peppercorn' shade. And while I wouldn't ordinarily opt for blue in my kitchen aesthetic, this certainly wouldn't look out of place on any countertop.</p><p>What’s more, the textured crinkle finish gives it a sleek appeal, while the hardened, fluted glass bowl catches the natural light. </p><p>I love the fact that you can see every stage of mixing, which upgrades the entire baking experience when whipping up your baked treats. And if you have junior bakers at home, this would make it even more entertaining.</p><p>In addition, the glass bowl is durable and scratch-resistant during use and when cleaning. </p><p>Beyond its stunning aesthetic, it's equipped with Precision Speed Control to easily adjust your mixing process every step of the way.</p><h2 id="integrated-bowl-light">Integrated bowl light</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:998px;"><p class="vanilla-image-block" style="padding-top:56.21%;"><img id="mdsE5VYne3UTAwmUn8r93P" name="KitchenAid Luminaire on countertop" alt="KitchenAid Luminaire on countertop" src="https://cdn.mos.cms.futurecdn.net/mdsE5VYne3UTAwmUn8r93P-1920-80.jpg" mos="" align="middle" fullscreen="" width="998" height="561" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">KitchenAid Luminaire on countertop </span><span class="credit" itemprop="copyrightHolder">(Image credit: KitchenAid)</span></figcaption></figure><p>Perhaps the one feature that I'm most excited about is the integrated bowl light. </p><p>According to KitchenAid, this stand mixer was "engineered to illuminate" to help you see each stage more clearly. </p><p>This feature comes in handy, especially as the days grow darker this cozy season, and you'll benefit from the extra light.</p><p>Even better, the integrated lighting highlights the entire appliance, making it stand out on your countertop even more. </p><p>I'm sold on this new KitchenAid Luminaire design. Not only does it look the part, but its impressive features are definitely a bonus and will make baking a breeze. Just in time for the festive season. </p><h3 class="article-body__section" id="section-for-more-information"><span>For more information</span></h3><p>Go to: <a href="https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire" target="_blank" rel="nofollow">https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire</a></p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/how-to-choose-the-best-kitchenaid-stand-mixer">How to choose the best KitchenAid stand mixer</a></li><li><a href="https://www.tomsguide.com/best-picks/best-stand-mixers">Discover KitchenAid's Artisan stand mixer is my best kitchen purchase ever — here's why</a> </li><li><a href="https://www.tomsguide.com/features/5-kitchenaid-attachments-to-get-the-most-out-of-your-mixer-and-where-to-buy-them">And 5 KitchenAid gadgets to get the most out of your mixer</a></li></ul><div data-widget-type="multimodelreview" data-widget-title="Today's best KitchenAid blender deals" data-model-name="KitchenAid blender,KitchenAid K150 Blender,KitchenAid Artisan Blender,KitchenAid K400 Artisan Blender"></div> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/kitchenaid-just-launched-its-new-luminaire-stand-mixer-and-it-has-the-one-feature-ive-been-waiting-for</link>
                                                                            <description>
                            <![CDATA[ KitchenAid has just revealed its elegant new stand mixer, and here’s what I love the most about it. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">2Ajhde7fEknstfGzLvDx66</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/SAxgvJkUCSuxvZs4e56d5Y-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 15 Sep 2026 12:29:21 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Kitchen & Dining]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                                    <dc:creator><![CDATA[ Cynthia Lawrence ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/4hFvAy3JvgCJamhKf5KoPU-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/SAxgvJkUCSuxvZs4e56d5Y-1920-80.jpg">
                                                            <media:credit><![CDATA[KitchenAid]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[KitchenAid® Design Series Luminaire Tilt-HeadStand Mixer on countertop]]></media:description>                                                            <media:text><![CDATA[KitchenAid® Design Series Luminaire Tilt-HeadStand Mixer on countertop]]></media:text>
                                <media:title type="plain"><![CDATA[KitchenAid® Design Series Luminaire Tilt-HeadStand Mixer on countertop]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/SAxgvJkUCSuxvZs4e56d5Y-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Whether you’re a master baker or an amateur, owning one of the <a href="https://www.tomsguide.com/best-picks/best-stand-mixers">best stand mixers </a>is an absolute essential — and KitchenAid remains the gold standard of mixers.</p><p>Known for its versatile design and stunning color options, I always get excited about every new launch — and KitchenAid's Luminaire design series doesn’t disappoint.</p><p>KitchenAid's latest <a href="https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire" target="_blank" rel="nofollow">Luminaire tilt-head stand mixer </a>features a stunning fluted glass bowl, gorgeous polished details, and an eye-catching peppercorn blue crinkle finish that shimmers under the lights. But that’s not all.</p><p>It features an integrated bowl light so you can see each stage clearly — a game-changing addition I’ve always wanted to see on a mixer. Here’s why this will be a welcome addition to my kitchen. </p><div class="product"><a data-dimension112="16f6a04a-b0f5-11f1-b127-85c222e96faa" data-action="Deal Block" data-label="Design Series Luminaire Tilt-Head Stand Mixer" data-dimension48="Design Series Luminaire Tilt-Head Stand Mixer" data-dimension25="$699" href="https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="ktYcMrAnn2kxJvcuD3NzqT" name="KitchenAid Luminaire stand mixer product" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ktYcMrAnn2kxJvcuD3NzqT-1920-80.jpg" mos="" align="middle" fullscreen="" width="2500" height="2500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The KitchenAid Design Series Luminaire Tilt-Head stand mixer is designed to be a 'sculptural centerpiece,' and it shows. With its trademark power and precise speed control, it also includes an integrated glass bowl light to help you see with ease. Available for $699.99, it's well-designed and crafted to last.<a class="view-deal button" href="https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire" target="_blank" rel="nofollow" data-dimension112="16f6a04a-b0f5-11f1-b127-85c222e96faa" data-action="Deal Block" data-label="Design Series Luminaire Tilt-Head Stand Mixer" data-dimension48="Design Series Luminaire Tilt-Head Stand Mixer" data-dimension25="$699">View Deal</a></p></div><h2 id="here-39-s-what-you-need-to-know">Here's what you need to know</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2560px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="SAxgvJkUCSuxvZs4e56d5Y" name="KitchenAid® Design Series Luminaire Tilt-Head Stand Mixer" alt="KitchenAid® Design Series Luminaire Tilt-HeadStand Mixer on countertop" src="https://cdn.mos.cms.futurecdn.net/SAxgvJkUCSuxvZs4e56d5Y-1920-80.jpg" mos="" align="middle" fullscreen="" width="2560" height="1440" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Precision control for your desired texture </span><span class="credit" itemprop="copyrightHolder">(Image credit: KitchenAid)</span></figcaption></figure><p>The first thing that caught my eye was its Italian-crafted design and striking 'dried peppercorn' shade. And while I wouldn't ordinarily opt for blue in my kitchen aesthetic, this certainly wouldn't look out of place on any countertop.</p><p>What’s more, the textured crinkle finish gives it a sleek appeal, while the hardened, fluted glass bowl catches the natural light. </p><p>I love the fact that you can see every stage of mixing, which upgrades the entire baking experience when whipping up your baked treats. And if you have junior bakers at home, this would make it even more entertaining.</p><p>In addition, the glass bowl is durable and scratch-resistant during use and when cleaning. </p><p>Beyond its stunning aesthetic, it's equipped with Precision Speed Control to easily adjust your mixing process every step of the way.</p><h2 id="integrated-bowl-light">Integrated bowl light</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:998px;"><p class="vanilla-image-block" style="padding-top:56.21%;"><img id="mdsE5VYne3UTAwmUn8r93P" name="KitchenAid Luminaire on countertop" alt="KitchenAid Luminaire on countertop" src="https://cdn.mos.cms.futurecdn.net/mdsE5VYne3UTAwmUn8r93P-1920-80.jpg" mos="" align="middle" fullscreen="" width="998" height="561" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">KitchenAid Luminaire on countertop </span><span class="credit" itemprop="copyrightHolder">(Image credit: KitchenAid)</span></figcaption></figure><p>Perhaps the one feature that I'm most excited about is the integrated bowl light. </p><p>According to KitchenAid, this stand mixer was "engineered to illuminate" to help you see each stage more clearly. </p><p>This feature comes in handy, especially as the days grow darker this cozy season, and you'll benefit from the extra light.</p><p>Even better, the integrated lighting highlights the entire appliance, making it stand out on your countertop even more. </p><p>I'm sold on this new KitchenAid Luminaire design. Not only does it look the part, but its impressive features are definitely a bonus and will make baking a breeze. Just in time for the festive season. </p><h3 class="article-body__section" id="section-for-more-information"><span>For more information</span></h3><p>Go to: <a href="https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire" target="_blank" rel="nofollow">https://www.kitchenaid.com/countertop-appliances/stand-mixers/design-series/luminaire</a></p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/how-to-choose-the-best-kitchenaid-stand-mixer">How to choose the best KitchenAid stand mixer</a></li><li><a href="https://www.tomsguide.com/best-picks/best-stand-mixers">Discover KitchenAid's Artisan stand mixer is my best kitchen purchase ever — here's why</a> </li><li><a href="https://www.tomsguide.com/features/5-kitchenaid-attachments-to-get-the-most-out-of-your-mixer-and-where-to-buy-them">And 5 KitchenAid gadgets to get the most out of your mixer</a></li></ul><div data-widget-type="multimodelreview" data-widget-title="Today's best KitchenAid blender deals" data-model-name="KitchenAid blender,KitchenAid K150 Blender,KitchenAid Artisan Blender,KitchenAid K400 Artisan Blender"></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tried the $7 hack that promises to keep spiders out of my house — and it uses just 3 simple items ]]></title>
                                                                                                <dc:content><![CDATA[ <p>I'm a big fan of fall. Crispy weather, comfy clothing and cozy nights in. But, I tell you what I'm not a big fan of – spiders. Unfortunately, when we reach the end of summer and beginning of fall, it also becomes mating season for spiders.</p><p>Male spiders are desperately on the hunt and that brings them out of their usual hidey-holes looking for a mate. It turns out if you're seeing more spiders right now, they've probably been living in your house all year long. </p><p>Plus, if you're leaving lights on and windows open, the bugs will fly in and the spiders will surely follow their prey. Either way, it makes my skin crawl and I'd like to avoid any crawling altogether. Fortunately, I found a spider-repelling hack just in time – and it uses just three affordable items.</p><h2 id="how-does-it-work-4">How does it work?</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@haz_colourfulhome/video/7547276301959171350" data-video-id="7547276301959171350" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@haz_colourfulhome" href="https://www.tiktok.com/@haz_colourfulhome">@haz_colourfulhome</a>                            <p></p><a target="_blank" title="♬ original sound - haz_colourfulhome" href="https://www.tiktok.com/music/original-sound-7547276405613136662">♬ original sound - haz_colourfulhome</a></section>                    </blockquote></div>                <p>TikTok user, <a href="https://www.tiktok.com/@haz_colourfulhome" target="_blank" rel="nofollow">@haz_colourfulhome</a>, shared a simple hack on her social media that has kept her home spider-free for years. All you need, she says, is epsom salt, little net bags and some essential oil(s). </p><p>For the essential oil, Harriet recommends lemon, mint, eucalyptus and lavender, but you could also use peppermint oil, other citrus oils such as orange and lime, or tea tree. These are all smells that spiders <em>hate, </em>but you can pick ones that you love.</p><p><strong>To follow this hack, carry out these five simple steps:</strong></p><ul><li><strong>Pour the epsom salt into each bag, around half full</strong></li><li><strong>Fasten it securely</strong></li><li><strong>Dab the essential oil onto the epsom salt over the bag</strong></li><li><strong>Be as generous as you want with the oil</strong></li><li><strong>Repeat the process as many times as you need</strong></li></ul><p>One <strong>important caveat</strong> for this hack is that the essential oil <em>will</em> make the bag quite greasy. So, you should avoid placing it directly on any wood surfaces or any surfaces you'd like not to be affected. Alternatively, you can place it on a little dish on top of the delicate surfaces.</p><p>She adds, it's completely up to personal choice how many you decide to place around your home, but she has them in lots of corners, by the front door and any hidden places around her home: "I am just that petrified I just think more is more in this case."</p><div class="product"><a data-dimension112="3a9c2aa4-ad55-11f1-b212-d9cc046b0401" data-action="Deal Block" data-label="50-Pack Small Mesh Bags" data-dimension48="50-Pack Small Mesh Bags" data-dimension25="$7.99" href="https://www.amazon.com/gp/aw/d/B0DXV59SHD" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="pK8ieLxxL4qW5rkpANx4XV" name="net_bags_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/pK8ieLxxL4qW5rkpANx4XV-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/gp/aw/d/B0DXV59SHD" target="_blank" rel="nofollow" data-dimension112="3a9c2aa4-ad55-11f1-b212-d9cc046b0401" data-action="Deal Block" data-label="50-Pack Small Mesh Bags" data-dimension48="50-Pack Small Mesh Bags" data-dimension25="$7.99">50-Pack Small Mesh Bags: was $9.99 now $7.99</a></strong><br />While this 50-pack of little net bags are presented as perfect for party favors (which I'm sure they are), you can repurpose them for this spider-repellent hack with ease. And with 50 in there, you can place them by every crack or gap you see.<a class="view-deal button" href="https://www.amazon.com/gp/aw/d/B0DXV59SHD" target="_blank" rel="nofollow" data-dimension112="3a9c2aa4-ad55-11f1-b212-d9cc046b0401" data-action="Deal Block" data-label="50-Pack Small Mesh Bags" data-dimension48="50-Pack Small Mesh Bags" data-dimension25="$7.99">View Deal</a></p></div><h2 id="here-39-s-what-happened-when-i-tried-it-4">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="32hYorX4qQGVfMZFjJgAEG" name="spider_hack_bags" alt="A hand holds two bags of epsom salt and essential oils for a spider repelling hack" src="https://cdn.mos.cms.futurecdn.net/32hYorX4qQGVfMZFjJgAEG-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>While there's a <a href="https://www.tomsguide.com/home/the-1-minute-kitchen-scrap-hack-i-use-every-july-to-keep-spiders-out-of-my-house">citrus peel spider hack</a> that I've been trying out, I feel like you can't overdo trying to stop the spiders taking over your home. It also doesn't hurt that it smells lovely, too. So, I grabbed some epsom salts, little net bags and essential oil ready to try out this hack.</p><p>And it was actually surprisingly simple. I should've known really considering Harriet managed to keep up an entire narrative during her TikTok video while completing the hack, but I was still worried the oil would get everywhere.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3HXLw42w3z4xF6WVBNbFEG" name="spider_hack_window" alt="A bag of epsom salt and essential oil is placed on a windowsill to stop spiders coming in" src="https://cdn.mos.cms.futurecdn.net/3HXLw42w3z4xF6WVBNbFEG-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I'm happy to report though that the epsom salts and net bag seemed to soak up the oil quite well. It was still greasy, as Harriet warned, but not enough that I felt it would leave a stain or a mark. </p><p>It took me around 5 minutes to make a handful of bags and then I placed them around my home. The smell was subtle, but just enough to add a nice scent to the rooms. Unfortunately, I hadn't put into consideration my kids who decided it was game to find all the net bags and collect them all up again.</p><p>After I explained what they were for though, they were in full support of keeping the spider count down in our house. Now, I've not seen any spiders <em>yet</em>, but I fear it might be a little too soon to tell. Either way, it took me minimal effort, it was incredibly affordable and the net bags can be reused year after year. </p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><strong></strong><a href="https://www.tomsguide.com/home/its-peak-spider-season-heres-what-to-look-out-for-and-how-to-keep-them-at-bay-this-fall"><strong>It’s peak spider season — here’s what to look out for and how to keep them at bay this fall</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/home/i-banished-spiders-with-this-3-dollar-cleaning-hack"><strong>I banished spiders with this $3 cleaning hack — and it actually worked</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/home/5-spider-repelling-hacks-that-actually-work-and-you-probably-have-everything-you-need-at-home"><strong>5 spider-repelling hacks that actually work — and you probably have everything you need at home</strong></a><strong></strong></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/i-tried-the-usd7-hack-that-promises-to-keep-spiders-out-of-my-house-and-it-uses-just-3-simple-items</link>
                                                                            <description>
                            <![CDATA[ It's officially spider season, which means there's going to be a lot more unwanted visitors in your home. Here's the simple hack I followed to see if I could have a spider-free season instead. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">eJhze9kA6SRCnbAq2qJXSC</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/3PxoY4eXFkFTB8ZbNbiBEG-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 14 Sep 2026 05:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/3PxoY4eXFkFTB8ZbNbiBEG-1920-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A bag of epsom salts and a pile of small net bags lay on a countertop]]></media:description>                                                            <media:text><![CDATA[A bag of epsom salts and a pile of small net bags lay on a countertop]]></media:text>
                                <media:title type="plain"><![CDATA[A bag of epsom salts and a pile of small net bags lay on a countertop]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/3PxoY4eXFkFTB8ZbNbiBEG-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I'm a big fan of fall. Crispy weather, comfy clothing and cozy nights in. But, I tell you what I'm not a big fan of – spiders. Unfortunately, when we reach the end of summer and beginning of fall, it also becomes mating season for spiders.</p><p>Male spiders are desperately on the hunt and that brings them out of their usual hidey-holes looking for a mate. It turns out if you're seeing more spiders right now, they've probably been living in your house all year long. </p><p>Plus, if you're leaving lights on and windows open, the bugs will fly in and the spiders will surely follow their prey. Either way, it makes my skin crawl and I'd like to avoid any crawling altogether. Fortunately, I found a spider-repelling hack just in time – and it uses just three affordable items.</p><h2 id="how-does-it-work-4">How does it work?</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@haz_colourfulhome/video/7547276301959171350" data-video-id="7547276301959171350" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@haz_colourfulhome" href="https://www.tiktok.com/@haz_colourfulhome">@haz_colourfulhome</a>                            <p></p><a target="_blank" title="♬ original sound - haz_colourfulhome" href="https://www.tiktok.com/music/original-sound-7547276405613136662">♬ original sound - haz_colourfulhome</a></section>                    </blockquote></div>                <p>TikTok user, <a href="https://www.tiktok.com/@haz_colourfulhome" target="_blank" rel="nofollow">@haz_colourfulhome</a>, shared a simple hack on her social media that has kept her home spider-free for years. All you need, she says, is epsom salt, little net bags and some essential oil(s). </p><p>For the essential oil, Harriet recommends lemon, mint, eucalyptus and lavender, but you could also use peppermint oil, other citrus oils such as orange and lime, or tea tree. These are all smells that spiders <em>hate, </em>but you can pick ones that you love.</p><p><strong>To follow this hack, carry out these five simple steps:</strong></p><ul><li><strong>Pour the epsom salt into each bag, around half full</strong></li><li><strong>Fasten it securely</strong></li><li><strong>Dab the essential oil onto the epsom salt over the bag</strong></li><li><strong>Be as generous as you want with the oil</strong></li><li><strong>Repeat the process as many times as you need</strong></li></ul><p>One <strong>important caveat</strong> for this hack is that the essential oil <em>will</em> make the bag quite greasy. So, you should avoid placing it directly on any wood surfaces or any surfaces you'd like not to be affected. Alternatively, you can place it on a little dish on top of the delicate surfaces.</p><p>She adds, it's completely up to personal choice how many you decide to place around your home, but she has them in lots of corners, by the front door and any hidden places around her home: "I am just that petrified I just think more is more in this case."</p><div class="product"><a data-dimension112="3a9c2aa4-ad55-11f1-b212-d9cc046b0401" data-action="Deal Block" data-label="50-Pack Small Mesh Bags" data-dimension48="50-Pack Small Mesh Bags" data-dimension25="$7.99" href="https://www.amazon.com/gp/aw/d/B0DXV59SHD" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="pK8ieLxxL4qW5rkpANx4XV" name="net_bags_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/pK8ieLxxL4qW5rkpANx4XV-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/gp/aw/d/B0DXV59SHD" target="_blank" rel="nofollow" data-dimension112="3a9c2aa4-ad55-11f1-b212-d9cc046b0401" data-action="Deal Block" data-label="50-Pack Small Mesh Bags" data-dimension48="50-Pack Small Mesh Bags" data-dimension25="$7.99">50-Pack Small Mesh Bags: was $9.99 now $7.99</a></strong><br />While this 50-pack of little net bags are presented as perfect for party favors (which I'm sure they are), you can repurpose them for this spider-repellent hack with ease. And with 50 in there, you can place them by every crack or gap you see.<a class="view-deal button" href="https://www.amazon.com/gp/aw/d/B0DXV59SHD" target="_blank" rel="nofollow" data-dimension112="3a9c2aa4-ad55-11f1-b212-d9cc046b0401" data-action="Deal Block" data-label="50-Pack Small Mesh Bags" data-dimension48="50-Pack Small Mesh Bags" data-dimension25="$7.99">View Deal</a></p></div><h2 id="here-39-s-what-happened-when-i-tried-it-4">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="32hYorX4qQGVfMZFjJgAEG" name="spider_hack_bags" alt="A hand holds two bags of epsom salt and essential oils for a spider repelling hack" src="https://cdn.mos.cms.futurecdn.net/32hYorX4qQGVfMZFjJgAEG-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>While there's a <a href="https://www.tomsguide.com/home/the-1-minute-kitchen-scrap-hack-i-use-every-july-to-keep-spiders-out-of-my-house">citrus peel spider hack</a> that I've been trying out, I feel like you can't overdo trying to stop the spiders taking over your home. It also doesn't hurt that it smells lovely, too. So, I grabbed some epsom salts, little net bags and essential oil ready to try out this hack.</p><p>And it was actually surprisingly simple. I should've known really considering Harriet managed to keep up an entire narrative during her TikTok video while completing the hack, but I was still worried the oil would get everywhere.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3HXLw42w3z4xF6WVBNbFEG" name="spider_hack_window" alt="A bag of epsom salt and essential oil is placed on a windowsill to stop spiders coming in" src="https://cdn.mos.cms.futurecdn.net/3HXLw42w3z4xF6WVBNbFEG-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I'm happy to report though that the epsom salts and net bag seemed to soak up the oil quite well. It was still greasy, as Harriet warned, but not enough that I felt it would leave a stain or a mark. </p><p>It took me around 5 minutes to make a handful of bags and then I placed them around my home. The smell was subtle, but just enough to add a nice scent to the rooms. Unfortunately, I hadn't put into consideration my kids who decided it was game to find all the net bags and collect them all up again.</p><p>After I explained what they were for though, they were in full support of keeping the spider count down in our house. Now, I've not seen any spiders <em>yet</em>, but I fear it might be a little too soon to tell. Either way, it took me minimal effort, it was incredibly affordable and the net bags can be reused year after year. </p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><strong></strong><a href="https://www.tomsguide.com/home/its-peak-spider-season-heres-what-to-look-out-for-and-how-to-keep-them-at-bay-this-fall"><strong>It’s peak spider season — here’s what to look out for and how to keep them at bay this fall</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/home/i-banished-spiders-with-this-3-dollar-cleaning-hack"><strong>I banished spiders with this $3 cleaning hack — and it actually worked</strong></a><strong></strong></li><li><strong></strong><a href="https://www.tomsguide.com/home/5-spider-repelling-hacks-that-actually-work-and-you-probably-have-everything-you-need-at-home"><strong>5 spider-repelling hacks that actually work — and you probably have everything you need at home</strong></a><strong></strong></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Le Creuset just dropped an entire Star Trek collection — and I can't decide which item I like the most ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Le Creuset is an iconic kitchen brand. <a href="https://www.tomsguide.com/entertainment/movies/how-to-watch-the-star-trek-movies-in-order">Star Trek is an iconic franchise</a>. And what happens when you take two icons, put them in a bowl and mix them together? Well, a 12-piece kitchenware collection that'll turn your kitchen into a culinary command center.</p><p>To celebrate 60 years of "Star Trek", the cookware brand has lovingly crafted a limited-edition collection for fans of the franchise. Or, maybe you're just a fan of Spock (don't worry, there's a mug for that). </p><p>Christopher Scinto, Chief Marketing Officer at Le Creuset says: "With the Le Creuset x Star Trek Collection, we set out to commemorate some of the franchise's most beloved symbols with our signature craftsmanship and iconic colors and designs."</p><p>While there's 12 pieces in the collection that you can check out for a limited time only at Le Creuset stores, <a href="http://LeCreuset.com" target="_blank" rel="nofollow">LeCreuset.com</a>, and <a href="https://www.williams-sonoma.com/" target="_blank" rel="nofollow">Williams-Sonoma.com</a>, I've highlighted my five top picks below.</p><h2 id="what-39-s-in-my-basket">What's in my basket</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="VenG82ejhYRyErJC2Qj59Q" name="Le Creuset x Star Treck Collection 2" alt="The Le Creuset and Star Trek Collection" src="https://cdn.mos.cms.futurecdn.net/VenG82ejhYRyErJC2Qj59Q-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Le Creuset/CBS)</span></figcaption></figure><p>The full Le Creuset x "Star Trek" collection ranges from $35 to $500, but with 12 items there's hopefully something for every price range. Before we jump into my basket, I want to give a special mention to the Mini Cocottes for Balok, Gorn and Talosian. While they're not in my basket right now, they're certainly worth checking out if you're a fan.</p><div class="product"><a data-dimension112="433de4a6-aaba-11f1-b35b-5b7496d67c8f" data-action="Deal Block" data-label="Spock Mug" data-dimension48="Spock Mug" data-dimension25="$35" href="https://www.lecreuset.com/round-dutch-oven/21177US.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="CCp3WkA7DwRqzDscYBz35T" name="lecreuset_spockmug" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CCp3WkA7DwRqzDscYBz35T-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/round-dutch-oven/21177US.html" target="_blank" rel="nofollow" data-dimension112="433de4a6-aaba-11f1-b35b-5b7496d67c8f" data-action="Deal Block" data-label="Spock Mug" data-dimension48="Spock Mug" data-dimension25="$35">Spock Mug: $35</a></strong><br />Le Creuset transforms the everyday mug handle into Spock's infamous ear in this unique design. While missing the usual gap for your fingers in the handle, it replaces it with the fun of gripping onto Spock's most defining feature.<a class="view-deal button" href="https://www.lecreuset.com/round-dutch-oven/21177US.html" target="_blank" rel="nofollow" data-dimension112="433de4a6-aaba-11f1-b35b-5b7496d67c8f" data-action="Deal Block" data-label="Spock Mug" data-dimension48="Spock Mug" data-dimension25="$35">View Deal</a></p></div><div class="product"><a data-dimension112="433de5f0-aaba-11f1-bbcc-932ffe9bbb44" data-action="Deal Block" data-label="Live Long and Prosper Spoon Rest" data-dimension48="Live Long and Prosper Spoon Rest" data-dimension25="$55" href="https://www.lecreuset.com/pepper-mill/44001.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="j3CT7XhbZUE9aXfNvK9Pm8" name="lecreuset_spoonrest" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/j3CT7XhbZUE9aXfNvK9Pm8-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/pepper-mill/44001.html" target="_blank" rel="nofollow" data-dimension112="433de5f0-aaba-11f1-bbcc-932ffe9bbb44" data-action="Deal Block" data-label="Live Long and Prosper Spoon Rest" data-dimension48="Live Long and Prosper Spoon Rest" data-dimension25="$55">Live Long and Prosper Spoon Rest: $55</a></strong><br />It wouldn't be <em>Star Trek</em> without the emblematic four-finger split. The Vulcan salute can become a kitchen staple instead taking on new life as a spoon rest that'll subtly tell your friends and family that you're a Trekkie – and a chef.<a class="view-deal button" href="https://www.lecreuset.com/pepper-mill/44001.html" target="_blank" rel="nofollow" data-dimension112="433de5f0-aaba-11f1-bbcc-932ffe9bbb44" data-action="Deal Block" data-label="Live Long and Prosper Spoon Rest" data-dimension48="Live Long and Prosper Spoon Rest" data-dimension25="$55">View Deal</a></p></div><div class="product"><a data-dimension112="433de514-aaba-11f1-840f-63fa391c57df" data-action="Deal Block" data-label="Communi-Grater" data-dimension48="Communi-Grater" data-dimension25="$68" href="https://www.lecreuset.com/signature-skillet/20182US.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="yM3UkLRCCQPiTnkkfysh8T" name="lecreuset_communigrater" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/yM3UkLRCCQPiTnkkfysh8T-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/signature-skillet/20182US.html" target="_blank" rel="nofollow" data-dimension112="433de514-aaba-11f1-840f-63fa391c57df" data-action="Deal Block" data-label="Communi-Grater" data-dimension48="Communi-Grater" data-dimension25="$68">Communi-Grater: $68</a></strong><br />Le Creuset are known more for cookware than they are for kitchen accessories, but there's something extra special about this one. This greater plays on the Communicator with a quirky pun and a unique design to desire.<a class="view-deal button" href="https://www.lecreuset.com/signature-skillet/20182US.html" target="_blank" rel="nofollow" data-dimension112="433de514-aaba-11f1-840f-63fa391c57df" data-action="Deal Block" data-label="Communi-Grater" data-dimension48="Communi-Grater" data-dimension25="$68">View Deal</a></p></div><div class="product"><a data-dimension112="433de668-aaba-11f1-868d-fb080f159d20" data-action="Deal Block" data-label="Galileo Shuttlecraft Rectangular Casserole" data-dimension48="Galileo Shuttlecraft Rectangular Casserole" data-dimension25="$150" href="https://www.lecreuset.com/vancouver-mug/70317US.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="8QvQF6LU5t8Fto3vLjoDn8" name="lecreuset_galileocasserole" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/8QvQF6LU5t8Fto3vLjoDn8-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/vancouver-mug/70317US.html" target="_blank" rel="nofollow" data-dimension112="433de668-aaba-11f1-868d-fb080f159d20" data-action="Deal Block" data-label="Galileo Shuttlecraft Rectangular Casserole" data-dimension48="Galileo Shuttlecraft Rectangular Casserole" data-dimension25="$150">Galileo Shuttlecraft Rectangular Casserole: $150</a></strong><br />My favorite piece from the collection is this retro <em>Star Trek</em> twist on Le Creuset's iconic rectangular casserole dishes. A nod to the 1960s Galileo Shuttlecraft, it's equal parts nostalgia and cookware goodness.<a class="view-deal button" href="https://www.lecreuset.com/vancouver-mug/70317US.html" target="_blank" rel="nofollow" data-dimension112="433de668-aaba-11f1-868d-fb080f159d20" data-action="Deal Block" data-label="Galileo Shuttlecraft Rectangular Casserole" data-dimension48="Galileo Shuttlecraft Rectangular Casserole" data-dimension25="$150">View Deal</a></p></div><div class="product"><a data-dimension112="433de582-aaba-11f1-8881-0ddce702c4bc" data-action="Deal Block" data-label="Klingon Braiser with Klingon Trefoil Knob" data-dimension48="Klingon Braiser with Klingon Trefoil Knob" data-dimension25="$450" href="https://www.lecreuset.com/heritage-3-piece-rectangular-baking-dish-set/ST0098.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="SU5y49orWDCp43mFjBrG6T" name="lecreuset_klingonbraiser" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SU5y49orWDCp43mFjBrG6T-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/heritage-3-piece-rectangular-baking-dish-set/ST0098.html" target="_blank" rel="nofollow" data-dimension112="433de582-aaba-11f1-8881-0ddce702c4bc" data-action="Deal Block" data-label="Klingon Braiser with Klingon Trefoil Knob" data-dimension48="Klingon Braiser with Klingon Trefoil Knob" data-dimension25="$450">Klingon Braiser with Klingon Trefoil Knob: $450</a></strong><br />And Le Creuset have given another iconic cookware item, the Braiser, a "Star Trek" twist. To commemorate 60 years, it has replaced the trefoil knob with a Klingon emblem whilst embossing a Klingon starship on the lid – all in a striking dark blue.<a class="view-deal button" href="https://www.lecreuset.com/heritage-3-piece-rectangular-baking-dish-set/ST0098.html" target="_blank" rel="nofollow" data-dimension112="433de582-aaba-11f1-8881-0ddce702c4bc" data-action="Deal Block" data-label="Klingon Braiser with Klingon Trefoil Knob" data-dimension48="Klingon Braiser with Klingon Trefoil Knob" data-dimension25="$450">View Deal</a></p></div><ul><li><a href="https://www.tomsguide.com/home/revolutionary-for-homemade-bread-why-i-cant-wait-to-try-le-creusets-new-oval-bread-oven">'Revolutionary for homemade bread': Why I can't wait to try Le Creuset's new oval bread oven</a></li><li><a href="https://www.tomsguide.com/home/cast-iron-skillet-vs-dutch-oven-which-is-better">Cast iron skillet vs Dutch oven — which is better?</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/what-is-a-dutch-oven-everything-you-need-to-know-about-this-kitchen-essential">What is a Dutch oven — everything you need to know about this kitchen essential</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/kitchen-dining/le-creuset-just-dropped-an-entire-star-trek-collection-and-i-cant-decide-which-item-i-like-the-most</link>
                                                                            <description>
                            <![CDATA[ In an unexpected collab, Le Creuset has teamed up with Paramount to celebrate 60 years of Star Trek with kitchenware that's sure to live long and prosper. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">bBZw6JfeqxmyuRJMyv53yD</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/wfxRUph98kwvpRwDGtveGQ-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 08 Sep 2026 13:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Kitchen & Dining]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/wfxRUph98kwvpRwDGtveGQ-1920-80.jpg">
                                                            <media:credit><![CDATA[Le Creuset/CBS]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Le Creuset and Star Trek Collection]]></media:description>                                                            <media:text><![CDATA[The Le Creuset and Star Trek Collection]]></media:text>
                                <media:title type="plain"><![CDATA[The Le Creuset and Star Trek Collection]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/wfxRUph98kwvpRwDGtveGQ-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Le Creuset is an iconic kitchen brand. <a href="https://www.tomsguide.com/entertainment/movies/how-to-watch-the-star-trek-movies-in-order">Star Trek is an iconic franchise</a>. And what happens when you take two icons, put them in a bowl and mix them together? Well, a 12-piece kitchenware collection that'll turn your kitchen into a culinary command center.</p><p>To celebrate 60 years of "Star Trek", the cookware brand has lovingly crafted a limited-edition collection for fans of the franchise. Or, maybe you're just a fan of Spock (don't worry, there's a mug for that). </p><p>Christopher Scinto, Chief Marketing Officer at Le Creuset says: "With the Le Creuset x Star Trek Collection, we set out to commemorate some of the franchise's most beloved symbols with our signature craftsmanship and iconic colors and designs."</p><p>While there's 12 pieces in the collection that you can check out for a limited time only at Le Creuset stores, <a href="http://LeCreuset.com" target="_blank" rel="nofollow">LeCreuset.com</a>, and <a href="https://www.williams-sonoma.com/" target="_blank" rel="nofollow">Williams-Sonoma.com</a>, I've highlighted my five top picks below.</p><h2 id="what-39-s-in-my-basket">What's in my basket</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="VenG82ejhYRyErJC2Qj59Q" name="Le Creuset x Star Treck Collection 2" alt="The Le Creuset and Star Trek Collection" src="https://cdn.mos.cms.futurecdn.net/VenG82ejhYRyErJC2Qj59Q-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Le Creuset/CBS)</span></figcaption></figure><p>The full Le Creuset x "Star Trek" collection ranges from $35 to $500, but with 12 items there's hopefully something for every price range. Before we jump into my basket, I want to give a special mention to the Mini Cocottes for Balok, Gorn and Talosian. While they're not in my basket right now, they're certainly worth checking out if you're a fan.</p><div class="product"><a data-dimension112="433de4a6-aaba-11f1-b35b-5b7496d67c8f" data-action="Deal Block" data-label="Spock Mug" data-dimension48="Spock Mug" data-dimension25="$35" href="https://www.lecreuset.com/round-dutch-oven/21177US.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="CCp3WkA7DwRqzDscYBz35T" name="lecreuset_spockmug" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CCp3WkA7DwRqzDscYBz35T-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/round-dutch-oven/21177US.html" target="_blank" rel="nofollow" data-dimension112="433de4a6-aaba-11f1-b35b-5b7496d67c8f" data-action="Deal Block" data-label="Spock Mug" data-dimension48="Spock Mug" data-dimension25="$35">Spock Mug: $35</a></strong><br />Le Creuset transforms the everyday mug handle into Spock's infamous ear in this unique design. While missing the usual gap for your fingers in the handle, it replaces it with the fun of gripping onto Spock's most defining feature.<a class="view-deal button" href="https://www.lecreuset.com/round-dutch-oven/21177US.html" target="_blank" rel="nofollow" data-dimension112="433de4a6-aaba-11f1-b35b-5b7496d67c8f" data-action="Deal Block" data-label="Spock Mug" data-dimension48="Spock Mug" data-dimension25="$35">View Deal</a></p></div><div class="product"><a data-dimension112="433de5f0-aaba-11f1-bbcc-932ffe9bbb44" data-action="Deal Block" data-label="Live Long and Prosper Spoon Rest" data-dimension48="Live Long and Prosper Spoon Rest" data-dimension25="$55" href="https://www.lecreuset.com/pepper-mill/44001.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="j3CT7XhbZUE9aXfNvK9Pm8" name="lecreuset_spoonrest" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/j3CT7XhbZUE9aXfNvK9Pm8-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/pepper-mill/44001.html" target="_blank" rel="nofollow" data-dimension112="433de5f0-aaba-11f1-bbcc-932ffe9bbb44" data-action="Deal Block" data-label="Live Long and Prosper Spoon Rest" data-dimension48="Live Long and Prosper Spoon Rest" data-dimension25="$55">Live Long and Prosper Spoon Rest: $55</a></strong><br />It wouldn't be <em>Star Trek</em> without the emblematic four-finger split. The Vulcan salute can become a kitchen staple instead taking on new life as a spoon rest that'll subtly tell your friends and family that you're a Trekkie – and a chef.<a class="view-deal button" href="https://www.lecreuset.com/pepper-mill/44001.html" target="_blank" rel="nofollow" data-dimension112="433de5f0-aaba-11f1-bbcc-932ffe9bbb44" data-action="Deal Block" data-label="Live Long and Prosper Spoon Rest" data-dimension48="Live Long and Prosper Spoon Rest" data-dimension25="$55">View Deal</a></p></div><div class="product"><a data-dimension112="433de514-aaba-11f1-840f-63fa391c57df" data-action="Deal Block" data-label="Communi-Grater" data-dimension48="Communi-Grater" data-dimension25="$68" href="https://www.lecreuset.com/signature-skillet/20182US.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="yM3UkLRCCQPiTnkkfysh8T" name="lecreuset_communigrater" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/yM3UkLRCCQPiTnkkfysh8T-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/signature-skillet/20182US.html" target="_blank" rel="nofollow" data-dimension112="433de514-aaba-11f1-840f-63fa391c57df" data-action="Deal Block" data-label="Communi-Grater" data-dimension48="Communi-Grater" data-dimension25="$68">Communi-Grater: $68</a></strong><br />Le Creuset are known more for cookware than they are for kitchen accessories, but there's something extra special about this one. This greater plays on the Communicator with a quirky pun and a unique design to desire.<a class="view-deal button" href="https://www.lecreuset.com/signature-skillet/20182US.html" target="_blank" rel="nofollow" data-dimension112="433de514-aaba-11f1-840f-63fa391c57df" data-action="Deal Block" data-label="Communi-Grater" data-dimension48="Communi-Grater" data-dimension25="$68">View Deal</a></p></div><div class="product"><a data-dimension112="433de668-aaba-11f1-868d-fb080f159d20" data-action="Deal Block" data-label="Galileo Shuttlecraft Rectangular Casserole" data-dimension48="Galileo Shuttlecraft Rectangular Casserole" data-dimension25="$150" href="https://www.lecreuset.com/vancouver-mug/70317US.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="8QvQF6LU5t8Fto3vLjoDn8" name="lecreuset_galileocasserole" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/8QvQF6LU5t8Fto3vLjoDn8-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/vancouver-mug/70317US.html" target="_blank" rel="nofollow" data-dimension112="433de668-aaba-11f1-868d-fb080f159d20" data-action="Deal Block" data-label="Galileo Shuttlecraft Rectangular Casserole" data-dimension48="Galileo Shuttlecraft Rectangular Casserole" data-dimension25="$150">Galileo Shuttlecraft Rectangular Casserole: $150</a></strong><br />My favorite piece from the collection is this retro <em>Star Trek</em> twist on Le Creuset's iconic rectangular casserole dishes. A nod to the 1960s Galileo Shuttlecraft, it's equal parts nostalgia and cookware goodness.<a class="view-deal button" href="https://www.lecreuset.com/vancouver-mug/70317US.html" target="_blank" rel="nofollow" data-dimension112="433de668-aaba-11f1-868d-fb080f159d20" data-action="Deal Block" data-label="Galileo Shuttlecraft Rectangular Casserole" data-dimension48="Galileo Shuttlecraft Rectangular Casserole" data-dimension25="$150">View Deal</a></p></div><div class="product"><a data-dimension112="433de582-aaba-11f1-8881-0ddce702c4bc" data-action="Deal Block" data-label="Klingon Braiser with Klingon Trefoil Knob" data-dimension48="Klingon Braiser with Klingon Trefoil Knob" data-dimension25="$450" href="https://www.lecreuset.com/heritage-3-piece-rectangular-baking-dish-set/ST0098.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="SU5y49orWDCp43mFjBrG6T" name="lecreuset_klingonbraiser" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SU5y49orWDCp43mFjBrG6T-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.lecreuset.com/heritage-3-piece-rectangular-baking-dish-set/ST0098.html" target="_blank" rel="nofollow" data-dimension112="433de582-aaba-11f1-8881-0ddce702c4bc" data-action="Deal Block" data-label="Klingon Braiser with Klingon Trefoil Knob" data-dimension48="Klingon Braiser with Klingon Trefoil Knob" data-dimension25="$450">Klingon Braiser with Klingon Trefoil Knob: $450</a></strong><br />And Le Creuset have given another iconic cookware item, the Braiser, a "Star Trek" twist. To commemorate 60 years, it has replaced the trefoil knob with a Klingon emblem whilst embossing a Klingon starship on the lid – all in a striking dark blue.<a class="view-deal button" href="https://www.lecreuset.com/heritage-3-piece-rectangular-baking-dish-set/ST0098.html" target="_blank" rel="nofollow" data-dimension112="433de582-aaba-11f1-8881-0ddce702c4bc" data-action="Deal Block" data-label="Klingon Braiser with Klingon Trefoil Knob" data-dimension48="Klingon Braiser with Klingon Trefoil Knob" data-dimension25="$450">View Deal</a></p></div><ul><li><a href="https://www.tomsguide.com/home/revolutionary-for-homemade-bread-why-i-cant-wait-to-try-le-creusets-new-oval-bread-oven">'Revolutionary for homemade bread': Why I can't wait to try Le Creuset's new oval bread oven</a></li><li><a href="https://www.tomsguide.com/home/cast-iron-skillet-vs-dutch-oven-which-is-better">Cast iron skillet vs Dutch oven — which is better?</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/what-is-a-dutch-oven-everything-you-need-to-know-about-this-kitchen-essential">What is a Dutch oven — everything you need to know about this kitchen essential</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ How to help hummingbirds prepare for fall migration — 3 essential yard tweaks to do right now ]]></title>
                                                                                                <dc:content><![CDATA[ <p>As late summer transitions into autumn, North America’s smallest birds begin preparing for one of the most grueling journeys in the animal kingdom. </p><p>Before flying south to their wintering grounds in Mexico and Central America, many hummingbirds must fuel up for non-stop flights that, for some species, include a harrowing five-hundred-mile stretch across open water. </p><p>While natural environmental cues like decreasing daylight hours signal when it is time for them to depart, backyard bird feeders provide a crucial, high-energy pit stop along their migration highway.</p><h2 id="the-physics-of-migration">The physics of migration </h2><p>Understanding the extreme physical demands of migration highlights why suburban backyards matter so much in the fall. </p><p>In the weeks leading up to departure, <strong>hummingbirds enter a state of extreme hyperphagia, eating constantly to gain twenty-five to forty percent of their body weight</strong> in fat store reserves. This rapid fat gain is essential because their tiny bodies burn energy at an astounding rate. </p><p>During migration flight, a hummingbird's heart beats up to twelve hundred times per minute while its wings flap anywhere from fifteen to eighty times every second. </p><p><strong>Migration occurs in staggered waves</strong>, starting with adult males in late summer, followed by females, and finally young birds making the journey for the very first time well into fall. </p><h3 class="article-body__section" id="section-how-to-help-hummingbirds-prepare-for-migration"><span>How to help hummingbirds prepare for migration</span></h3><section class="howto-block">                    <h3>1. Keep feeders clean and fresh </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/jyfqJzPybUx5W8CPbFEXsU.jpg"                                        alt="Hummingbirds and feeder"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/jyfqJzPybUx5W8CPbFEXsU.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Supporting these passing travelers starts with proper feeder maintenance. Because migrating hummingbirds rely heavily on local yards to refuel quickly, keeping your nectar clean is essential.</p><p>Late-summer heat can easily ferment sugar water or cause toxic black mold buildup, which deters hungry visitors and spreads deadly tongue infections. </p><p><strong>Scrub your feeders every few days</strong> <strong>with hot water and a bottle brush, </strong>avoiding harsh detergents, and <strong>refill them with fresh liquid </strong>to ensure passing migrants get safe, reliable nutrition.</p></p>                </section><section class="howto-block">                    <h3>2. Stick to the classic nectar formula </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/YmEVmVK6myh7xSVdGjjjvB.jpg"                                        alt="Hummingbird drinking water"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/YmEVmVK6myh7xSVdGjjjvB.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>When mixing nectar at home, stick strictly to the classic recipe that mimics natural flower nectar. <strong>Combine four parts boiling water with one part pure white granulated sugar</strong>, stirring until completely dissolved. </p><p>Let the mixture cool completely before filling your feeder. You must a<strong>void using honey, brown sugar, artificial sweeteners, or red food dye</strong>, as these additives can cause fatal organ damage or infections.</p></p>                </section><section class="howto-block">                    <h3>3. The fall feeder myth: don't take them down too early</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/gUFPbrYWoziDa8GtaV2858.png"                                        alt="Hummingbird feeder near window"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/gUFPbrYWoziDa8GtaV2858.png"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>The biggest mistake well-meaning bird watchers make in the autumn is taking their feeders down too early out of fear that abundant food will trap the birds in cold weather. </p><p>However, leading ornithologists at organizations like the <a href="https://www.audubon.org/" target="_blank">National Audubon Society</a> confirm that food availability does not stop a hummingbird from migrating. Their instinct to head south is governed entirely by internal biological clocks and shortening daylight hours. </p><p><strong>Leaving your feeders up through October, or until two full weeks pass without a single sighting</strong>, provides a life-saving energy source for northern stragglers and late-season migrants passing through your neighborhood.</p></p>                </section><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-W0EvNO"></div>                            </div>                            <script src="https://kwizly.com/embed/W0EvNO.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/gardening/want-to-attract-hummingbirds-to-your-yard-it-turns-out-theres-a-sweet-spot-for-hanging-your-feeder">Want to attract hummingbirds to your yard? It turns out there's a sweet spot for hanging your feeder</a></li><li><a href="https://www.tomsguide.com/home/lawn-care/i-brought-my-brown-lawn-back-to-life-using-these-5-recovery-steps">I brought my brown lawn back to life using these 5 recovery steps</a></li><li><a href="https://www.tomsguide.com/home/want-more-songbirds-visiting-7-changes-that-bring-them-to-your-yard">Want more songbirds visiting? 7 changes that bring them to your yard</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/hummingbirds-are-getting-ready-to-migrate-3-things-you-must-do-in-your-yard-right-now</link>
                                                                            <description>
                            <![CDATA[ How to help hummingbirds prepare for fall migration — and why taking feeders down too early is a huge mistake. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">JWHBusSPSKFRzHm66KyPkY</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/oBewbsgqogPfU95PeXKorF-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 05 Sep 2026 11:45:00 +0000</pubDate>                                                                                                                                <updated>Mon, 07 Sep 2026 10:45:49 +0000</updated>
                                                                                                                                            <category><![CDATA[Gardening]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                <author><![CDATA[ kaycee.hill@futurenet.com (Kaycee Hill) ]]></author>                    <dc:creator><![CDATA[ Kaycee Hill ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/xHn6RmpEqg87cvtLwrBu9G-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/oBewbsgqogPfU95PeXKorF-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                        <media:description><![CDATA[Hummingbird and lilac flower]]></media:description>                                                            <media:text><![CDATA[Anna&#039;s Hummingbird]]></media:text>
                                <media:title type="plain"><![CDATA[Anna&#039;s Hummingbird]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/oBewbsgqogPfU95PeXKorF-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As late summer transitions into autumn, North America’s smallest birds begin preparing for one of the most grueling journeys in the animal kingdom. </p><p>Before flying south to their wintering grounds in Mexico and Central America, many hummingbirds must fuel up for non-stop flights that, for some species, include a harrowing five-hundred-mile stretch across open water. </p><p>While natural environmental cues like decreasing daylight hours signal when it is time for them to depart, backyard bird feeders provide a crucial, high-energy pit stop along their migration highway.</p><h2 id="the-physics-of-migration">The physics of migration </h2><p>Understanding the extreme physical demands of migration highlights why suburban backyards matter so much in the fall. </p><p>In the weeks leading up to departure, <strong>hummingbirds enter a state of extreme hyperphagia, eating constantly to gain twenty-five to forty percent of their body weight</strong> in fat store reserves. This rapid fat gain is essential because their tiny bodies burn energy at an astounding rate. </p><p>During migration flight, a hummingbird's heart beats up to twelve hundred times per minute while its wings flap anywhere from fifteen to eighty times every second. </p><p><strong>Migration occurs in staggered waves</strong>, starting with adult males in late summer, followed by females, and finally young birds making the journey for the very first time well into fall. </p><h3 class="article-body__section" id="section-how-to-help-hummingbirds-prepare-for-migration"><span>How to help hummingbirds prepare for migration</span></h3><section class="howto-block">                    <h3>1. Keep feeders clean and fresh </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/jyfqJzPybUx5W8CPbFEXsU.jpg"                                        alt="Hummingbirds and feeder"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/jyfqJzPybUx5W8CPbFEXsU.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Supporting these passing travelers starts with proper feeder maintenance. Because migrating hummingbirds rely heavily on local yards to refuel quickly, keeping your nectar clean is essential.</p><p>Late-summer heat can easily ferment sugar water or cause toxic black mold buildup, which deters hungry visitors and spreads deadly tongue infections. </p><p><strong>Scrub your feeders every few days</strong> <strong>with hot water and a bottle brush, </strong>avoiding harsh detergents, and <strong>refill them with fresh liquid </strong>to ensure passing migrants get safe, reliable nutrition.</p></p>                </section><section class="howto-block">                    <h3>2. Stick to the classic nectar formula </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="http://cdn.mos.cms.futurecdn.net/YmEVmVK6myh7xSVdGjjjvB.jpg"                                        alt="Hummingbird drinking water"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="http://cdn.mos.cms.futurecdn.net/YmEVmVK6myh7xSVdGjjjvB.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>When mixing nectar at home, stick strictly to the classic recipe that mimics natural flower nectar. <strong>Combine four parts boiling water with one part pure white granulated sugar</strong>, stirring until completely dissolved. </p><p>Let the mixture cool completely before filling your feeder. You must a<strong>void using honey, brown sugar, artificial sweeteners, or red food dye</strong>, as these additives can cause fatal organ damage or infections.</p></p>                </section><section class="howto-block">                    <h3>3. The fall feeder myth: don't take them down too early</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/gUFPbrYWoziDa8GtaV2858.png"                                        alt="Hummingbird feeder near window"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/gUFPbrYWoziDa8GtaV2858.png"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>The biggest mistake well-meaning bird watchers make in the autumn is taking their feeders down too early out of fear that abundant food will trap the birds in cold weather. </p><p>However, leading ornithologists at organizations like the <a href="https://www.audubon.org/" target="_blank">National Audubon Society</a> confirm that food availability does not stop a hummingbird from migrating. Their instinct to head south is governed entirely by internal biological clocks and shortening daylight hours. </p><p><strong>Leaving your feeders up through October, or until two full weeks pass without a single sighting</strong>, provides a life-saving energy source for northern stragglers and late-season migrants passing through your neighborhood.</p></p>                </section><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-W0EvNO"></div>                            </div>                            <script src="https://kwizly.com/embed/W0EvNO.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/gardening/want-to-attract-hummingbirds-to-your-yard-it-turns-out-theres-a-sweet-spot-for-hanging-your-feeder">Want to attract hummingbirds to your yard? It turns out there's a sweet spot for hanging your feeder</a></li><li><a href="https://www.tomsguide.com/home/lawn-care/i-brought-my-brown-lawn-back-to-life-using-these-5-recovery-steps">I brought my brown lawn back to life using these 5 recovery steps</a></li><li><a href="https://www.tomsguide.com/home/want-more-songbirds-visiting-7-changes-that-bring-them-to-your-yard">Want more songbirds visiting? 7 changes that bring them to your yard</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ It’s peak spider season — here’s what to look out for and how to keep them at bay this fall ]]></title>
                                                                                                <dc:content><![CDATA[ <p>If you’ve suddenly spotted more spiders in your home recently, you’re not the only one. Be it roaming along baseboards, lurking behind furniture, or on the ceiling, these creepy crawlies can be everywhere.</p><p>Not only can these pests hide in your home, but they can leave unsightly <a href="https://www.tomsguide.com/home/how-to-get-rid-of-cobwebs-and-keep-them-away">cobwebs</a> — which only add to your weekend cleaning chores. </p><p>According to pest control experts, September is the peak season for <a href="https://www.tomsguide.com/home/why-you-keep-getting-spiders-in-your-home-according-to-pest-control-experts">spiders</a>. This is because arachnids often begin their mating season from the end of August to late October as male spiders become more active to seek out their female counterparts. </p><p>Additionally, as they grow in size, larger spiders often venture into our homes to find a warm sanctuary and food sources.</p><p>While it can be alarming <a href="https://www.tomsguide.com/how-to/how-to-get-rid-of-spiders-and-keep-them-out-of-your-home">to get rid of spiders</a>, there are a few easy hacks you can do to keep them away. So before you get out the toxic repellents, check out these expert-approved tips to prevent a home invasion. </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Od2lJe"></div>                            </div>                            <script src="https://kwizly.com/embed/Od2lJe.js" async=""></script><h3 class="article-body__section" id="section-spray-white-vinegar-on-cotton-wool-pads"><span>Spray white vinegar on cotton wool pads</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3537px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="D934c2EELAYWbJw3CowXFe" name="White vinegar bottle on countertop" alt="White vinegar bottle on countertop" src="https://cdn.mos.cms.futurecdn.net/D934c2EELAYWbJw3CowXFe-1920-80.jpg" mos="" align="middle" fullscreen="" width="3537" height="1990" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">White vinegar bottle on countertop </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>White vinegar has many uses around the home, but it is also a great spider repellent. Again, this is thanks to its potent smell, which spiders hate and will stay away from.</p><p>“Another strong spell to help steer spiders away is white vinegar,” advises Helen Godsiff, brand manager at home improvement specialist <a href="https://www.eurocell.co.uk/" target="_blank">Eurocell</a>.<br /><br />“Mix two tablespoons in a solution with warm soapy water and dose cotton wool pads in the mixture. Dot them around potential entry points, such as window sills and door frames, to help keep them away.”</p><p>What’s more, if you’re battling with spiders outdoors or around your front porch, another top tip is to <a href="https://www.tomsguide.com/home/gardeners-urged-to-spray-patios-and-paths-with-vinegar-until-november-and-its-not-as-strange-as-it-sounds">spray patios and paths with vinegar</a>. While this won’t kill spiders, the strong scent will keep them at bay. </p><h3 class="article-body__section" id="section-the-peppermint-oil-method"><span>The peppermint oil method </span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1846px;"><p class="vanilla-image-block" style="padding-top:56.23%;"><img id="N6NvDdu2oRuGySJV7r7w95" name="Peppermint oil and cotton balls.jpg" alt="Peppermint oil and cotton balls on countertop" src="https://cdn.mos.cms.futurecdn.net/N6NvDdu2oRuGySJV7r7w95-1920-80.jpg" mos="" align="middle" fullscreen="" width="1846" height="1038" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Peppermint oil and cotton balls on countertop </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>While we might love this fresh scent, spiders hate the strong smell.</p><p>Simply mix a few drops of peppermint essential oil with water in a small bottle. Spray directly into corners, around cracks, and any other trouble areas where you often spot spiders. </p><p>“Peppermint is often viewed as a natural deterrent for critters like spiders, as the strong scent is thought to be unpleasant to them,” adds Godsiff.</p><p>Alternatively, you could soak cotton balls with the oil and place them around those hotspot areas where spiders often appear.</p><p>In fact, you could try any strong, plant-extracted oils such as eucalyptus or even cinnamon oil, which are all effective repellents for most household pests, including <a href="https://www.tomsguide.com/how-to/how-to-get-rid-of-mice">mice</a>, <a href="https://www.tomsguide.com/how-to/how-to-get-rid-of-ants">ants</a>, and more.</p><p><em><strong>NOTE: </strong></em><em>Do </em><em><strong>NOT </strong></em><em>use peppermint oil if you have pets as this is toxic when inhaled or ingested. </em></p><div class="product"><a data-dimension112="9332f470-a848-11f1-bd36-b9c0e8307528" data-action="Deal Block" data-label="Peppermint Essential Oil" data-dimension48="Peppermint Essential Oil" data-dimension25="$9" href="https://www.amazon.com/Handcraft-Peppermint-Essential-Oil-Therapeutic/dp/B0756MBLNX" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1083px;"><p class="vanilla-image-block" style="padding-top:138.50%;"><img id="C5bgA7yNE8JWTZ9kYwfZEn" name="Handcraft Blends Peppermint Essential Oil" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/C5bgA7yNE8JWTZ9kYwfZEn-1920-80.jpg" mos="" align="middle" fullscreen="" width="1083" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Handcraft-Peppermint-Essential-Oil-Therapeutic/dp/B0756MBLNX" target="_blank" rel="nofollow" data-dimension112="9332f470-a848-11f1-bd36-b9c0e8307528" data-action="Deal Block" data-label="Peppermint Essential Oil" data-dimension48="Peppermint Essential Oil" data-dimension25="$9">Peppermint Essential Oil: $9</a></strong><br />This pure peppermint oil is paraben free, and provides a fresh scent. Versatile to use in aromatherapy, or in an oil or reed diffuser. And while the fragrance is pleasant to our senses, it is also known to be a natural pest repellent.<a class="view-deal button" href="https://www.amazon.com/Handcraft-Peppermint-Essential-Oil-Therapeutic/dp/B0756MBLNX" target="_blank" rel="nofollow" data-dimension112="9332f470-a848-11f1-bd36-b9c0e8307528" data-action="Deal Block" data-label="Peppermint Essential Oil" data-dimension48="Peppermint Essential Oil" data-dimension25="$9">View Deal</a></p></div><h3 class="article-body__section" id="section-regularly-vacuum"><span>Regularly vacuum</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5742px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="LP39LNVQ8xm3qERGsg7inY" name="cleaning floor - crop.jpg" alt="Woman vacuum cleaning floor" src="https://cdn.mos.cms.futurecdn.net/LP39LNVQ8xm3qERGsg7inY-1920-80.jpg" mos="" align="middle" fullscreen="" width="5742" height="3230" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Woman vacuum cleaning floor </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Of course, if you want a spider-free home, always maintain regular cleaning and use a powerful <a href="https://www.tomsguide.com/best-picks/best-vacuum-cleaners">vacuum cleaner</a> to deal with cobwebs immediately. What’s more, spiders love to feast on any other insects, so keeping a clean space will be uninviting for them. </p><p>Also, remember to vacuum behind sofas, beds, under rugs, and any other hidden spaces where they might be lurking. </p><p>“As male spiders will be more visible during mating season, pay close attention to quiet areas around the house where webs have been formed,” adds Godsiff. “Don’t forget to also vacuum behind other hotspots for spiders such as behind sofas or inside ceiling lights". </p><p>For more tips, check out these <a href="https://www.tomsguide.com/home/5-common-places-spiders-love-to-hide-in-your-home">5 common places spiders love to hide in your home</a><u>.</u></p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/5-common-places-spiders-love-to-hide-in-your-home">5 common places spiders love to hide in your home</a></li><li><a href="https://www.tomsguide.com/home/pest-experts-warn-you-should-never-squash-spiders-in-your-home-heres-why">Pest experts warn you should never squash spiders in your home — here’s why</a></li><li><a href="https://www.tomsguide.com/how-to/9-plants-that-repel-spiders">9 plants that repel spiders and keep them out of your home</a></li></ul><div data-model-name="Essential Oils" data-widget-type="multimodelreview"></div> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/its-peak-spider-season-heres-what-to-look-out-for-and-how-to-keep-them-at-bay-this-fall</link>
                                                                            <description>
                            <![CDATA[ Why are there so many spiders in your home right now? Here’s why and how to keep them out. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">TtirVjiRdMp8qdDv9QFuCU</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/iCxCZMMcV23r5NrLyn8pfJ-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 04 Sep 2026 10:42:32 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Cynthia Lawrence ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/CCuSgQpd5NyZ46CgoF9cva-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/iCxCZMMcV23r5NrLyn8pfJ-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Spider crawling on floor]]></media:description>                                                            <media:text><![CDATA[Spider crawling on floor]]></media:text>
                                <media:title type="plain"><![CDATA[Spider crawling on floor]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/iCxCZMMcV23r5NrLyn8pfJ-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>If you’ve suddenly spotted more spiders in your home recently, you’re not the only one. Be it roaming along baseboards, lurking behind furniture, or on the ceiling, these creepy crawlies can be everywhere.</p><p>Not only can these pests hide in your home, but they can leave unsightly <a href="https://www.tomsguide.com/home/how-to-get-rid-of-cobwebs-and-keep-them-away">cobwebs</a> — which only add to your weekend cleaning chores. </p><p>According to pest control experts, September is the peak season for <a href="https://www.tomsguide.com/home/why-you-keep-getting-spiders-in-your-home-according-to-pest-control-experts">spiders</a>. This is because arachnids often begin their mating season from the end of August to late October as male spiders become more active to seek out their female counterparts. </p><p>Additionally, as they grow in size, larger spiders often venture into our homes to find a warm sanctuary and food sources.</p><p>While it can be alarming <a href="https://www.tomsguide.com/how-to/how-to-get-rid-of-spiders-and-keep-them-out-of-your-home">to get rid of spiders</a>, there are a few easy hacks you can do to keep them away. So before you get out the toxic repellents, check out these expert-approved tips to prevent a home invasion. </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Od2lJe"></div>                            </div>                            <script src="https://kwizly.com/embed/Od2lJe.js" async=""></script><h3 class="article-body__section" id="section-spray-white-vinegar-on-cotton-wool-pads"><span>Spray white vinegar on cotton wool pads</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3537px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="D934c2EELAYWbJw3CowXFe" name="White vinegar bottle on countertop" alt="White vinegar bottle on countertop" src="https://cdn.mos.cms.futurecdn.net/D934c2EELAYWbJw3CowXFe-1920-80.jpg" mos="" align="middle" fullscreen="" width="3537" height="1990" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">White vinegar bottle on countertop </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>White vinegar has many uses around the home, but it is also a great spider repellent. Again, this is thanks to its potent smell, which spiders hate and will stay away from.</p><p>“Another strong spell to help steer spiders away is white vinegar,” advises Helen Godsiff, brand manager at home improvement specialist <a href="https://www.eurocell.co.uk/" target="_blank">Eurocell</a>.<br /><br />“Mix two tablespoons in a solution with warm soapy water and dose cotton wool pads in the mixture. Dot them around potential entry points, such as window sills and door frames, to help keep them away.”</p><p>What’s more, if you’re battling with spiders outdoors or around your front porch, another top tip is to <a href="https://www.tomsguide.com/home/gardeners-urged-to-spray-patios-and-paths-with-vinegar-until-november-and-its-not-as-strange-as-it-sounds">spray patios and paths with vinegar</a>. While this won’t kill spiders, the strong scent will keep them at bay. </p><h3 class="article-body__section" id="section-the-peppermint-oil-method"><span>The peppermint oil method </span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1846px;"><p class="vanilla-image-block" style="padding-top:56.23%;"><img id="N6NvDdu2oRuGySJV7r7w95" name="Peppermint oil and cotton balls.jpg" alt="Peppermint oil and cotton balls on countertop" src="https://cdn.mos.cms.futurecdn.net/N6NvDdu2oRuGySJV7r7w95-1920-80.jpg" mos="" align="middle" fullscreen="" width="1846" height="1038" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Peppermint oil and cotton balls on countertop </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>While we might love this fresh scent, spiders hate the strong smell.</p><p>Simply mix a few drops of peppermint essential oil with water in a small bottle. Spray directly into corners, around cracks, and any other trouble areas where you often spot spiders. </p><p>“Peppermint is often viewed as a natural deterrent for critters like spiders, as the strong scent is thought to be unpleasant to them,” adds Godsiff.</p><p>Alternatively, you could soak cotton balls with the oil and place them around those hotspot areas where spiders often appear.</p><p>In fact, you could try any strong, plant-extracted oils such as eucalyptus or even cinnamon oil, which are all effective repellents for most household pests, including <a href="https://www.tomsguide.com/how-to/how-to-get-rid-of-mice">mice</a>, <a href="https://www.tomsguide.com/how-to/how-to-get-rid-of-ants">ants</a>, and more.</p><p><em><strong>NOTE: </strong></em><em>Do </em><em><strong>NOT </strong></em><em>use peppermint oil if you have pets as this is toxic when inhaled or ingested. </em></p><div class="product"><a data-dimension112="9332f470-a848-11f1-bd36-b9c0e8307528" data-action="Deal Block" data-label="Peppermint Essential Oil" data-dimension48="Peppermint Essential Oil" data-dimension25="$9" href="https://www.amazon.com/Handcraft-Peppermint-Essential-Oil-Therapeutic/dp/B0756MBLNX" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1083px;"><p class="vanilla-image-block" style="padding-top:138.50%;"><img id="C5bgA7yNE8JWTZ9kYwfZEn" name="Handcraft Blends Peppermint Essential Oil" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/C5bgA7yNE8JWTZ9kYwfZEn-1920-80.jpg" mos="" align="middle" fullscreen="" width="1083" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Handcraft-Peppermint-Essential-Oil-Therapeutic/dp/B0756MBLNX" target="_blank" rel="nofollow" data-dimension112="9332f470-a848-11f1-bd36-b9c0e8307528" data-action="Deal Block" data-label="Peppermint Essential Oil" data-dimension48="Peppermint Essential Oil" data-dimension25="$9">Peppermint Essential Oil: $9</a></strong><br />This pure peppermint oil is paraben free, and provides a fresh scent. Versatile to use in aromatherapy, or in an oil or reed diffuser. And while the fragrance is pleasant to our senses, it is also known to be a natural pest repellent.<a class="view-deal button" href="https://www.amazon.com/Handcraft-Peppermint-Essential-Oil-Therapeutic/dp/B0756MBLNX" target="_blank" rel="nofollow" data-dimension112="9332f470-a848-11f1-bd36-b9c0e8307528" data-action="Deal Block" data-label="Peppermint Essential Oil" data-dimension48="Peppermint Essential Oil" data-dimension25="$9">View Deal</a></p></div><h3 class="article-body__section" id="section-regularly-vacuum"><span>Regularly vacuum</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5742px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="LP39LNVQ8xm3qERGsg7inY" name="cleaning floor - crop.jpg" alt="Woman vacuum cleaning floor" src="https://cdn.mos.cms.futurecdn.net/LP39LNVQ8xm3qERGsg7inY-1920-80.jpg" mos="" align="middle" fullscreen="" width="5742" height="3230" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Woman vacuum cleaning floor </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Of course, if you want a spider-free home, always maintain regular cleaning and use a powerful <a href="https://www.tomsguide.com/best-picks/best-vacuum-cleaners">vacuum cleaner</a> to deal with cobwebs immediately. What’s more, spiders love to feast on any other insects, so keeping a clean space will be uninviting for them. </p><p>Also, remember to vacuum behind sofas, beds, under rugs, and any other hidden spaces where they might be lurking. </p><p>“As male spiders will be more visible during mating season, pay close attention to quiet areas around the house where webs have been formed,” adds Godsiff. “Don’t forget to also vacuum behind other hotspots for spiders such as behind sofas or inside ceiling lights". </p><p>For more tips, check out these <a href="https://www.tomsguide.com/home/5-common-places-spiders-love-to-hide-in-your-home">5 common places spiders love to hide in your home</a><u>.</u></p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/5-common-places-spiders-love-to-hide-in-your-home">5 common places spiders love to hide in your home</a></li><li><a href="https://www.tomsguide.com/home/pest-experts-warn-you-should-never-squash-spiders-in-your-home-heres-why">Pest experts warn you should never squash spiders in your home — here’s why</a></li><li><a href="https://www.tomsguide.com/how-to/9-plants-that-repel-spiders">9 plants that repel spiders and keep them out of your home</a></li></ul><div data-model-name="Essential Oils" data-widget-type="multimodelreview"></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Anker just launched a ton of new products at IFA 2026 — including an AI-powered home hub ]]></title>
                                                                                                <dc:content><![CDATA[ <p><a href="https://www.tomsguide.com/tag/ifa-2026">IFA 2026</a> is in full swing and Anker has made some pretty big announcements beyond just revealing a <a href="https://www.tomsguide.com/best-picks/best-magsafe-chargers-for-your-iphone-year">new MagSafe charger</a> or two. Not only has the company revealed a swathe of new products, including its own AI-powered home hub (we'll get to that shortly), but it's also revealed it will be unifying all of its brands under one name from here on out.</p><p>That means its five sub-brands, including well-known names like Eufy and Soundcore, will now all be recognized as Anker. Founder and CEO of Anker Innovations, Steven Yang, said: "Category brands made sense when categories were separate. They no longer are. One brand, one promise – Ultimate Innovation, now unified across everything we make."</p><p>Instead, Anker will now present its products in two groups: Anker for You and Anker for Home. And there are new additions to both. And, as mentioned, this new era for Anker has been accompanied by some big product reveals that are worth talking about.</p><h2 id="what-new-products-have-been-announced">What new products have been announced</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="saWMJuGJgwnWnqi5wWDULf" name="anker_powerbank" alt="The Anker MagGo Power Bank Pro 2 on the back of three smartphones" src="https://cdn.mos.cms.futurecdn.net/saWMJuGJgwnWnqi5wWDULf-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Anker)</span></figcaption></figure><p>During its IFA 2026 appearance, <strong>Anker revealed a whopping 22 new products</strong> including headphones, earbuds, power banks, chargers and more. But, there's definitely some that stand out to us here at Tom's Guide. Take the Anker eufy Robot Vacuum Omni E35, which joins the brand's existing lineup of robot vacs. Equipped with a HydroJet 2.0 Self-Cleaning Roller Mop and 35,000Pa of suction power, it looks set to take on the dirt and dust throughout your home.</p><p>Or, the new Soundcore earbuds, the AeroClip 2 and AeroClip 2 Pro, bringing Anker's THUS AI chip to an on-ear clip form to add AI voice recording, capturing meetings, phone calls and personal interactions, as well as transcribing and summarizing them. </p><p>And then there's the Anker MagGo Power Bank Pro 2 that claims it's "the world's fastest and coolest wireless power bank", as well as "the first magnetic power bank with a built-in cooling fan." According to Anker, it'll take your <a href="https://www.tomsguide.com/phones/iphones/apple-iphone-17-pro-review">iPhone 17 Pro</a> to 50% in just 25 minutes.</p><p>Not forgetting the Robot Lawn Mower S2 Max, which is Anker's first time developing a robot lawn mower <em>entirely</em> in-house. What's different about it? Well, Anker says it is fully autonomous with no boundary wires or RTK, plus an automatic extendable cutting arm. </p><p>When it comes to Anker's full IFA 2026 product announcement, though, the full range includes:</p><ul><li>Anker MindBase</li><li>Anker MindBase Security Kit</li><li>Anker Soundcore AeroClip 2 Pro</li><li>Anker Soundcore AeroClip 2</li><li>Anker Soundcore Space 2 Pro</li><li>Anker Soundcore Liberty Buds 2</li><li>Anker Sleep 4</li><li>Anker Sleep 4 Pro</li><li>Anker SleepLab</li><li>Anker SleepLab Pro</li><li>Anker MagGo Power Bank Pro 2</li><li>Anker Laptop Charger Pro</li><li>Anker MagStand Charging Station</li><li>Anker Eufy TrackLight Cam S1</li><li>Anker Eufy Video Doorbell S4</li><li>Anker Eufy Smart Security Shield</li><li>Anker Eufy NVR Security System E50</li><li>Anker Eufy Window Camera E10</li><li>Anker Eufy Fall Detection Sensor</li><li>Anker Eufy Robot Vacuum Omni E35</li><li>Anker Robot Lawn Mower S2 Max</li><li>Anker SOLIX Solarbank Max</li></ul><h2 id="introducing-anker-mindbase">Introducing Anker MindBase</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2560px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Htp7ApwwyXHiTYaDZGWnHY" name="Anker MindBase" alt="Anker MindBase" src="https://cdn.mos.cms.futurecdn.net/Htp7ApwwyXHiTYaDZGWnHY-1920-80.jpg" mos="" align="middle" fullscreen="" width="2560" height="1440" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Anker)</span></figcaption></figure><p>Of the 22 products announced during IFA 2026, there was one that particularly caught our eye — the Anker MindBase.</p><p>This is Anker's first AI hub that it hopes will bring "the truly autonomous home to life." It'll connect your Anker and Matter-compatible devices across your home into one system, working alongside the likes of Apple HomeKit, Amazon Alexa, and Google Home.</p><p>But it's also competing with these brands. The smart home hub space is busy with the likes of Google Nest and Amazon Echo, but for anyone who already owns a large number of Anker products, from Eufy vacuums to SOLIX power stations, this could be a tempting upgrade.</p><p>Anker uses what it calls a TrueSmart Agent to bring local intelligence across different areas of your home through dedicated AI agents. And with 48TB of expandable local storage, you can keep recordings, household data and even family photos inside your home safe.</p><p>While Anker has got a lot of new arrivals, it's not the only brand making waves at IFA 2026. You can <a href="https://www.tomsguide.com/tag/ifa-2026">follow all of our extensive coverage from Berlin's big tech show right here</a>. </p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/tech-events/ifa-2026-what-to-expect">What to expect at IFA 2026: AI everywhere, robots, laptops evolved, smarter homes and more</a></li><li><a href="https://www.tomsguide.com/home/this-portable-solar-generator-managed-to-restore-power-to-the-places-my-home-solar-system-couldnt-reach">I tested Anker's portable solar generator and it managed to bring power to places my home solar system couldn't reach</a></li><li><a href="https://www.tomsguide.com/home/smart-home/eufys-new-robot-vacuum-is-a-massive-upgrade-over-its-predecessor-at-half-the-price">Eufy's new robot vacuum is a massive upgrade over its predecessor — at half the price</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/anker-just-launched-a-ton-of-new-products-at-ifa-2026-including-an-ai-powered-home-hub</link>
                                                                            <description>
                            <![CDATA[ IFA 2026 is in full swing and Anker has some big announcements to make, including a unification of its brand, 22 new products and its very own AI home hub. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">cHGiRHcqxVWASkK6KVZygP</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/6MxBGKhBJQL6FvKrVdBiiT-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 03 Sep 2026 02:30:00 +0000</pubDate>                                                                                                                                <updated>Thu, 03 Sep 2026 08:07:01 +0000</updated>
                                                                                                                                            <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/6MxBGKhBJQL6FvKrVdBiiT-1920-80.jpg">
                                                            <media:credit><![CDATA[Anker]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Anker MindBase on a side table in a living room]]></media:description>                                                            <media:text><![CDATA[The Anker MindBase on a side table in a living room]]></media:text>
                                <media:title type="plain"><![CDATA[The Anker MindBase on a side table in a living room]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/6MxBGKhBJQL6FvKrVdBiiT-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p><a href="https://www.tomsguide.com/tag/ifa-2026">IFA 2026</a> is in full swing and Anker has made some pretty big announcements beyond just revealing a <a href="https://www.tomsguide.com/best-picks/best-magsafe-chargers-for-your-iphone-year">new MagSafe charger</a> or two. Not only has the company revealed a swathe of new products, including its own AI-powered home hub (we'll get to that shortly), but it's also revealed it will be unifying all of its brands under one name from here on out.</p><p>That means its five sub-brands, including well-known names like Eufy and Soundcore, will now all be recognized as Anker. Founder and CEO of Anker Innovations, Steven Yang, said: "Category brands made sense when categories were separate. They no longer are. One brand, one promise – Ultimate Innovation, now unified across everything we make."</p><p>Instead, Anker will now present its products in two groups: Anker for You and Anker for Home. And there are new additions to both. And, as mentioned, this new era for Anker has been accompanied by some big product reveals that are worth talking about.</p><h2 id="what-new-products-have-been-announced">What new products have been announced</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="saWMJuGJgwnWnqi5wWDULf" name="anker_powerbank" alt="The Anker MagGo Power Bank Pro 2 on the back of three smartphones" src="https://cdn.mos.cms.futurecdn.net/saWMJuGJgwnWnqi5wWDULf-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Anker)</span></figcaption></figure><p>During its IFA 2026 appearance, <strong>Anker revealed a whopping 22 new products</strong> including headphones, earbuds, power banks, chargers and more. But, there's definitely some that stand out to us here at Tom's Guide. Take the Anker eufy Robot Vacuum Omni E35, which joins the brand's existing lineup of robot vacs. Equipped with a HydroJet 2.0 Self-Cleaning Roller Mop and 35,000Pa of suction power, it looks set to take on the dirt and dust throughout your home.</p><p>Or, the new Soundcore earbuds, the AeroClip 2 and AeroClip 2 Pro, bringing Anker's THUS AI chip to an on-ear clip form to add AI voice recording, capturing meetings, phone calls and personal interactions, as well as transcribing and summarizing them. </p><p>And then there's the Anker MagGo Power Bank Pro 2 that claims it's "the world's fastest and coolest wireless power bank", as well as "the first magnetic power bank with a built-in cooling fan." According to Anker, it'll take your <a href="https://www.tomsguide.com/phones/iphones/apple-iphone-17-pro-review">iPhone 17 Pro</a> to 50% in just 25 minutes.</p><p>Not forgetting the Robot Lawn Mower S2 Max, which is Anker's first time developing a robot lawn mower <em>entirely</em> in-house. What's different about it? Well, Anker says it is fully autonomous with no boundary wires or RTK, plus an automatic extendable cutting arm. </p><p>When it comes to Anker's full IFA 2026 product announcement, though, the full range includes:</p><ul><li>Anker MindBase</li><li>Anker MindBase Security Kit</li><li>Anker Soundcore AeroClip 2 Pro</li><li>Anker Soundcore AeroClip 2</li><li>Anker Soundcore Space 2 Pro</li><li>Anker Soundcore Liberty Buds 2</li><li>Anker Sleep 4</li><li>Anker Sleep 4 Pro</li><li>Anker SleepLab</li><li>Anker SleepLab Pro</li><li>Anker MagGo Power Bank Pro 2</li><li>Anker Laptop Charger Pro</li><li>Anker MagStand Charging Station</li><li>Anker Eufy TrackLight Cam S1</li><li>Anker Eufy Video Doorbell S4</li><li>Anker Eufy Smart Security Shield</li><li>Anker Eufy NVR Security System E50</li><li>Anker Eufy Window Camera E10</li><li>Anker Eufy Fall Detection Sensor</li><li>Anker Eufy Robot Vacuum Omni E35</li><li>Anker Robot Lawn Mower S2 Max</li><li>Anker SOLIX Solarbank Max</li></ul><h2 id="introducing-anker-mindbase">Introducing Anker MindBase</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2560px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Htp7ApwwyXHiTYaDZGWnHY" name="Anker MindBase" alt="Anker MindBase" src="https://cdn.mos.cms.futurecdn.net/Htp7ApwwyXHiTYaDZGWnHY-1920-80.jpg" mos="" align="middle" fullscreen="" width="2560" height="1440" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Anker)</span></figcaption></figure><p>Of the 22 products announced during IFA 2026, there was one that particularly caught our eye — the Anker MindBase.</p><p>This is Anker's first AI hub that it hopes will bring "the truly autonomous home to life." It'll connect your Anker and Matter-compatible devices across your home into one system, working alongside the likes of Apple HomeKit, Amazon Alexa, and Google Home.</p><p>But it's also competing with these brands. The smart home hub space is busy with the likes of Google Nest and Amazon Echo, but for anyone who already owns a large number of Anker products, from Eufy vacuums to SOLIX power stations, this could be a tempting upgrade.</p><p>Anker uses what it calls a TrueSmart Agent to bring local intelligence across different areas of your home through dedicated AI agents. And with 48TB of expandable local storage, you can keep recordings, household data and even family photos inside your home safe.</p><p>While Anker has got a lot of new arrivals, it's not the only brand making waves at IFA 2026. You can <a href="https://www.tomsguide.com/tag/ifa-2026">follow all of our extensive coverage from Berlin's big tech show right here</a>. </p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/tech-events/ifa-2026-what-to-expect">What to expect at IFA 2026: AI everywhere, robots, laptops evolved, smarter homes and more</a></li><li><a href="https://www.tomsguide.com/home/this-portable-solar-generator-managed-to-restore-power-to-the-places-my-home-solar-system-couldnt-reach">I tested Anker's portable solar generator and it managed to bring power to places my home solar system couldn't reach</a></li><li><a href="https://www.tomsguide.com/home/smart-home/eufys-new-robot-vacuum-is-a-massive-upgrade-over-its-predecessor-at-half-the-price">Eufy's new robot vacuum is a massive upgrade over its predecessor — at half the price</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ iRobot's new flagship Roomba creates an airtight seal with your carpet — the competition should be worried ]]></title>
                                                                                                <dc:content><![CDATA[ <p>It’s been a busy year for iRobot. March brought the Roomba Mini — a new compact bot available in bold, playful colorways rarely seen in the category. May saw a massive release of eight new models, ranging from the entry-level 115 to the flagship 775. </p><p>Now, just in time for IFA and as we roll into September, the company has dropped another heavyweight. Enter the Roomba Max 875 Combo, pushing the 775 off the top spot. </p><p>With so many new models on the market, you’ve got to ask whether the world needs yet another robot vacuum? Apparently so.</p><p>Could the Roomba Max 875 Combo be the ultimate floor cleaning tool? At <a href="https://www.irobot.com/en_US/roomba-max-875-combo-robot-plus-autowash-dock/Z185020.html" target="_blank" rel="nofollow">$1,119 at iRobot</a>, I’ll let you decide if the features justify the price tag. I can’t wait to see how it compares to the <a href="https://www.tomsguide.com/home/dreame-x60-max-ultra-complete-review">Dreame X60 Max Ultra Complete</a>, which currently ranks as the<a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html"> best robot vacuum</a> in our buying guide.</p><h2 id="hard-floors-and-carpet-no-problem">Hard floors and carpet: No problem</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="dS2ykywVQWbg4ZnAMyhdqV" name="Roomba Max 875" alt="Roomba Max 875" src="https://cdn.mos.cms.futurecdn.net/dS2ykywVQWbg4ZnAMyhdqV-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: iRobot)</span></figcaption></figure><p>I spoke to Reena Patel, Floorcare Category Manager at iRobot, to learn more about iRobot’s flagship model. She says it was engineered to tackle the full spectrum of household messes, from deeply embedded debris to everyday dust and pet hair.  </p><p>“It combines serious cleaning power with smart automation, so customers can spend less time managing their floors and more time enjoying their homes and experiences outside their home, too,” Patel says. “It’s not just a smarter clean; it’s a stronger, deeper, and more effortless clean," which she adds is all handled through the app. </p><p>She explains that the Roomba Max 875 was designed around clear feedback iRobot repeatedly sees. “Customers continually want to experience a robot to deliver a tough stain clean. So if you’ve got debris locked into your carpets or liquid stains that are dried on your hard floors, you want the robot to be able to clean those away effectively.” </p><h2 id="what-does-the-roomba-max-875-combo-deliver">What does the Roomba Max 875 Combo deliver?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UsDxpmJh5NQ9mPaSx45s56" name="Roomba Max 875" alt="Roomba Max 875" src="https://cdn.mos.cms.futurecdn.net/UsDxpmJh5NQ9mPaSx45s56-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: iRobot)</span></figcaption></figure><p>So, what does iRobot’s latest model actually bring to the table? According to the company, the robot pairs proprietary <strong>SealForce vacuuming technology</strong> with a <strong>dual-action heated mopping system</strong>. The result is deep carpet cleaning, target stain removal on hard floors, and automated rug protection during mopping. </p><p><strong>Deep cleaning on carpets</strong><br />Let’s look at that more closely. SealForce does not rely on suction power alone; instead, the chassis lowers a dedicated skirt to create a tight seal against carpet fibers, concentrating vacuuming force directly where debris hides. </p><p>Paired with 20 L/s of tornado-like airflow and 35,000 Pa of suction, iRobot claims this delivers three times deeper carpet cleaning than systems without SealForce, making it their best pickup performance to date.  </p><p><strong>Tough on hard floor stains</strong><br />On hard surfaces, the vacuuming pairs with an advanced mopping system. iRobot’s ultrasonic <strong>ThermaMist technology</strong> continuously sprays a heated mist to soften and loosen dried-on spills so tough stains lift in a single pass — eliminating the need for manual scrubbing.  It could be a game-changer in the kitchen.</p><p>What’s more, this intelligent floor cleaner boasts a continuously self-cleaning <strong>PowerSpin Max roller mop </strong>— the industry’s largest according to iRobot. It scrubs with heated water at 300 RPM under 18 Newtons of downward pressure, delivering 3.75 times deeper scrubbing power and 1.2 times wider coverage per pass, compared to a standard PowerSpin roller mop.  </p><p><strong>Rug-safe mopping</strong> <br />When returning to carpets, the patented <strong>DriLift technology</strong> automatically detects carpeted areas, raises the mop roller, and lowers a protective shield to guarantee rugs remain completely dry throughout the run. That puts an end to stopping the robot mid-clean to remove a rug.  </p><p><strong>Sharp on edges</strong><br />The 875 also addresses the common pain point of robots not reaching the edges by delivering <strong>PerfectEdge cleaning</strong>, with an outward-expanding brush for corners.</p><p>However, despite all the tech, this model still can't climb stairs.</p><div class="product"><a data-dimension112="ec31572e-a6bd-11f1-9a0c-f1fd724aae38" data-action="Deal Block" data-label="Roomba Max 875 Combo robot + AutoWash dock" data-dimension48="Roomba Max 875 Combo robot + AutoWash dock" data-dimension25="$1199" href="https://www.irobot.com/en_US/roomba-max-875-combo-robot-plus-autowash-dock/Z185020.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="YWA5uyNArvwkBsPw8UVGuQ" name="Roomba Max 875" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/YWA5uyNArvwkBsPw8UVGuQ-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="2000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.irobot.com/en_US/roomba-max-875-combo-robot-plus-autowash-dock/Z185020.html" target="_blank" rel="nofollow" data-dimension112="ec31572e-a6bd-11f1-9a0c-f1fd724aae38" data-action="Deal Block" data-label="Roomba Max 875 Combo robot + AutoWash dock" data-dimension48="Roomba Max 875 Combo robot + AutoWash dock" data-dimension25="$1199">Roomba Max 875 Combo robot + AutoWash dock: $1199</a></strong><br />Designed for pro-level cleaning, this robot vacuum and mop combines powerful suction and SealForce Technology, with ultrasonic ThermaMist and a PowerSpin roller mop. <a class="view-deal button" href="https://www.irobot.com/en_US/roomba-max-875-combo-robot-plus-autowash-dock/Z185020.html" target="_blank" rel="nofollow" data-dimension112="ec31572e-a6bd-11f1-9a0c-f1fd724aae38" data-action="Deal Block" data-label="Roomba Max 875 Combo robot + AutoWash dock" data-dimension48="Roomba Max 875 Combo robot + AutoWash dock" data-dimension25="$1199">View Deal</a></p></div><h2 id="smart-cleaning-from-irobot">Smart cleaning from iRobot</h2><p>When paired with the Roomba app, you can make the most of personalized cleaning schedules, target specific rooms with heavier footfall like hallways and prioritize pet areas. You can even define whether you require a light, medium or deep clean.</p><p>And with Precision Vision AI, you shouldn’t have to worry about common floor hazards, such as pet bowls and children’s toys, as it recognizes over 300 common household objects. </p><p>We can't recommend iRobot’s latest flagship model without testing it, but it sure sounds impressive. Would you consider purchasing the 875 to clean your floors? Let me know in the comments below.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/home-appliances/best-robot-vacuums-of-ces-2026">The top robot vacuums we saw at CES 2026</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/best-robot-vacuums-for-pet-hair">We fought fur and mopped paw prints with the best robot vacuums for pet hair in 2026 — these 5 came out on top</a></li><li><a href="https://www.tomsguide.com/best-picks/best-vacuum-cleaners">Best vacuum cleaners 2026: Top picks for spotless floors</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/irobots-new-flagship-roomba-creates-an-airtight-seal-with-your-carpet-the-competition-should-be-worried</link>
                                                                            <description>
                            <![CDATA[ iRobot unveils the Roomba Max 875 Combo: Is it the ultimate floor cleaning tool? ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">vXGQpNwoCjaqnApdx7qHA5</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/yyBPERs5wVRPE9yP72cBzH-1920-80.png" type="image/png" length="0"></enclosure>
                                                                        <pubDate>Wed, 02 Sep 2026 13:12:14 +0000</pubDate>                                                                                                                                <updated>Wed, 16 Sep 2026 13:48:54 +0000</updated>
                                                                                                                                            <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                <author><![CDATA[ camilla.sharman@futurenet.com (Camilla Sharman) ]]></author>                    <dc:creator><![CDATA[ Camilla Sharman ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/nY4nvWzofHKHpvzAqN5LVH-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Camilla is the Homes Staff Writer and covers everything to do with homes and gardens. She has a wealth of editorial experience, mounting over 30 years, and covers news and features, tests products for reviews and compiles buying guides.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Her work has appeared in business and consumer titles, including Ideal Home, Real Homes, House Beautiful, Homebuilding &amp;amp; Renovation, and Kitchen &amp;amp; Bathroom Business. She’s even appeared on the cover of Your Home, writing about her own house renovation.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Although she’s obsessed with decorating her home, she also enjoys baking and trying out the latest kitchen appliances. But when she’s not inside, you’ll find her pottering about in her yard, tending to her vegetable patch or taking in her prized hydrangeas. She also enjoys keeping fit, and if she&#039;s not on a spin bike trying to keep up with the class, she&#039;ll be in the pool, or trying to perfect her headstand in a yoga class.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/png" url="https://cdn.mos.cms.futurecdn.net/yyBPERs5wVRPE9yP72cBzH-1920-80.png">
                                                            <media:credit><![CDATA[iRobot]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Roomba Max 875]]></media:description>                                                            <media:text><![CDATA[Roomba Max 875]]></media:text>
                                <media:title type="plain"><![CDATA[Roomba Max 875]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/yyBPERs5wVRPE9yP72cBzH-1920-80.png" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>It’s been a busy year for iRobot. March brought the Roomba Mini — a new compact bot available in bold, playful colorways rarely seen in the category. May saw a massive release of eight new models, ranging from the entry-level 115 to the flagship 775. </p><p>Now, just in time for IFA and as we roll into September, the company has dropped another heavyweight. Enter the Roomba Max 875 Combo, pushing the 775 off the top spot. </p><p>With so many new models on the market, you’ve got to ask whether the world needs yet another robot vacuum? Apparently so.</p><p>Could the Roomba Max 875 Combo be the ultimate floor cleaning tool? At <a href="https://www.irobot.com/en_US/roomba-max-875-combo-robot-plus-autowash-dock/Z185020.html" target="_blank" rel="nofollow">$1,119 at iRobot</a>, I’ll let you decide if the features justify the price tag. I can’t wait to see how it compares to the <a href="https://www.tomsguide.com/home/dreame-x60-max-ultra-complete-review">Dreame X60 Max Ultra Complete</a>, which currently ranks as the<a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html"> best robot vacuum</a> in our buying guide.</p><h2 id="hard-floors-and-carpet-no-problem">Hard floors and carpet: No problem</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="dS2ykywVQWbg4ZnAMyhdqV" name="Roomba Max 875" alt="Roomba Max 875" src="https://cdn.mos.cms.futurecdn.net/dS2ykywVQWbg4ZnAMyhdqV-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: iRobot)</span></figcaption></figure><p>I spoke to Reena Patel, Floorcare Category Manager at iRobot, to learn more about iRobot’s flagship model. She says it was engineered to tackle the full spectrum of household messes, from deeply embedded debris to everyday dust and pet hair.  </p><p>“It combines serious cleaning power with smart automation, so customers can spend less time managing their floors and more time enjoying their homes and experiences outside their home, too,” Patel says. “It’s not just a smarter clean; it’s a stronger, deeper, and more effortless clean," which she adds is all handled through the app. </p><p>She explains that the Roomba Max 875 was designed around clear feedback iRobot repeatedly sees. “Customers continually want to experience a robot to deliver a tough stain clean. So if you’ve got debris locked into your carpets or liquid stains that are dried on your hard floors, you want the robot to be able to clean those away effectively.” </p><h2 id="what-does-the-roomba-max-875-combo-deliver">What does the Roomba Max 875 Combo deliver?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UsDxpmJh5NQ9mPaSx45s56" name="Roomba Max 875" alt="Roomba Max 875" src="https://cdn.mos.cms.futurecdn.net/UsDxpmJh5NQ9mPaSx45s56-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: iRobot)</span></figcaption></figure><p>So, what does iRobot’s latest model actually bring to the table? According to the company, the robot pairs proprietary <strong>SealForce vacuuming technology</strong> with a <strong>dual-action heated mopping system</strong>. The result is deep carpet cleaning, target stain removal on hard floors, and automated rug protection during mopping. </p><p><strong>Deep cleaning on carpets</strong><br />Let’s look at that more closely. SealForce does not rely on suction power alone; instead, the chassis lowers a dedicated skirt to create a tight seal against carpet fibers, concentrating vacuuming force directly where debris hides. </p><p>Paired with 20 L/s of tornado-like airflow and 35,000 Pa of suction, iRobot claims this delivers three times deeper carpet cleaning than systems without SealForce, making it their best pickup performance to date.  </p><p><strong>Tough on hard floor stains</strong><br />On hard surfaces, the vacuuming pairs with an advanced mopping system. iRobot’s ultrasonic <strong>ThermaMist technology</strong> continuously sprays a heated mist to soften and loosen dried-on spills so tough stains lift in a single pass — eliminating the need for manual scrubbing.  It could be a game-changer in the kitchen.</p><p>What’s more, this intelligent floor cleaner boasts a continuously self-cleaning <strong>PowerSpin Max roller mop </strong>— the industry’s largest according to iRobot. It scrubs with heated water at 300 RPM under 18 Newtons of downward pressure, delivering 3.75 times deeper scrubbing power and 1.2 times wider coverage per pass, compared to a standard PowerSpin roller mop.  </p><p><strong>Rug-safe mopping</strong> <br />When returning to carpets, the patented <strong>DriLift technology</strong> automatically detects carpeted areas, raises the mop roller, and lowers a protective shield to guarantee rugs remain completely dry throughout the run. That puts an end to stopping the robot mid-clean to remove a rug.  </p><p><strong>Sharp on edges</strong><br />The 875 also addresses the common pain point of robots not reaching the edges by delivering <strong>PerfectEdge cleaning</strong>, with an outward-expanding brush for corners.</p><p>However, despite all the tech, this model still can't climb stairs.</p><div class="product"><a data-dimension112="ec31572e-a6bd-11f1-9a0c-f1fd724aae38" data-action="Deal Block" data-label="Roomba Max 875 Combo robot + AutoWash dock" data-dimension48="Roomba Max 875 Combo robot + AutoWash dock" data-dimension25="$1199" href="https://www.irobot.com/en_US/roomba-max-875-combo-robot-plus-autowash-dock/Z185020.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="YWA5uyNArvwkBsPw8UVGuQ" name="Roomba Max 875" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/YWA5uyNArvwkBsPw8UVGuQ-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="2000" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.irobot.com/en_US/roomba-max-875-combo-robot-plus-autowash-dock/Z185020.html" target="_blank" rel="nofollow" data-dimension112="ec31572e-a6bd-11f1-9a0c-f1fd724aae38" data-action="Deal Block" data-label="Roomba Max 875 Combo robot + AutoWash dock" data-dimension48="Roomba Max 875 Combo robot + AutoWash dock" data-dimension25="$1199">Roomba Max 875 Combo robot + AutoWash dock: $1199</a></strong><br />Designed for pro-level cleaning, this robot vacuum and mop combines powerful suction and SealForce Technology, with ultrasonic ThermaMist and a PowerSpin roller mop. <a class="view-deal button" href="https://www.irobot.com/en_US/roomba-max-875-combo-robot-plus-autowash-dock/Z185020.html" target="_blank" rel="nofollow" data-dimension112="ec31572e-a6bd-11f1-9a0c-f1fd724aae38" data-action="Deal Block" data-label="Roomba Max 875 Combo robot + AutoWash dock" data-dimension48="Roomba Max 875 Combo robot + AutoWash dock" data-dimension25="$1199">View Deal</a></p></div><h2 id="smart-cleaning-from-irobot">Smart cleaning from iRobot</h2><p>When paired with the Roomba app, you can make the most of personalized cleaning schedules, target specific rooms with heavier footfall like hallways and prioritize pet areas. You can even define whether you require a light, medium or deep clean.</p><p>And with Precision Vision AI, you shouldn’t have to worry about common floor hazards, such as pet bowls and children’s toys, as it recognizes over 300 common household objects. </p><p>We can't recommend iRobot’s latest flagship model without testing it, but it sure sounds impressive. Would you consider purchasing the 875 to clean your floors? Let me know in the comments below.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/home-appliances/best-robot-vacuums-of-ces-2026">The top robot vacuums we saw at CES 2026</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/best-robot-vacuums-for-pet-hair">We fought fur and mopped paw prints with the best robot vacuums for pet hair in 2026 — these 5 came out on top</a></li><li><a href="https://www.tomsguide.com/best-picks/best-vacuum-cleaners">Best vacuum cleaners 2026: Top picks for spotless floors</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I’ve been testing this robot vacuum with a compact design that takes care of itself for up to 65 days, and it’s quickly become a staple in my home ]]></title>
                                                                                                <dc:content><![CDATA[ <p>After spending the last year reviewing all of the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuums</a>, I know what to look for when it comes to getting value for your money. The Roborock Qrevo 2 Pro robot vacuum delivers reliable performance at a mid-range price that will please anyone looking for a helping set of hands (or wheels) around the house. </p><p>Vacuuming is effective, especially on hard floors, and mopping is impressive thanks to the dual circular mops. The small dock design will suit even smaller homes, and mapping through the app is quick and easy. </p><p>Unfortunately, it struggles to pick up hair and bumps into some obstacles with some force (so mind your legs), but overall, I think this is a great mid-range option. To find out more, you can keep reading this full Roborock Qrevo 2 Pro review.</p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-specs"><span>Roborock Qrevo 2 Pro review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/roborock-Qrevo-Pro-Vacuum-Suction/dp/B0GXFHY7Y2" target="_blank" rel="nofollow">$799</a> / <a href="https://www.amazon.co.uk/roborock-Qrevo-Curv-Zero-Tangle-Multifunctional/dp/B0G2SDJML8" target="_blank" rel="nofollow">£1,199</a></p></td></tr><tr><td class="firstcol " ><p><strong>Robot dimensions</strong></p></td><td  ><p>13.9 x 13.8 x 3.8 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Robot and dock dimensions</strong></p></td><td  ><p>19.5 x 17.7 x 15.8 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Robot and dock weight</strong></p></td><td  ><p>37.3 lbs</p></td></tr><tr><td class="firstcol " ><p><strong>Maximum suction power</strong></p></td><td  ><p>25,000Pa</p></td></tr><tr><td class="firstcol " ><p><strong>Mapping</strong></p></td><td  ><p>yes</p></td></tr><tr><td class="firstcol " ><p><strong>Mop function</strong></p></td><td  ><p>yes</p></td></tr><tr><td class="firstcol " ><p><strong>Self-emptying</strong></p></td><td  ><p>yes</p></td></tr><tr><td class="firstcol " ><p><strong>Self-cleaning/drying</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Onboard dustbin capacity</strong></p></td><td  ><p>11.8 fl oz</p></td></tr><tr><td class="firstcol " ><p><strong>Dock dustbin capacity</strong></p></td><td  ><p>2.7L</p></td></tr><tr><td class="firstcol " ><p><strong>Onboard water tank capacity</strong></p></td><td  ><p>4L</p></td></tr><tr><td class="firstcol " ><p><strong>App</strong></p></td><td  ><p>Roborock</p></td></tr><tr><td class="firstcol " ><p><strong>Battery</strong></p></td><td  ><p>6400mAh</p></td></tr><tr><td class="firstcol " ><p><strong>Runtime</strong></p></td><td  ><p>253 minutes</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-price-availability"><span>Roborock Qrevo 2 Pro review: Price &amp; availability</span></h2><p>The Roborock Qrevo 2 Pro is available for <a href="https://www.amazon.com/roborock-Qrevo-Pro-Vacuum-Suction/dp/B0GXFHY7Y2" target="_blank" rel="nofollow">$799 on Amazon U.S.</a> and <a href="https://www.amazon.co.uk/roborock-Qrevo-Curv-Zero-Tangle-Multifunctional/dp/B0G2SDJML8" target="_blank" rel="nofollow">£1,199 on Amazon U.K.</a> This is a mid-range robot vacuum that’s pretty small, but I think you get a lot of bang for your buck considering the cleaning performance. </p><p>It’s a little more expensive than the <a href="https://www.tomsguide.com/home/roborock-qv-35s-review">Roborock QV 35S</a>, which is available for $749, but this vacuum only has a suction power of 10,000Pa, whereas the Qrevo 2 Pro has 25,000Pa. It also performs better than the <a href="https://www.tomsguide.com/home/roborock-qrevo-curv-review">Roborock Qrevo Curv</a>, which costs $999, although they look very similar. If you have mostly hard flooring in your home and need more reliable mopping, I would recommend the Qrevo Pro 2. </p><p>The <a href="https://www.tomsguide.com/home/smart-home/ecovacs-deebot-t30s-combo-review">Ecovacs Deebot T30S</a> is $300 cheaper at $499 and provides an excellent clean. It even does well at picking up pet hair, so this could be a better option for pet owners, as the Qrevo 2 Pro doesn’t do the best job picking up hair. </p><p>It’s worth keeping in mind that if you have a lot of pets that shed fur or children running around, you may want something a little more heavy-duty. For this, I’d recommend splashing a few extra bucks and picking up one of the <a href="https://www.tomsguide.com/home/home-appliances/best-robot-vacuums-for-pet-hair">best robot vacuums for pet hair</a><u>,</u> such as the <a href="https://www.tomsguide.com/home/dreame-x60-max-ultra-complete-review">Dreame X60 Max Ultra Complete</a> for $1,699 or the <a href="https://www.tomsguide.com/home/home-appliances/roborock-saros-20-review">Roborock Saros 20</a> for $1,599. </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-design"><span>Roborock Qrevo 2 Pro review: Design</span></h2><p>The Roborock Qrevo 2 Pro, like most other Roborock products, looks sleek and will suit any home. It comes in black or white, so there’s an option for whatever your interior decor looks like. I tested the black colorway, and it looked good next to the rest of my home appliances. The dock measures 19.5 x 17.7 x 15.8 inches, making it compact as far as robot vacuums go. Together, the dock and vacuum weigh 37.3 lbs. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="a7TNKj8wKcXtknAwDVq6u8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/a7TNKj8wKcXtknAwDVq6u8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The <a href="https://www.tomsguide.com/home/dreame-d10-plus-gen-2-review">Dreame D10 Plus Gen 2</a> ($299) is another robot vacuum with a small dock, but this one only has a max suction power of 6,000Pa, meaning it’s only really good for hard floors. It’s great to see the Roborock incorporating high suction power into a dock with a smaller design.</p><p>The robot vacuum measures 13.9 x 13.8 x 3.8 inches, the same as the Roborock QV 35S, which isn’t too invasive. The Qrevo 2 Pro has a front bumper that is very reactive when it moves into furniture. Underneath the robot, there’s a side brush that rotates to kick up dust at the side of the room. On this model, the brush is also reversible, so it can, in theory, pick up more dust from the corners of the room. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="kviUcBedUzoVUqStDqqf48" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/kviUcBedUzoVUqStDqqf48-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>At the back of the robot vacuum, there are two circular mops. I much prefer circular mops, as they agitate the ground more, instead of wiping over it like the flat mop on the <a href="https://www.tomsguide.com/home/home-appliances/shark-powerdetect-2-in-1-thermacharged-nevertouch-review">Shark PowerDetect 2-in-1 ThermaCharged NeverTouch</a> ($1,199). </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-app"><span>Roborock Qrevo 2 Pro review: App</span></h2><p>The Roborock Qrevo 2 Pro is controlled via the Roborock app. This is free to download on iOS and Android devices. This isn’t my first time using the Roborock app, as it’s what I use to control my Roborock Saros 20 at home, so I’m familiar with the controls. But if you’ve never used it before, you get a walkthrough when you set up the device for the first time. </p><p>The app is easy to navigate. Vacuum controls are at the bottom of the screen where you can dictate the strength of the suction, the amount of water used by the mops, and how many passes the vacuum makes over the room. You control mapping at the top of the screen and can send the vacuum back to the dock with the click of a button. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="t9G2DuZKTSGbsrMnFMuSV8" name="qrevo 2 pro app" alt="screenshots from the Roborock app showing mapping and controls for the Roborock Qrevo 2 Pro" src="https://cdn.mos.cms.futurecdn.net/t9G2DuZKTSGbsrMnFMuSV8-1920-80.jpg" mos="" align="middle" fullscreen="1" width="1510" height="850" attribution="" endorsement="" class="inline expandable" /><a href='https://cdn.mos.cms.futurecdn.net/t9G2DuZKTSGbsrMnFMuSV8-1920-80.jpg' target='_blank' class='expand-button icon-expand-image icon' ></a></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Roborock)</span></figcaption></figure><p>You can watch the route the vacuum has taken on the app, where a line is tracked around the room. It also lets you know how many square meters it has cleaned and how long it’s been cleaning for, but unfortunately, it doesn’t tell you how much time is left in the routine.</p><p>Although I usually decline notifications from new apps, I recommend turning them on for the Roborock app because if anything happens to your robot, such as it becoming stuck, you’ll receive a handy notification so you know it needs a helping hand. </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-mapping"><span>Roborock Qrevo 2 Pro review: Mapping</span></h2><p>The first thing I did when I set up the Roborock Qrevo 2 Pro in the app was map the first floor of my house. This is done through the quick mapping setting in the app. </p><p>The robovac uses LiDAR navigation to create the layout, and this was very accurate. The LiDAR was so effective that it even mapped into the backyard. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="g7WgWrcpiw2LHATwoHtjv8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/g7WgWrcpiw2LHATwoHtjv8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The mapping took around 10 minutes to complete for four rooms. This process was a lot quicker than when I recently used the Dreame app. During this time, it noted obstacles such as chairs and marked them in the app with a small traffic cone icon so it knew to avoid them in the future. </p><p>My only issue here is the obstacle avoidance. The robovac has a bumper at the front, but it would crash pretty hard into things like sofa legs and the dining room table. It didn’t do any damage. But I found myself jumping a little each time it crashed. </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-cleaning"><span>Roborock Qrevo 2 Pro review: Cleaning</span></h2><p>I found the Roborock Qrevo 2 Pro to perform best on hard floors, though it struggled to pick up hair on all surfaces. The vacuum has a maximum suction power of 25,000 Pa, the setting I used to conduct my testing. This is good for a mid-range vacuum, as the Roborock QV 35S has a maximum suction power of 10,000Pa. </p><h3 id="vacuuming">Vacuuming</h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="8gqmaCTX9drBdgSMfAfGx8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/8gqmaCTX9drBdgSMfAfGx8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I tested how good the Roborock Qrevo 2 Pro is at vacuuming by carrying out our standardized testing criteria. This involved setting out quantities of hair, cereal and flaxseeds in a six-by-three-foot grid on both hardwood floor and carpet and measuring the amount of pickup during a standard cleaning cycle. </p><p><strong>Hardwood floor:</strong></p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UeKhkYbsTix256NxaxVEw8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/UeKhkYbsTix256NxaxVEw8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I was generally happy with how the robot vacuum performed on the hardwood floor. Robovacs tend to do a better job cleaning hard flooring, but I was a little disappointed by how much hair it failed to pick up. It seemed to be completely skipping over it, and some got trapped in the wheels. Pet owners will probably want to skip this robovac, as you’ll be left with fur on the floor.</p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Dustbin weight before</strong></p></td><td  ><p><strong>Dustbin weight after</strong></p></td><td  ><p><strong>Percentage of debris picked up</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Hair (5g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>39.5g</p></td><td  ><p>60%</p></td></tr><tr><td class="firstcol " ><p><strong>Rice Krispies (20g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>55g</p></td><td  ><p>92.5%</p></td></tr><tr><td class="firstcol " ><p><strong>Flaxseeds (20g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>54.9g</p></td><td  ><p>92%</p></td></tr></tbody></table></div><p>That said, it was clear the reversible side brush did a great job collecting the small seeds from the sides of the room. The vacuum performed far better than the <a href="https://www.tomsguide.com/home/dreame-d10-plus-gen-2-review">Dreame D10 Plus Gen 2</a> and was a lot more reliable for daily cleaning. </p><p><strong>Carpet:</strong></p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="obGAfkezTJVDCKf2Bxzyv8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/obGAfkezTJVDCKf2Bxzyv8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I was less impressed with the performance on carpet; since this is a mid-range vacuum, we should expect a middle-of-the-road performance. It struggled even more to pick up hair here, but thrived when picking up regular debris such as Rice Krispies.</p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Dustbin weight before</strong></p></td><td  ><p><strong>Dustbin weight after</strong></p></td><td  ><p><strong>Percentage of debris picked up</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Hair (5g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>38.9g</p></td><td  ><p>48%</p></td></tr><tr><td class="firstcol " ><p><strong>Rice Krispies (20g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>51.8g</p></td><td  ><p>76.5%</p></td></tr><tr><td class="firstcol " ><p><strong>Flax seeds (20g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>46.7g</p></td><td  ><p>51%</p></td></tr></tbody></table></div><p>Although these scores aren’t the best, when using the vacuum in my home over the course of a few days, I’ve been happy with the results. It left crisp vacuum lines in the carpet, and every room looked clean. I think the Roborock Qrevo 2 Pro is a good choice for everyday cleaning; it’s just not reliable for deep cleaning.</p><p>Unfortunately, for deeper cleaning from a robot vacuum, you will need to spend more money. If you live in a carpeted home, I would recommend the Dreame X60 Max Ultra Complete. Although it’s pricier, the result means you’ll spend less time following up with a handheld vacuum to deal with pet hair stuck in the carpet. </p><h3 id="mopping">Mopping</h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Jf77PFL3wYgdVATJ5MGXu8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/Jf77PFL3wYgdVATJ5MGXu8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>To test how well the Roborock Qrevo 2 Pro performs when mopping, I carried out my usual tests: soy sauce, mayonnaise and mud. </p><p>The robot vac did a great job of cleaning up every last drop with two passes of the room. More expensive flagship models feature heated mopping, but I think the Qrevo 2 Pro did a good job of getting my floors sparkling, even though it took a little longer since it had to do two passes to fully clean the floor. </p><p>After mopping, the dock will also clean and sock the mop pads at 167ºF before quietly drying them with 113ºF warm air. This is a feature I’m familiar with from flagship models, so it’s great to see it in a mid-range option. You don't get this luxury with the Dreame D10 Plus Gen 2, as you need to remove the mop pads and wash them yourself.</p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-storage-maintenance"><span>Roborock Qrevo 2 Pro review: Storage &amp; maintenance</span></h2><p>The Roborock Qrevo 2 Pro can maintain itself for up to 65 days, depending on usage. After each clean, the onboard dustbin empties into the dustbag in the dock. This bag has a capacity of 2.7 liters. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="rANQWsCNNMmVujWXqDgha8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/rANQWsCNNMmVujWXqDgha8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>On top of the Roborock dock station are two four-liter tanks: one for clean water and one for dirty water. Both can be removed for refilling and emptying. Once removed, they expose a hatch, which is where the removable dustbag can be found. It’s easy to access these components, and they’re not too heavy even when full, thanks to the handles.</p><p>The four-liter clean water tank is used for cleaning the mops and for refilling the robovac’s onboard water tank. The dirty water tank needs to be emptied regularly, but it can be left for up to 65 days. I prefer to empty it more regularly to avoid any unwanted smells. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="KoDNznpPjQD2QUxT5xzyD8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/KoDNznpPjQD2QUxT5xzyD8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Qrevo 2 Pro is a lot smaller than flagship models, making it a great choice if you’re short on space in your home. You just need to make sure you have a power outlet nearby to plug it in and that the robot has enough space to reverse back into the dock. </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-verdict"><span>Roborock Qrevo 2 Pro review: Verdict</span></h2><p>I think the Roborock Qrevo 2 Pro is a good choice for its mid-range price tag and effective vacuuming. The mopping performance is also good with circular rotating mops that scrub the floors to lift away all the grime. </p><p>The smaller docking station is ideal for smaller homes, and maintenance is still easy with up to 65 days of storage in the self-emptying dustbag and water tank. Mapping is also accurate and easy to set up in the Roborock app. </p><p>Unfortunately, the vacuum doesn’t do the best job when dealing with hair and has a tendency to bump into some obstacles with force. For anyone with hard floors who wants something to help with daily cleaning, the Qrevo 2 Pro is a good option because despite its flaws, it’s still great value for money.</p> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/roborock-qrevo-2-pro-review</link>
                                                                            <description>
                            <![CDATA[ The Roborock Qrevo 2 Pro is a mid-range vacuum that cleans hard floors masterfully, but it’s not the best for pet owners. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Krh659BWywz2RFjcmcyT2E</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/kmKLai5yRefPfwQwm2ydX7-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 28 Aug 2026 13:05:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/kmKLai5yRefPfwQwm2ydX7-1920-80.jpg">
                                                            <media:credit><![CDATA[Tom&amp;#39;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Roborock Qrevo 2 Pro in black photographed on carpet]]></media:description>                                                            <media:text><![CDATA[Roborock Qrevo 2 Pro in black photographed on carpet]]></media:text>
                                <media:title type="plain"><![CDATA[Roborock Qrevo 2 Pro in black photographed on carpet]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/kmKLai5yRefPfwQwm2ydX7-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>After spending the last year reviewing all of the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuums</a>, I know what to look for when it comes to getting value for your money. The Roborock Qrevo 2 Pro robot vacuum delivers reliable performance at a mid-range price that will please anyone looking for a helping set of hands (or wheels) around the house. </p><p>Vacuuming is effective, especially on hard floors, and mopping is impressive thanks to the dual circular mops. The small dock design will suit even smaller homes, and mapping through the app is quick and easy. </p><p>Unfortunately, it struggles to pick up hair and bumps into some obstacles with some force (so mind your legs), but overall, I think this is a great mid-range option. To find out more, you can keep reading this full Roborock Qrevo 2 Pro review.</p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-specs"><span>Roborock Qrevo 2 Pro review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/roborock-Qrevo-Pro-Vacuum-Suction/dp/B0GXFHY7Y2" target="_blank" rel="nofollow">$799</a> / <a href="https://www.amazon.co.uk/roborock-Qrevo-Curv-Zero-Tangle-Multifunctional/dp/B0G2SDJML8" target="_blank" rel="nofollow">£1,199</a></p></td></tr><tr><td class="firstcol " ><p><strong>Robot dimensions</strong></p></td><td  ><p>13.9 x 13.8 x 3.8 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Robot and dock dimensions</strong></p></td><td  ><p>19.5 x 17.7 x 15.8 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Robot and dock weight</strong></p></td><td  ><p>37.3 lbs</p></td></tr><tr><td class="firstcol " ><p><strong>Maximum suction power</strong></p></td><td  ><p>25,000Pa</p></td></tr><tr><td class="firstcol " ><p><strong>Mapping</strong></p></td><td  ><p>yes</p></td></tr><tr><td class="firstcol " ><p><strong>Mop function</strong></p></td><td  ><p>yes</p></td></tr><tr><td class="firstcol " ><p><strong>Self-emptying</strong></p></td><td  ><p>yes</p></td></tr><tr><td class="firstcol " ><p><strong>Self-cleaning/drying</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Onboard dustbin capacity</strong></p></td><td  ><p>11.8 fl oz</p></td></tr><tr><td class="firstcol " ><p><strong>Dock dustbin capacity</strong></p></td><td  ><p>2.7L</p></td></tr><tr><td class="firstcol " ><p><strong>Onboard water tank capacity</strong></p></td><td  ><p>4L</p></td></tr><tr><td class="firstcol " ><p><strong>App</strong></p></td><td  ><p>Roborock</p></td></tr><tr><td class="firstcol " ><p><strong>Battery</strong></p></td><td  ><p>6400mAh</p></td></tr><tr><td class="firstcol " ><p><strong>Runtime</strong></p></td><td  ><p>253 minutes</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-price-availability"><span>Roborock Qrevo 2 Pro review: Price &amp; availability</span></h2><p>The Roborock Qrevo 2 Pro is available for <a href="https://www.amazon.com/roborock-Qrevo-Pro-Vacuum-Suction/dp/B0GXFHY7Y2" target="_blank" rel="nofollow">$799 on Amazon U.S.</a> and <a href="https://www.amazon.co.uk/roborock-Qrevo-Curv-Zero-Tangle-Multifunctional/dp/B0G2SDJML8" target="_blank" rel="nofollow">£1,199 on Amazon U.K.</a> This is a mid-range robot vacuum that’s pretty small, but I think you get a lot of bang for your buck considering the cleaning performance. </p><p>It’s a little more expensive than the <a href="https://www.tomsguide.com/home/roborock-qv-35s-review">Roborock QV 35S</a>, which is available for $749, but this vacuum only has a suction power of 10,000Pa, whereas the Qrevo 2 Pro has 25,000Pa. It also performs better than the <a href="https://www.tomsguide.com/home/roborock-qrevo-curv-review">Roborock Qrevo Curv</a>, which costs $999, although they look very similar. If you have mostly hard flooring in your home and need more reliable mopping, I would recommend the Qrevo Pro 2. </p><p>The <a href="https://www.tomsguide.com/home/smart-home/ecovacs-deebot-t30s-combo-review">Ecovacs Deebot T30S</a> is $300 cheaper at $499 and provides an excellent clean. It even does well at picking up pet hair, so this could be a better option for pet owners, as the Qrevo 2 Pro doesn’t do the best job picking up hair. </p><p>It’s worth keeping in mind that if you have a lot of pets that shed fur or children running around, you may want something a little more heavy-duty. For this, I’d recommend splashing a few extra bucks and picking up one of the <a href="https://www.tomsguide.com/home/home-appliances/best-robot-vacuums-for-pet-hair">best robot vacuums for pet hair</a><u>,</u> such as the <a href="https://www.tomsguide.com/home/dreame-x60-max-ultra-complete-review">Dreame X60 Max Ultra Complete</a> for $1,699 or the <a href="https://www.tomsguide.com/home/home-appliances/roborock-saros-20-review">Roborock Saros 20</a> for $1,599. </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-design"><span>Roborock Qrevo 2 Pro review: Design</span></h2><p>The Roborock Qrevo 2 Pro, like most other Roborock products, looks sleek and will suit any home. It comes in black or white, so there’s an option for whatever your interior decor looks like. I tested the black colorway, and it looked good next to the rest of my home appliances. The dock measures 19.5 x 17.7 x 15.8 inches, making it compact as far as robot vacuums go. Together, the dock and vacuum weigh 37.3 lbs. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="a7TNKj8wKcXtknAwDVq6u8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/a7TNKj8wKcXtknAwDVq6u8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The <a href="https://www.tomsguide.com/home/dreame-d10-plus-gen-2-review">Dreame D10 Plus Gen 2</a> ($299) is another robot vacuum with a small dock, but this one only has a max suction power of 6,000Pa, meaning it’s only really good for hard floors. It’s great to see the Roborock incorporating high suction power into a dock with a smaller design.</p><p>The robot vacuum measures 13.9 x 13.8 x 3.8 inches, the same as the Roborock QV 35S, which isn’t too invasive. The Qrevo 2 Pro has a front bumper that is very reactive when it moves into furniture. Underneath the robot, there’s a side brush that rotates to kick up dust at the side of the room. On this model, the brush is also reversible, so it can, in theory, pick up more dust from the corners of the room. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="kviUcBedUzoVUqStDqqf48" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/kviUcBedUzoVUqStDqqf48-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>At the back of the robot vacuum, there are two circular mops. I much prefer circular mops, as they agitate the ground more, instead of wiping over it like the flat mop on the <a href="https://www.tomsguide.com/home/home-appliances/shark-powerdetect-2-in-1-thermacharged-nevertouch-review">Shark PowerDetect 2-in-1 ThermaCharged NeverTouch</a> ($1,199). </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-app"><span>Roborock Qrevo 2 Pro review: App</span></h2><p>The Roborock Qrevo 2 Pro is controlled via the Roborock app. This is free to download on iOS and Android devices. This isn’t my first time using the Roborock app, as it’s what I use to control my Roborock Saros 20 at home, so I’m familiar with the controls. But if you’ve never used it before, you get a walkthrough when you set up the device for the first time. </p><p>The app is easy to navigate. Vacuum controls are at the bottom of the screen where you can dictate the strength of the suction, the amount of water used by the mops, and how many passes the vacuum makes over the room. You control mapping at the top of the screen and can send the vacuum back to the dock with the click of a button. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="t9G2DuZKTSGbsrMnFMuSV8" name="qrevo 2 pro app" alt="screenshots from the Roborock app showing mapping and controls for the Roborock Qrevo 2 Pro" src="https://cdn.mos.cms.futurecdn.net/t9G2DuZKTSGbsrMnFMuSV8-1920-80.jpg" mos="" align="middle" fullscreen="1" width="1510" height="850" attribution="" endorsement="" class="inline expandable" /><a href='https://cdn.mos.cms.futurecdn.net/t9G2DuZKTSGbsrMnFMuSV8-1920-80.jpg' target='_blank' class='expand-button icon-expand-image icon' ></a></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Roborock)</span></figcaption></figure><p>You can watch the route the vacuum has taken on the app, where a line is tracked around the room. It also lets you know how many square meters it has cleaned and how long it’s been cleaning for, but unfortunately, it doesn’t tell you how much time is left in the routine.</p><p>Although I usually decline notifications from new apps, I recommend turning them on for the Roborock app because if anything happens to your robot, such as it becoming stuck, you’ll receive a handy notification so you know it needs a helping hand. </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-mapping"><span>Roborock Qrevo 2 Pro review: Mapping</span></h2><p>The first thing I did when I set up the Roborock Qrevo 2 Pro in the app was map the first floor of my house. This is done through the quick mapping setting in the app. </p><p>The robovac uses LiDAR navigation to create the layout, and this was very accurate. The LiDAR was so effective that it even mapped into the backyard. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="g7WgWrcpiw2LHATwoHtjv8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/g7WgWrcpiw2LHATwoHtjv8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The mapping took around 10 minutes to complete for four rooms. This process was a lot quicker than when I recently used the Dreame app. During this time, it noted obstacles such as chairs and marked them in the app with a small traffic cone icon so it knew to avoid them in the future. </p><p>My only issue here is the obstacle avoidance. The robovac has a bumper at the front, but it would crash pretty hard into things like sofa legs and the dining room table. It didn’t do any damage. But I found myself jumping a little each time it crashed. </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-cleaning"><span>Roborock Qrevo 2 Pro review: Cleaning</span></h2><p>I found the Roborock Qrevo 2 Pro to perform best on hard floors, though it struggled to pick up hair on all surfaces. The vacuum has a maximum suction power of 25,000 Pa, the setting I used to conduct my testing. This is good for a mid-range vacuum, as the Roborock QV 35S has a maximum suction power of 10,000Pa. </p><h3 id="vacuuming">Vacuuming</h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="8gqmaCTX9drBdgSMfAfGx8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/8gqmaCTX9drBdgSMfAfGx8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I tested how good the Roborock Qrevo 2 Pro is at vacuuming by carrying out our standardized testing criteria. This involved setting out quantities of hair, cereal and flaxseeds in a six-by-three-foot grid on both hardwood floor and carpet and measuring the amount of pickup during a standard cleaning cycle. </p><p><strong>Hardwood floor:</strong></p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UeKhkYbsTix256NxaxVEw8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/UeKhkYbsTix256NxaxVEw8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I was generally happy with how the robot vacuum performed on the hardwood floor. Robovacs tend to do a better job cleaning hard flooring, but I was a little disappointed by how much hair it failed to pick up. It seemed to be completely skipping over it, and some got trapped in the wheels. Pet owners will probably want to skip this robovac, as you’ll be left with fur on the floor.</p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Dustbin weight before</strong></p></td><td  ><p><strong>Dustbin weight after</strong></p></td><td  ><p><strong>Percentage of debris picked up</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Hair (5g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>39.5g</p></td><td  ><p>60%</p></td></tr><tr><td class="firstcol " ><p><strong>Rice Krispies (20g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>55g</p></td><td  ><p>92.5%</p></td></tr><tr><td class="firstcol " ><p><strong>Flaxseeds (20g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>54.9g</p></td><td  ><p>92%</p></td></tr></tbody></table></div><p>That said, it was clear the reversible side brush did a great job collecting the small seeds from the sides of the room. The vacuum performed far better than the <a href="https://www.tomsguide.com/home/dreame-d10-plus-gen-2-review">Dreame D10 Plus Gen 2</a> and was a lot more reliable for daily cleaning. </p><p><strong>Carpet:</strong></p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="obGAfkezTJVDCKf2Bxzyv8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/obGAfkezTJVDCKf2Bxzyv8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I was less impressed with the performance on carpet; since this is a mid-range vacuum, we should expect a middle-of-the-road performance. It struggled even more to pick up hair here, but thrived when picking up regular debris such as Rice Krispies.</p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Dustbin weight before</strong></p></td><td  ><p><strong>Dustbin weight after</strong></p></td><td  ><p><strong>Percentage of debris picked up</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Hair (5g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>38.9g</p></td><td  ><p>48%</p></td></tr><tr><td class="firstcol " ><p><strong>Rice Krispies (20g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>51.8g</p></td><td  ><p>76.5%</p></td></tr><tr><td class="firstcol " ><p><strong>Flax seeds (20g)</strong></p></td><td  ><p>36.5g</p></td><td  ><p>46.7g</p></td><td  ><p>51%</p></td></tr></tbody></table></div><p>Although these scores aren’t the best, when using the vacuum in my home over the course of a few days, I’ve been happy with the results. It left crisp vacuum lines in the carpet, and every room looked clean. I think the Roborock Qrevo 2 Pro is a good choice for everyday cleaning; it’s just not reliable for deep cleaning.</p><p>Unfortunately, for deeper cleaning from a robot vacuum, you will need to spend more money. If you live in a carpeted home, I would recommend the Dreame X60 Max Ultra Complete. Although it’s pricier, the result means you’ll spend less time following up with a handheld vacuum to deal with pet hair stuck in the carpet. </p><h3 id="mopping">Mopping</h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Jf77PFL3wYgdVATJ5MGXu8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/Jf77PFL3wYgdVATJ5MGXu8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>To test how well the Roborock Qrevo 2 Pro performs when mopping, I carried out my usual tests: soy sauce, mayonnaise and mud. </p><p>The robot vac did a great job of cleaning up every last drop with two passes of the room. More expensive flagship models feature heated mopping, but I think the Qrevo 2 Pro did a good job of getting my floors sparkling, even though it took a little longer since it had to do two passes to fully clean the floor. </p><p>After mopping, the dock will also clean and sock the mop pads at 167ºF before quietly drying them with 113ºF warm air. This is a feature I’m familiar with from flagship models, so it’s great to see it in a mid-range option. You don't get this luxury with the Dreame D10 Plus Gen 2, as you need to remove the mop pads and wash them yourself.</p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-storage-maintenance"><span>Roborock Qrevo 2 Pro review: Storage &amp; maintenance</span></h2><p>The Roborock Qrevo 2 Pro can maintain itself for up to 65 days, depending on usage. After each clean, the onboard dustbin empties into the dustbag in the dock. This bag has a capacity of 2.7 liters. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="rANQWsCNNMmVujWXqDgha8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/rANQWsCNNMmVujWXqDgha8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>On top of the Roborock dock station are two four-liter tanks: one for clean water and one for dirty water. Both can be removed for refilling and emptying. Once removed, they expose a hatch, which is where the removable dustbag can be found. It’s easy to access these components, and they’re not too heavy even when full, thanks to the handles.</p><p>The four-liter clean water tank is used for cleaning the mops and for refilling the robovac’s onboard water tank. The dirty water tank needs to be emptied regularly, but it can be left for up to 65 days. I prefer to empty it more regularly to avoid any unwanted smells. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="KoDNznpPjQD2QUxT5xzyD8" name="Roborock Qrevo 2 Pro" alt="Roborock Qrevo 2 Pro in black photographed on carpet" src="https://cdn.mos.cms.futurecdn.net/KoDNznpPjQD2QUxT5xzyD8-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Qrevo 2 Pro is a lot smaller than flagship models, making it a great choice if you’re short on space in your home. You just need to make sure you have a power outlet nearby to plug it in and that the robot has enough space to reverse back into the dock. </p><h2 class="article-body__section" id="section-roborock-qrevo-2-pro-review-verdict"><span>Roborock Qrevo 2 Pro review: Verdict</span></h2><p>I think the Roborock Qrevo 2 Pro is a good choice for its mid-range price tag and effective vacuuming. The mopping performance is also good with circular rotating mops that scrub the floors to lift away all the grime. </p><p>The smaller docking station is ideal for smaller homes, and maintenance is still easy with up to 65 days of storage in the self-emptying dustbag and water tank. Mapping is also accurate and easy to set up in the Roborock app. </p><p>Unfortunately, the vacuum doesn’t do the best job when dealing with hair and has a tendency to bump into some obstacles with force. For anyone with hard floors who wants something to help with daily cleaning, the Qrevo 2 Pro is a good option because despite its flaws, it’s still great value for money.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 13 best cooler deals on Amazon to shop before Labor Day Weekend — up to 44% on YETI, Ninja, Coleman and more ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Summer may be winding down, but there’s still plenty of time for Labor Day weekend picnics, barbecues, and getaways! If any of these sound like a part of your end of summer plans, you’ll likely need a little help keeping your snacks and drinks perfectly chilled. That’s why now is the time to invest in one of the <a href="https://www.tomsguide.com/best-picks/best-coolers">best coolers</a>.</p><p>A few of our favorite brands — like Ninja, Igloo, Coleman, YETI and more — are knocking <a href="https://www.amazon.com/camp-coolers/b/ref=dp_bc_5?ie=UTF8&amp;node=14335431" target="_blank" rel="nofollow">up to 44% off</a> select coolers. For instance, our favorite budget cooler, <a href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow">the Coleman Classic Series (70 qt), is down to just $67</a> right now. If you're looking for something with wheels, I'd suggest <a href="https://www.amazon.com/YETI-Roadie-Wheeled-Retractable-Periscope/dp/B0G62KNNXM/" target="_blank" rel="nofollow">the YETI Roadie 48 that's now $85 off</a>. </p><p>If you're not sure where to begin, keep scrolling to see my list of all the cooler deals I recommend for your Labor Day Weekend plans and beyond! You can also check out our <a href="https://www.tomsguide.com/coupons/amazon.com">Amazon promo codes</a> page.</p><h3 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h3><ul><li><a href="https://www.amazon.com/camp-coolers/b/ref=dp_bc_5?ie=UTF8&amp;node=14335431" target="_blank" rel="nofollow"><strong>shop cooler deals at Amazon</strong></a></li><li><strong>Coleman Classic Playmate Coolers: </strong><a href="https://www.amazon.com/Igloo-7362-Playmate-Personal-12-Inch/dp/B0B4X1WX2T?" target="_blank" rel="nofollow"><strong>was $33 now $25</strong></a></li><li><strong>Igloo Marine Cooler 25qt: </strong><a href="https://www.amazon.com/Igloo-Latitude-Marine-Ultra-Cooler/dp/B0BRL9S8L9" target="_blank" rel="nofollow"><strong>was $41 now $31</strong></a></li><li><strong>Coleman Classic Series Cooler 70qt: </strong><a href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow"><strong>was $94 now $67</strong></a></li><li><strong>Stanley All Day Julienne Soft Cooler: </strong><a href="https://www.amazon.com/STANLEY-Julienne-Handles-Insulated-BPA-Free/dp/B0DZ35RDQ1?" target="_blank" rel="nofollow"><strong>was $140 now $78</strong></a></li><li><strong>Ninja Backpack Cooler: </strong><a href="https://www.amazon.com/Ninja-Backpack-FrostVault-Leakproof-FF124CS/dp/B0F4Y5NDKM" target="_blank" rel="nofollow"><strong>was $199 now $179</strong></a></li><li><strong>YETI Hopper Flip 12: </strong><a href="https://www.amazon.com/dp/B0G62KNZFF?" target="_blank" rel="nofollow"><strong>was $250 now $200</strong></a></li></ul><h3 class="article-body__section" id="section-the-best-cooler-deals"><span>The Best Cooler Deals</span></h3><div class="product"><a data-dimension112="02cbb810-a152-11f1-af38-5bef563971c0" data-action="Deal Block" data-label="Chiller Soft Coolers" data-dimension48="Chiller Soft Coolers" data-dimension25="$24" href="https://www.amazon.com/Coleman-Chiller-Soft-Cooler-Ocean/dp/B09HN1WTY5?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:84.68%;"><img id="Mcx2Aj6u6FJ6mYMpxEcdBJ" name="Coleman Cooler.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/Mcx2Aj6u6FJ6mYMpxEcdBJ-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="575" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Coleman-Chiller-Soft-Cooler-Ocean/dp/B09HN1WTY5?" target="_blank" rel="nofollow" data-dimension112="02cbb810-a152-11f1-af38-5bef563971c0" data-action="Deal Block" data-label="Chiller Soft Coolers" data-dimension48="Chiller Soft Coolers" data-dimension25="$24">Chiller Soft Coolers: was $32 now $24</a></strong><br />This portable cooler is ideal for toting along food and beverages on your daily hiking excursions, trips to the beach or just keeping your drinks cold this summer. It will retain ice for 12 hours and you don't need to worry about spills thanks to its leakproof design. The cooler also features an adjustable padded sling strap and padded side handles for easy transporting to the top of the mountain.  <a class="view-deal button" href="https://www.amazon.com/Coleman-Chiller-Soft-Cooler-Ocean/dp/B09HN1WTY5?" target="_blank" rel="nofollow" data-dimension112="02cbb810-a152-11f1-af38-5bef563971c0" data-action="Deal Block" data-label="Chiller Soft Coolers" data-dimension48="Chiller Soft Coolers" data-dimension25="$24">View Deal</a></p></div><div class="product"><a data-dimension112="02cbb87e-a152-11f1-8a39-3d3d6fef76e1" data-action="Deal Block" data-label="Classic Playmate Coolers" data-dimension48="Classic Playmate Coolers" data-dimension25="$25" href="https://www.amazon.com/Igloo-7362-Playmate-Personal-12-Inch/dp/B0B4WY9YP6?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:96.13%;"><img id="RCnEs4JhY7VGfMrrMS2ZE" name="Classic Playmate Coolers" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/RCnEs4JhY7VGfMrrMS2ZE-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1442" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-7362-Playmate-Personal-12-Inch/dp/B0B4WY9YP6?" target="_blank" rel="nofollow" data-dimension112="02cbb87e-a152-11f1-8a39-3d3d6fef76e1" data-action="Deal Block" data-label="Classic Playmate Coolers" data-dimension48="Classic Playmate Coolers" data-dimension25="$25">Classic Playmate Coolers: was $33 now $25</a></strong><br />Perfect for lunch, picnics and work days, the Playmate cooler is ready to join you on your next adventure. It's designed to be very easy to hold and carry, and the push-button lid will help prevent spills. This 7qt cooler can fit 9 cans.<a class="view-deal button" href="https://www.amazon.com/Igloo-7362-Playmate-Personal-12-Inch/dp/B0B4WY9YP6?" target="_blank" rel="nofollow" data-dimension112="02cbb87e-a152-11f1-8a39-3d3d6fef76e1" data-action="Deal Block" data-label="Classic Playmate Coolers" data-dimension48="Classic Playmate Coolers" data-dimension25="$25">View Deal</a></p></div><div class="product"><a data-dimension112="02cbb8ec-a152-11f1-aa95-b976e406a246" data-action="Deal Block" data-label="Marine Cooler 25qt" data-dimension48="Marine Cooler 25qt" data-dimension25="$31" href="https://www.amazon.com/Igloo-Latitude-Marine-Ultra-Cooler/dp/B0BRL9S8L9" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:66.93%;"><img id="KCGTcWXbH8iR4k2Csb4b5j" name="Marine Cooler 25QT" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/KCGTcWXbH8iR4k2Csb4b5j-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1004" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-Latitude-Marine-Ultra-Cooler/dp/B0BRL9S8L9" target="_blank" rel="nofollow" data-dimension112="02cbb8ec-a152-11f1-aa95-b976e406a246" data-action="Deal Block" data-label="Marine Cooler 25qt" data-dimension48="Marine Cooler 25qt" data-dimension25="$31">Marine Cooler 25qt: was $46 now $31</a></strong><br />The perfect compact cooler, now with 33% off. This Igloo cooler has a 25qt capacity, space for 36 cans. The non-slip handles make it easy to carry, and there's even a fish ruler on top to measure your catch.<a class="view-deal button" href="https://www.amazon.com/Igloo-Latitude-Marine-Ultra-Cooler/dp/B0BRL9S8L9" target="_blank" rel="nofollow" data-dimension112="02cbb8ec-a152-11f1-aa95-b976e406a246" data-action="Deal Block" data-label="Marine Cooler 25qt" data-dimension48="Marine Cooler 25qt" data-dimension25="$31">View Deal</a></p></div><div class="product"><a data-dimension112="02cbb950-a152-11f1-bff0-a75b4eee8e7e" data-action="Deal Block" data-label="Marine Cooler 54qt" data-dimension48="Marine Cooler 54qt" data-dimension25="$54" href="https://www.amazon.com/Igloo-Marine-Ultra-Cooler-54-Quart/dp/B006H0L5TM" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:68.87%;"><img id="NBBUrFXtznQezDxoyyFSUd" name="Marine Cooler" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/NBBUrFXtznQezDxoyyFSUd-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1033" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-Marine-Ultra-Cooler-54-Quart/dp/B006H0L5TM" target="_blank" rel="nofollow" data-dimension112="02cbb950-a152-11f1-bff0-a75b4eee8e7e" data-action="Deal Block" data-label="Marine Cooler 54qt" data-dimension48="Marine Cooler 54qt" data-dimension25="$54">Marine Cooler 54qt: was $79 now $54</a></strong><br />This 54qt cooler is now on sale for $54 — a great discount. Our <a href="https://www.tomsguide.com/home/igloo-marine-ultra-cooler-review">Igloo Marine Ultra 54 review</a> said this cooler is very lightweight and keeps cold for two days straight. It's also easy to clean, which is a bonus.<a class="view-deal button" href="https://www.amazon.com/Igloo-Marine-Ultra-Cooler-54-Quart/dp/B006H0L5TM" target="_blank" rel="nofollow" data-dimension112="02cbb950-a152-11f1-bff0-a75b4eee8e7e" data-action="Deal Block" data-label="Marine Cooler 54qt" data-dimension48="Marine Cooler 54qt" data-dimension25="$54">View Deal</a></p></div><div class="product"><a data-dimension112="02cbb9be-a152-11f1-abe0-8d6a1e2a9aa2" data-action="Deal Block" data-label="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension48="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension25="$78" href="https://www.amazon.com/STANLEY-Julienne-Handles-Insulated-BPA-Free/dp/B0DZ35RDQ1?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1104px;"><p class="vanilla-image-block" style="padding-top:135.87%;"><img id="x2qTyESabmeEFV8zDktVG6" name="Stanley cooler" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/x2qTyESabmeEFV8zDktVG6-1920-80.jpg" mos="" align="middle" fullscreen="" width="1104" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/STANLEY-Julienne-Handles-Insulated-BPA-Free/dp/B0DZ35RDQ1?" target="_blank" rel="nofollow" data-dimension112="02cbb9be-a152-11f1-abe0-8d6a1e2a9aa2" data-action="Deal Block" data-label="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension48="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension25="$78">All Day Julienne Soft Cooler Bag and Lunch Box: was $140 now $78</a></strong><br />Need a new cooler for spring roadtrips, barbecues or beach days? This Stanley cooler bag is the perfect pick. It's currently only $78 and comes in a variety of vibrant colors that are perfect for summer. It fits up to 10 cans and will keep your food and drinks cold for hours. <a class="view-deal button" href="https://www.amazon.com/STANLEY-Julienne-Handles-Insulated-BPA-Free/dp/B0DZ35RDQ1?" target="_blank" rel="nofollow" data-dimension112="02cbb9be-a152-11f1-abe0-8d6a1e2a9aa2" data-action="Deal Block" data-label="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension48="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension25="$78">View Deal</a></p></div><div class="product"><a data-dimension112="02cbba2c-a152-11f1-835b-f5cf27696925" data-action="Deal Block" data-label="Classic Series Cooler 70qt" data-dimension48="Classic Series Cooler 70qt" data-dimension25="$67" href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:695px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="LLC8U9mUmqjs4623esUzGJ" name="Colemand Classic Cooler 70-quart" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/LLC8U9mUmqjs4623esUzGJ-1920-80.png" mos="" align="middle" fullscreen="" width="695" height="695" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow" data-dimension112="02cbba2c-a152-11f1-835b-f5cf27696925" data-action="Deal Block" data-label="Classic Series Cooler 70qt" data-dimension48="Classic Series Cooler 70qt" data-dimension25="$67">Classic Series Cooler 70qt: was $94 now $67</a></strong><br />The <a href="https://www.tomsguide.com/home/coleman-classic-cooler-review">Coleman Classic Cooler</a> isn't as fancy as some other brands, but this 70-quart version offers excellent capacity at a budget price. And that's why we recommend it as the best budget cooler in our buying guide. It can hold 100 cans, and doubles up as a seat — and if you're looking for a cooler to keep your catch on ice, it even has a fish ruler. It doesn't come with wheels, but with a discount we don't think you can ask for more.<a class="view-deal button" href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow" data-dimension112="02cbba2c-a152-11f1-835b-f5cf27696925" data-action="Deal Block" data-label="Classic Series Cooler 70qt" data-dimension48="Classic Series Cooler 70qt" data-dimension25="$67">View Deal</a></p></div><div class="product"><a data-dimension112="02cbba90-a152-11f1-babc-d3f24349b766" data-action="Deal Block" data-label="Polar Hard Coolers" data-dimension48="Polar Hard Coolers" data-dimension25="$115" href="https://www.amazon.com/Igloo-Polar-Cooler-120-Quart-White/dp/B004QILD6W" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:73.78%;"><img id="jFjwwiBUq7xKUtoEtNoUw3" name="Igloo coolers" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/jFjwwiBUq7xKUtoEtNoUw3-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="501" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-Polar-Cooler-120-Quart-White/dp/B004QILD6W" target="_blank" rel="nofollow" data-dimension112="02cbba90-a152-11f1-babc-d3f24349b766" data-action="Deal Block" data-label="Polar Hard Coolers" data-dimension48="Polar Hard Coolers" data-dimension25="$115">Polar Hard Coolers: was $129 now $115</a></strong><br />Perfect for your next roadtrip, family picnic or sporting event, this 120 qt. cooler features dual snap-fit latches to keep contents secure during transportation. It's also super easy to carry thanks to its swing-up handles. It even features a drain plug for easy draining. The cooler will retain ice for up to 5 days. <a class="view-deal button" href="https://www.amazon.com/Igloo-Polar-Cooler-120-Quart-White/dp/B004QILD6W" target="_blank" rel="nofollow" data-dimension112="02cbba90-a152-11f1-babc-d3f24349b766" data-action="Deal Block" data-label="Polar Hard Coolers" data-dimension48="Polar Hard Coolers" data-dimension25="$115">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbafe-a152-11f1-80a2-47f9511d1c8c" data-action="Deal Block" data-label="Iceless Thermoelectric Cooler" data-dimension48="Iceless Thermoelectric Cooler" data-dimension25="$145" href="https://www.amazon.com/Igloo-Portable-Electric-Coolers-Electrice/dp/B007ZYH4BM" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:122.24%;"><img id="fJtZwsva8iP3YAdyrUhXTP" name="Iceless Cooler" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fJtZwsva8iP3YAdyrUhXTP-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="830" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-Portable-Electric-Coolers-Electrice/dp/B007ZYH4BM" target="_blank" rel="nofollow" data-dimension112="02cbbafe-a152-11f1-80a2-47f9511d1c8c" data-action="Deal Block" data-label="Iceless Thermoelectric Cooler" data-dimension48="Iceless Thermoelectric Cooler" data-dimension25="$145">Iceless Thermoelectric Cooler: was $164 now $145</a></strong><br />This Igloo Iceless cooler is an ideal addition to any camping trip or road trip when you don't want to deal with ice. All you have to do is plug it into any 12V DC receptacle (cigarette lighter) and you'll be able to keep all your favorite drinks and snacks cold.<a class="view-deal button" href="https://www.amazon.com/Igloo-Portable-Electric-Coolers-Electrice/dp/B007ZYH4BM" target="_blank" rel="nofollow" data-dimension112="02cbbafe-a152-11f1-80a2-47f9511d1c8c" data-action="Deal Block" data-label="Iceless Thermoelectric Cooler" data-dimension48="Iceless Thermoelectric Cooler" data-dimension25="$145">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbb62-a152-11f1-8518-331e6fff5308" data-action="Deal Block" data-label="Pro Heavy-Duty 45qt" data-dimension48="Pro Heavy-Duty 45qt" data-dimension25="$149" href="https://www.amazon.com/Coleman-Ultra-Light-Extra-Thick-Insulation-Capacity/dp/B0DMW2Z6BP/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:71.47%;"><img id="e8w69SnKSZqpx46AUUAeY5" name="Coleman Pro" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/e8w69SnKSZqpx46AUUAeY5-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1072" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Coleman-Ultra-Light-Extra-Thick-Insulation-Capacity/dp/B0DMW2Z6BP/" target="_blank" rel="nofollow" data-dimension112="02cbbb62-a152-11f1-8518-331e6fff5308" data-action="Deal Block" data-label="Pro Heavy-Duty 45qt" data-dimension48="Pro Heavy-Duty 45qt" data-dimension25="$149">Pro Heavy-Duty 45qt: was $199 now $149</a></strong><br />The Coleman Pro 45qt is designed to be 30% lighter than other coolers of the same capacity, meaning you'll be able to carry your fully loaded cooler more easily. The cooler holds up to 74 cans without ice and stays cold for up to 4 days thanks to its fully insulated lid and body.<a class="view-deal button" href="https://www.amazon.com/Coleman-Ultra-Light-Extra-Thick-Insulation-Capacity/dp/B0DMW2Z6BP/" target="_blank" rel="nofollow" data-dimension112="02cbbb62-a152-11f1-8518-331e6fff5308" data-action="Deal Block" data-label="Pro Heavy-Duty 45qt" data-dimension48="Pro Heavy-Duty 45qt" data-dimension25="$149">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbbd0-a152-11f1-9777-090e704862a7" data-action="Deal Block" data-label="Backpack Cooler" data-dimension48="Backpack Cooler" data-dimension25="$179" href="https://www.amazon.com/Ninja-Backpack-FrostVault-Leakproof-FF124CS/dp/B0F4Y5NDKM" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:464px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="WW5AWCoTo6gey3CoZ7CHzk" name="Screenshot 2025-07-07 153631" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/WW5AWCoTo6gey3CoZ7CHzk-1920-80.jpg" mos="" align="middle" fullscreen="" width="464" height="464" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>If you have a smaller pack-up and can skip the wheels, Ninja's backpack cooler is just the ticket. It has a built-in cold dry zone to keep food dry and separate at under 40°F, holds ice for up to 24 hours, and has a top lid and side opening for easier access. It holds up to 24 cans, or 16 cans with ice. It even has a built in bottle opener.<a class="view-deal button" href="https://www.amazon.com/Ninja-Backpack-FrostVault-Leakproof-FF124CS/dp/B0F4Y5NDKM" target="_blank" rel="nofollow" data-dimension112="02cbbbd0-a152-11f1-9777-090e704862a7" data-action="Deal Block" data-label="Backpack Cooler" data-dimension48="Backpack Cooler" data-dimension25="$179">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbc52-a152-11f1-865b-913939bb659d" data-action="Deal Block" data-label="Hopper Flip 12 Soft Sided Cooler" data-dimension48="Hopper Flip 12 Soft Sided Cooler" data-dimension25="$200" href="https://www.amazon.com/dp/B0G62KNZFF?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1418px;"><p class="vanilla-image-block" style="padding-top:65.66%;"><img id="ezMMD2GC3rvaXXG9KUPRDA" name="yeti cooler" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ezMMD2GC3rvaXXG9KUPRDA-1920-80.jpg" mos="" align="middle" fullscreen="" width="1418" height="931" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0G62KNZFF?" target="_blank" rel="nofollow" data-dimension112="02cbbc52-a152-11f1-865b-913939bb659d" data-action="Deal Block" data-label="Hopper Flip 12 Soft Sided Cooler" data-dimension48="Hopper Flip 12 Soft Sided Cooler" data-dimension25="$200">Hopper Flip 12 Soft Sided Cooler: was $250 now $200</a></strong><br />This soft-sided cooler is perfect for day trips, picnics or outdoor adventures, and it's not too heavy to carry around. Compact and portable, it holds up to 13 cans and features a leakproof zipper, making it a must-have for on-the-go convenience.<a class="view-deal button" href="https://www.amazon.com/dp/B0G62KNZFF?" target="_blank" rel="nofollow" data-dimension112="02cbbc52-a152-11f1-865b-913939bb659d" data-action="Deal Block" data-label="Hopper Flip 12 Soft Sided Cooler" data-dimension48="Hopper Flip 12 Soft Sided Cooler" data-dimension25="$200">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbcb6-a152-11f1-952f-a109ca1c1321" data-action="Deal Block" data-label="Hopper M Series Backpack" data-dimension48="Hopper M Series Backpack" data-dimension25="$260" href="https://www.amazon.com/YETI-Hopper-Backpack-Cooler-MagShield/dp/B0DCW87YSY" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:94.55%;"><img id="W2bVFcrWaEYWduVsWR9Dri" name="YETI cooler backpack" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/W2bVFcrWaEYWduVsWR9Dri-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="642" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/YETI-Hopper-Backpack-Cooler-MagShield/dp/B0DCW87YSY" target="_blank" rel="nofollow" data-dimension112="02cbbcb6-a152-11f1-952f-a109ca1c1321" data-action="Deal Block" data-label="Hopper M Series Backpack" data-dimension48="Hopper M Series Backpack" data-dimension25="$260">Hopper M Series Backpack: was $325 now $260</a></strong><br />If you love adventure almost as much as you love beer, this convenient and secure backpack cooler is a must-have. The YETI Hopper can carry up to 36 cans of your favorite beverage while keeping your hands free — and most importantly, your drinks ice cold.<a class="view-deal button" href="https://www.amazon.com/YETI-Hopper-Backpack-Cooler-MagShield/dp/B0DCW87YSY" target="_blank" rel="nofollow" data-dimension112="02cbbcb6-a152-11f1-952f-a109ca1c1321" data-action="Deal Block" data-label="Hopper M Series Backpack" data-dimension48="Hopper M Series Backpack" data-dimension25="$260">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbd24-a152-11f1-82ad-bdd976aea89d" data-action="Deal Block" data-label="Roadie 48 Wheeled Cooler" data-dimension48="Roadie 48 Wheeled Cooler" data-dimension25="$340" href="https://www.amazon.com/YETI-Roadie-Wheeled-Retractable-Periscope/dp/B0G62KNNXM/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:926px;"><p class="vanilla-image-block" style="padding-top:161.99%;"><img id="4aLY8r3baTcT4isb6MCJK8" name="YETI Roadie 48" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4aLY8r3baTcT4isb6MCJK8-1920-80.jpg" mos="" align="middle" fullscreen="" width="926" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/YETI-Roadie-Wheeled-Retractable-Periscope/dp/B0G62KNNXM/" target="_blank" rel="nofollow" data-dimension112="02cbbd24-a152-11f1-82ad-bdd976aea89d" data-action="Deal Block" data-label="Roadie 48 Wheeled Cooler" data-dimension48="Roadie 48 Wheeled Cooler" data-dimension25="$340">Roadie 48 Wheeled Cooler: was $425 now $340</a></strong><br />Looking for a cooler that you can easily wheel around? This YETI Roadie the perfect find — especially right now since it rarely goes on sale. It can hold everything from wine bottles and soda cans to a whole watermelon. <a class="view-deal button" href="https://www.amazon.com/YETI-Roadie-Wheeled-Retractable-Periscope/dp/B0G62KNNXM/" target="_blank" rel="nofollow" data-dimension112="02cbbd24-a152-11f1-82ad-bdd976aea89d" data-action="Deal Block" data-label="Roadie 48 Wheeled Cooler" data-dimension48="Roadie 48 Wheeled Cooler" data-dimension25="$340">View Deal</a></p></div><h3 class="article-body__section" id="section-more-deals"><span>More Deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=outdoor&amp;view_mode=savings_squad&amp;widget_title=Top+Deals+Handpicked+by+Our+Editors&amp;widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&amp;bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function getTimeAgo(dateString) {        if (!dateString) return '';        const date = new Date(dateString);        const now = new Date();        const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);        if (diffInSeconds < 60) return 'Just now';        const diffInMinutes = Math.floor(diffInSeconds / 60);        if (diffInMinutes < 60) return `${diffInMinutes} min${diffInMinutes > 1 ? 's' : ''} ago`;        const diffInHours = Math.floor(diffInMinutes / 60);        if (diffInHours < 24) return `${diffInHours} hr${diffInHours > 1 ? 's' : ''} ago`;        const diffInDays = Math.floor(diffInHours / 24);        if (diffInDays < 30) return `${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`;        const diffInMonths = Math.floor(diffInDays / 30);        if (diffInMonths < 12) return `${diffInMonths} mo${diffInMonths > 1 ? 's' : ''} ago`;        const diffInYears = Math.floor(diffInDays / 365);        return `${diffInYears} yr${diffInYears > 1 ? 's' : ''} ago`;      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;      position: relative;      z-index: 20;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      margin: 0 auto;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {      display: grid;      width: 100%;      grid-template-columns: repeat(4, 1fr);      gap: 12px;      margin: 0 auto;      max-width: 800px;    }                 .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;      width: 100%;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      width: 100%;      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }    @container tg-df (max-width: 768px) {      .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {        width: 100%;        margin: 0;        margin-bottom: -320px;        padding: 0 16px 320px 16px;        display: flex;        flex-wrap: nowrap;        gap: 8px;        overflow-x: auto;        overflow-y: hidden;        pointer-events: none;        scrollbar-width: none;        -webkit-overflow-scrolling: touch;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }      .tg-df-sort-wrapper {        pointer-events: auto;        flex: 0 0 auto;        width: 175px;        min-width: 175px;      }    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 120px;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 16px 16px 8px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }                  .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;        width: auto;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;      width: 100vw;      max-width: 1200px;      position: relative;      left: 50%;      transform: translateX(-50%);    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 14px;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    .tg-df-grid-wrapper { position: relative; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn {      display: inline-flex;      align-items: center;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.40);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #1f69ff; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #0056e0; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }    .tg-df-savings-squad-header { margin-bottom: 24px; text-align: center; display: none; }    .tg-df-banner-img-desktop { display: block; width: 100%; height: auto; margin-bottom: 32px; }    .tg-df-banner-img-mobile { display: none; width: 100%; height: auto; margin-bottom: 32px; }    @container tg-df (max-width: 600px) {      .tg-df-banner-img-desktop { display: none; }      .tg-df-banner-img-mobile { display: block; }    }    .tg-df-header-title { font-size: 28px; font-weight: 700; color: var(--tg-df-text); margin: 32px 0 12px 0; line-height: 1.3; }    .tg-df-header-subtitle { font-size: 16px; color: var(--tg-df-text-muted); margin: 0 0 32px 0; line-height: 1.5; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3Cdiv class="tg-df-savings-squad-header" id="tg-df-savings-squad-header">      \x3Cpicture>        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/xkh2og7m3d1778189998.png" alt="Deals Banner" class="tg-df-banner-img-desktop" />        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/gmak6rtdf41778245089.png" alt="Deals Banner Mobile" class="tg-df-banner-img-mobile" />      \x3C/picture>      \x3Cdiv class="tg-df-header-text">        \x3Ch2 class="tg-df-header-title" id="tg-df-header-title">Editor's Choice Deals\x3C/h2>        \x3Cp class="tg-df-header-subtitle" id="tg-df-header-subtitle">Discover the best discounts currently available, curated daily by the Tom's Guide Savings Squad.\x3C/p>      \x3C/div>    \x3C/div>    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Televisions" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/wcMxTsHgqu3roMbAx7RLnT-132-100.png" alt="TVs" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">TVs\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Phones" data-pr="over50">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/G3KGaRGzj24F6PUsw4bWpT-132-100.png" alt="Phones" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Phones\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Computing" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/znNvsLzx8NEgNkD9HSFSnT-132-100.png" alt="Computing" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Computing\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Gaming" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/Pgew8yaRQeZFHqHjTzvBnT-132-100.png" alt="Gaming" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Gaming\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Mattresses" data-pr="over500">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/cW7xsaLyesxkHFVSiC4kmT-132-100.png" alt="Mattresses" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Mattresses\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Audio" data-pr="over30">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/pCvBVHuhaQVjKt3VgCjbqT-132-100.png" alt="Audio" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Audio\x3C/span>            \x3C/div>                  \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E      \x3Cdiv class="tg-df-top-bar" id="tg-df-top-bar" style="position: relative; z-index: 100; margin: 0 auto 20px;">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>      \x3C/div>    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">              \x3Cdiv class="tg-df-filters-container" style="position: relative; width: 100%; max-width: 800px; margin: 0 auto;">          \x3Cbutton class="tg-df-scroll-btn left" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: -200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M15 18l-6-6 6-6"/>\x3C/svg>          \x3C/button>          \x3Cbutton class="tg-df-scroll-btn right" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: 200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M9 18l6-6-6-6"/>\x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-filters">          \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>          \x3C/div>        \x3C/div>        \x3C/div>      \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();        }        getViewMode() {          console.log("DEBUG getViewMode -> override:", this.viewModeOverride, "editorMode:", this.editorMode);          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          console.log("[DEBUG] applyLayoutMode CALLED! mode=", mode);          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          const showHeaderDetails = params.get('show_header_details') !== 'false';          const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          const topBarDiv = this.root.querySelector('#tg-df-top-bar');          const headerElement = this.root.querySelector('#tg-df-savings-squad-header');          if (headerElement) {             headerElement.style.display = (mode === 'savings_squad' && showHeaderDetails) ? 'block' : 'none';          }          if (mode === 'carousel') {             this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (topBarDiv) topBarDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.add('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (topBarDiv) topBarDiv.style.display = 'block';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!this.viewModeOverride && initialViewMode) {            this.viewModeOverride = initialViewMode;          }          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Gaming laptops';          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button, .tg-df-container .tg-df-card-cta { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover, .tg-df-container .tg-df-card-cta:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (this.viewModeSelect && params.has('view_mode')) {            this.viewModeSelect.value = params.get('view_mode');          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'date_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }          const headerTitleEl = this.root.querySelector('#tg-df-header-title');          const headerSubtitleEl = this.root.querySelector('#tg-df-header-subtitle');          if (params.has('widget_title') && headerTitleEl) {             headerTitleEl.textContent = params.get('widget_title');          }          if (params.has('widget_subtitle') && headerSubtitleEl) {             headerSubtitleEl.textContent = params.get('widget_subtitle');          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            if (this.getViewMode() === 'savings_squad') {              this.searchInput.value = '';            } else {              this.searchInput.value = this.currentQuery;            }          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'date_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const handleFiltersScroll = () => {            const filters = this.root.querySelector('.tg-df-filters');            const leftBtn = this.root.querySelector('.tg-df-scroll-btn.left');            const rightBtn = this.root.querySelector('.tg-df-scroll-btn.right');            if (filters && leftBtn && rightBtn) {              const { scrollLeft, scrollWidth, clientWidth } = filters;              leftBtn.style.display = scrollLeft > 0 ? 'flex' : 'none';              rightBtn.style.display = Math.ceil(scrollLeft + clientWidth) < scrollWidth - 5 ? 'flex' : 'none';            }          };          const filters = this.root.querySelector('.tg-df-filters');          if (filters) {            filters.addEventListener('scroll', handleFiltersScroll);            window.addEventListener('resize', handleFiltersScroll);            setTimeout(handleFiltersScroll, 100);                        // Also call after rendering dropdowns            const origRenderCategories = this.renderCategories;            if (origRenderCategories) {               this.renderCategories = (...args) => {                 origRenderCategories.apply(this, args);                 setTimeout(handleFiltersScroll, 50);               };            }          }                const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          const showAutocomplete = () => {             if (this.getViewMode() !== 'savings_squad' || !this.autocompleteDropdown || !this.airedaleTags) return;                          let terms = this.airedaleTags;             if (this.airedaleBrands) {                terms = terms.concat(this.airedaleBrands.map(b => b.formatted_value));             }             terms = [...new Set(terms)];                          const query = this.searchInput.value.trim();             let matches = [];             if (query.length > 0) {                 matches = terms.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase());             } else {                 matches = terms;             }                          if (matches.length > 0) {                 this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                 this.autocompleteDropdown.classList.add('active');             } else {                 this.autocompleteDropdown.classList.remove('active');             }          };          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('focus', showAutocomplete);            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              showAutocomplete();              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  if (this.getViewMode() === 'savings_squad') {                    this.activeDealTag = null;                    this.currentQuery = '';                    if (this.categoryFilter) this.categoryFilter.value = 'all';                    this.fetchDeals('');                  } else {                    this.deals = [];                    this.render();                  }                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                                let isTag = false;                if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;                if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;                this.activeDealTag = isTag ? query : null;                                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   if (query.length === 0 && this.getViewMode() === 'savings_squad') {                       if (this.categoryFilter) this.categoryFilter.value = 'all';                   }                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   if (this.categoryFilter && this.airedaleTags.includes(tag)) {                       this.categoryFilter.value = tag;                   }                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                            let isTag = false;              if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;              if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;              this.activeDealTag = isTag ? query : null;                            this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 if (query.length === 0 && this.getViewMode() === 'savings_squad') {                     if (this.categoryFilter) this.categoryFilter.value = 'all';                 }                 this.fetchDeals(query);              }            });          }          if(this.sortSelect && this.sortSelect.querySelector('option[value="date_desc"]') === null) {              const option = document.createElement('option');              option.value = "date_desc";              option.text = "Newest First";              this.sortSelect.insertBefore(option, this.sortSelect.firstChild);          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               if (val) {                 this.currentQuery = val;               } else {                 if (this.searchInput && this.currentQuery === document.querySelector('#tg-df-brand-trigger')?.getAttribute('data-active-brand')) {                     // don't clear current query if a brand is selected                 } else if (this.searchInput) {                     this.currentQuery = '';                     this.searchInput.value = '';                 }               }               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = 'date_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const rewrittenLink = cardLink.getAttribute('href');                const revenueId = cardLink.getAttribute('data-revenue-id');                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getRowsLimit() {          if (this.rowsSelect && this.rowsSelect.value) return parseInt(this.rowsSelect.value, 10);          let configSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {             configSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {             configSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(configSource);          if (params.has('rows')) return parseInt(params.get('rows'), 10) || 12;          return 12;        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }        async fetchDeals(query) {          this.showLoading();          this.deals = [];          this.displayLimit = this.getRowsLimit();                    try {            console.log("getViewMode returns:", this.getViewMode());            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad();            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query);               } else {                 await this.fetchHawkDeals(query);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const siteParam = this.website || 'tomsguide';            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=${siteParam}&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (!this.activeDealTag && this.currentQuery) {             const tagMatch = this.airedaleTags.find(t => t.toLowerCase() === this.currentQuery.toLowerCase());             if (tagMatch) {                this.activeDealTag = tagMatch;             }          }          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const siteParam = this.website || 'tomsguide';             const url = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let seenUrls = new Set();                    let overallBrandsCounts = {};                    // First pass: extract ALL brands from topArticles so the dropdown has all options          topArticles.forEach((article) => {             if (!article.articlepage) return;             let pageData = [];             try { pageData = JSON.parse(article.articlepage[0]); } catch(e){ console.warn(e); }             const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');             savingsSquad.forEach((block) => {                const data = block.data || {};                if (data.brand) {                   const cleanBrand = data.brand.replace(/^\d+\.\s*/, '').trim();                   overallBrandsCounts[cleanBrand] = (overallBrandsCounts[cleanBrand] || 0) + 1;                }             });          });          targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim();                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                if (externalUrl) {                   if (seenUrls.has(externalUrl)) return;                  seenUrls.add(externalUrl);                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || '',                   authorName: article.articleauthortext ? article.articleauthortext[0] : (article.articleauthor ? article.articleauthor[0] : ''),                   authorRole: article.articleauthorrole ? article.articleauthorrole[0] : '',                   authorImage: article.articleauthormedia ? article.articleauthormedia[0] : '',                   documentUrl: article.documenturl ? article.documenturl[0] : '',                   modifiedDate: article.contentmodifieddate || article.modifieddate || ''                });             });          });                    const airedaleBrandsList = Object.keys(overallBrandsCounts).map(b => ({              formatted_value: b,              count: overallBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    url.searchParams.append('rows', this.getRowsLimit().toString());          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = this.getRowsLimit();          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: item.name || item.title || item.model_name || item.product_name || 'Unknown Product',            brand: item.brand || '',            productName: item.model_name || item.product_name || item.name || '',            merchant: item.merchant_name || item.merchant || item.retailer || 'Retailer',            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : 'date_desc';          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                ${_div}              ${_div}              \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin:0; border-radius:0;">${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const rewrittenLink = btn.getAttribute('href');                const revenueId = btn.getAttribute('data-revenue-id');                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)}${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = 'View Deal';              if (isSavingsSquadMode) {                priceGroupHtml = ``;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = isSavingsSquadMode ? `` : `                \x3Cdiv class="tg-df-card-price-group">                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                          \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                          \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                            var c = this.parentNode;                            if (this.dataset.expanded === 'true') {                              var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                              if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                              pd.style.display = '-webkit-box';                              pd.style.webkitLineClamp = '3';                              this.textContent = 'READ MORE';                              this.style.position = 'absolute';                              this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                              this.style.paddingLeft = '16px';                              this.dataset.expanded = 'false';                            } else {                              var pd = this.previousElementSibling;                              pd.style.display = 'inline';                              pd.style.webkitLineClamp = 'unset';                              this.textContent = 'READ LESS';                              this.style.position = 'static';                              this.style.background = 'transparent';                              this.style.paddingLeft = '4px';                              this.dataset.expanded = 'true';                              pd.appendChild(this);                            }                          ">READ MORE${_button}                        \x3C/div>` : ''}                      ${_div}                    ${_div}                    ${deal.authorName ? `                      \x3Cdiv class="tg-df-author-line-mobile" style="padding: 0 0 12px 0; background: transparent;">                         \x3Cdiv style="display: flex; align-items: center; gap: 12px;">                            ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="40" height="40" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 40px; min-height: 40px;">` : ''}                            \x3Cdiv style="display: flex; flex-direction: column;">                               \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">\x3Cspan style="color: #FF6600;">${this.escapeHTML(deal.merchant)}${_span} deal recommended by:${_div}                               \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.3;">                                  \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                  ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                  ${deal.modifiedDate ? `\x3Cdiv style="color: var(--tg-df-text-muted); margin-top: 2px;">${getTimeAgo(deal.modifiedDate)}${_div}` : ''}                               ${_div}                            ${_div}                         ${_div}                      ${_div}                    ` : ''}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>View Deal${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                  \x3Cdiv class="tg-df-card-merchant-wrapper" style="position: absolute; bottom: 0; right: 0; background: transparent; padding: 8px 12px; z-index: 10;">                     \x3Cspan class="tg-df-card-merchant-pill" style="text-align: right; margin-bottom: 0;" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" disable-tracking="true" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cdiv class="tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                    \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                    \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                      var c = this.parentNode;                      if (this.dataset.expanded === 'true') {                        var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                        if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                        pd.style.display = '-webkit-box';                        pd.style.webkitLineClamp = '3';                        this.textContent = 'READ MORE';                        this.style.position = 'absolute';                        this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                        this.style.paddingLeft = '16px';                        this.dataset.expanded = 'false';                      } else {                        var pd = this.previousElementSibling;                        pd.style.display = 'inline';                        pd.style.webkitLineClamp = 'unset';                        this.textContent = 'READ LESS';                        this.style.position = 'static';                        this.style.background = 'transparent';                        this.style.paddingLeft = '4px';                        this.dataset.expanded = 'true';                        pd.appendChild(this);                      }                    ">READ MORE${_button}                  \x3C/div>` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${deal.authorName ? `                    \x3Cdiv class="tg-df-author-line-desktop" style="padding: 0 0 ${isSavingsSquadMode ? 0 : 12}px 0;">                       \x3Cdiv style="display: flex; align-items: center; gap: 10px;">                          ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="36" height="36" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 36px; min-height: 36px;">` : ''}                          \x3Cdiv style="display: flex; flex-direction: column;">                             \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">Recommended by:${_div}                             \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.2;">                                \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                ${deal.modifiedDate ? `\x3Cspan style="color: var(--tg-df-text-muted);"> • ${getTimeAgo(deal.modifiedDate)}${_span}` : ''}                             ${_div}                          ${_div}                       ${_div}                    ${_div}                    ` : ''}                    ${priceGroupHtml}                  ${_div}                ${_div}                \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta" style="text-decoration: none; border-radius: 0;">${ctaText}${_a}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit) {            dealsHtml += `              \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer;">Load More${_button}              ${_div}            `;          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }          setTimeout(() => {            const contents = this.root.querySelectorAll('.tg-df-card-desc-content');            contents.forEach(p => {              if (p.scrollHeight > p.clientHeight || p.scrollHeight > 60) {                if (p.nextElementSibling) {                  p.nextElementSibling.style.display = 'block';                }              }            });                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));          }, 50);          const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              this.displayLimit += this.getRowsLimit();              this.render();            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/outdoors/13-best-cooler-deals-on-amazon-to-shop-before-labor-day-weekend-up-to-44-percent-on-yeti-ninja-coleman-and-more</link>
                                                                            <description>
                            <![CDATA[ Some of the best coolers we've reviewed are seeing price drops this summer! Check out the deals I recommend from top brands. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">VZg4TWvF84JraqKqYj8aW</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/fBcQvCo2N2YuDaHkh6gxTa-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 26 Aug 2026 14:18:30 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Outdoors]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Olivia Halevy ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/YAg7Fmh9dGKbg3hULBMWiU-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Olivia is a Deals Writer at Tom’s Guide. She loves all things lifestyle, shopping and sourcing the best deals from some of the top brands, retailers and websites around. From fashion and beauty to smart home and tech, she has an eye for finding practical, stylish, and reasonably-priced items that help make life simpler (and a little more aesthetically-pleasing).&amp;nbsp;Olivia has over five years of experience writing lifestyle, commerce, and branded content for &lt;a href=&quot;http://patch.com/&quot;&gt;Patch.com&lt;/a&gt;. She&#039;s covered major shopping holidays like Amazon Prime Day, Black Friday and Cyber Monday. In her free time, she enjoys trying out new exercise classes, binge-watching the latest viral TV shows, cooking, spending time with family and taking long walks with her dog, Gus.&amp;nbsp;&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/fBcQvCo2N2YuDaHkh6gxTa-1920-80.jpg">
                                                            <media:credit><![CDATA[Amazon / edited by Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Cooler deals]]></media:description>                                                            <media:text><![CDATA[Cooler deals]]></media:text>
                                <media:title type="plain"><![CDATA[Cooler deals]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/fBcQvCo2N2YuDaHkh6gxTa-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Summer may be winding down, but there’s still plenty of time for Labor Day weekend picnics, barbecues, and getaways! If any of these sound like a part of your end of summer plans, you’ll likely need a little help keeping your snacks and drinks perfectly chilled. That’s why now is the time to invest in one of the <a href="https://www.tomsguide.com/best-picks/best-coolers">best coolers</a>.</p><p>A few of our favorite brands — like Ninja, Igloo, Coleman, YETI and more — are knocking <a href="https://www.amazon.com/camp-coolers/b/ref=dp_bc_5?ie=UTF8&amp;node=14335431" target="_blank" rel="nofollow">up to 44% off</a> select coolers. For instance, our favorite budget cooler, <a href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow">the Coleman Classic Series (70 qt), is down to just $67</a> right now. If you're looking for something with wheels, I'd suggest <a href="https://www.amazon.com/YETI-Roadie-Wheeled-Retractable-Periscope/dp/B0G62KNNXM/" target="_blank" rel="nofollow">the YETI Roadie 48 that's now $85 off</a>. </p><p>If you're not sure where to begin, keep scrolling to see my list of all the cooler deals I recommend for your Labor Day Weekend plans and beyond! You can also check out our <a href="https://www.tomsguide.com/coupons/amazon.com">Amazon promo codes</a> page.</p><h3 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h3><ul><li><a href="https://www.amazon.com/camp-coolers/b/ref=dp_bc_5?ie=UTF8&amp;node=14335431" target="_blank" rel="nofollow"><strong>shop cooler deals at Amazon</strong></a></li><li><strong>Coleman Classic Playmate Coolers: </strong><a href="https://www.amazon.com/Igloo-7362-Playmate-Personal-12-Inch/dp/B0B4X1WX2T?" target="_blank" rel="nofollow"><strong>was $33 now $25</strong></a></li><li><strong>Igloo Marine Cooler 25qt: </strong><a href="https://www.amazon.com/Igloo-Latitude-Marine-Ultra-Cooler/dp/B0BRL9S8L9" target="_blank" rel="nofollow"><strong>was $41 now $31</strong></a></li><li><strong>Coleman Classic Series Cooler 70qt: </strong><a href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow"><strong>was $94 now $67</strong></a></li><li><strong>Stanley All Day Julienne Soft Cooler: </strong><a href="https://www.amazon.com/STANLEY-Julienne-Handles-Insulated-BPA-Free/dp/B0DZ35RDQ1?" target="_blank" rel="nofollow"><strong>was $140 now $78</strong></a></li><li><strong>Ninja Backpack Cooler: </strong><a href="https://www.amazon.com/Ninja-Backpack-FrostVault-Leakproof-FF124CS/dp/B0F4Y5NDKM" target="_blank" rel="nofollow"><strong>was $199 now $179</strong></a></li><li><strong>YETI Hopper Flip 12: </strong><a href="https://www.amazon.com/dp/B0G62KNZFF?" target="_blank" rel="nofollow"><strong>was $250 now $200</strong></a></li></ul><h3 class="article-body__section" id="section-the-best-cooler-deals"><span>The Best Cooler Deals</span></h3><div class="product"><a data-dimension112="02cbb810-a152-11f1-af38-5bef563971c0" data-action="Deal Block" data-label="Chiller Soft Coolers" data-dimension48="Chiller Soft Coolers" data-dimension25="$24" href="https://www.amazon.com/Coleman-Chiller-Soft-Cooler-Ocean/dp/B09HN1WTY5?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:84.68%;"><img id="Mcx2Aj6u6FJ6mYMpxEcdBJ" name="Coleman Cooler.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/Mcx2Aj6u6FJ6mYMpxEcdBJ-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="575" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Coleman-Chiller-Soft-Cooler-Ocean/dp/B09HN1WTY5?" target="_blank" rel="nofollow" data-dimension112="02cbb810-a152-11f1-af38-5bef563971c0" data-action="Deal Block" data-label="Chiller Soft Coolers" data-dimension48="Chiller Soft Coolers" data-dimension25="$24">Chiller Soft Coolers: was $32 now $24</a></strong><br />This portable cooler is ideal for toting along food and beverages on your daily hiking excursions, trips to the beach or just keeping your drinks cold this summer. It will retain ice for 12 hours and you don't need to worry about spills thanks to its leakproof design. The cooler also features an adjustable padded sling strap and padded side handles for easy transporting to the top of the mountain.  <a class="view-deal button" href="https://www.amazon.com/Coleman-Chiller-Soft-Cooler-Ocean/dp/B09HN1WTY5?" target="_blank" rel="nofollow" data-dimension112="02cbb810-a152-11f1-af38-5bef563971c0" data-action="Deal Block" data-label="Chiller Soft Coolers" data-dimension48="Chiller Soft Coolers" data-dimension25="$24">View Deal</a></p></div><div class="product"><a data-dimension112="02cbb87e-a152-11f1-8a39-3d3d6fef76e1" data-action="Deal Block" data-label="Classic Playmate Coolers" data-dimension48="Classic Playmate Coolers" data-dimension25="$25" href="https://www.amazon.com/Igloo-7362-Playmate-Personal-12-Inch/dp/B0B4WY9YP6?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:96.13%;"><img id="RCnEs4JhY7VGfMrrMS2ZE" name="Classic Playmate Coolers" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/RCnEs4JhY7VGfMrrMS2ZE-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1442" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-7362-Playmate-Personal-12-Inch/dp/B0B4WY9YP6?" target="_blank" rel="nofollow" data-dimension112="02cbb87e-a152-11f1-8a39-3d3d6fef76e1" data-action="Deal Block" data-label="Classic Playmate Coolers" data-dimension48="Classic Playmate Coolers" data-dimension25="$25">Classic Playmate Coolers: was $33 now $25</a></strong><br />Perfect for lunch, picnics and work days, the Playmate cooler is ready to join you on your next adventure. It's designed to be very easy to hold and carry, and the push-button lid will help prevent spills. This 7qt cooler can fit 9 cans.<a class="view-deal button" href="https://www.amazon.com/Igloo-7362-Playmate-Personal-12-Inch/dp/B0B4WY9YP6?" target="_blank" rel="nofollow" data-dimension112="02cbb87e-a152-11f1-8a39-3d3d6fef76e1" data-action="Deal Block" data-label="Classic Playmate Coolers" data-dimension48="Classic Playmate Coolers" data-dimension25="$25">View Deal</a></p></div><div class="product"><a data-dimension112="02cbb8ec-a152-11f1-aa95-b976e406a246" data-action="Deal Block" data-label="Marine Cooler 25qt" data-dimension48="Marine Cooler 25qt" data-dimension25="$31" href="https://www.amazon.com/Igloo-Latitude-Marine-Ultra-Cooler/dp/B0BRL9S8L9" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:66.93%;"><img id="KCGTcWXbH8iR4k2Csb4b5j" name="Marine Cooler 25QT" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/KCGTcWXbH8iR4k2Csb4b5j-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1004" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-Latitude-Marine-Ultra-Cooler/dp/B0BRL9S8L9" target="_blank" rel="nofollow" data-dimension112="02cbb8ec-a152-11f1-aa95-b976e406a246" data-action="Deal Block" data-label="Marine Cooler 25qt" data-dimension48="Marine Cooler 25qt" data-dimension25="$31">Marine Cooler 25qt: was $46 now $31</a></strong><br />The perfect compact cooler, now with 33% off. This Igloo cooler has a 25qt capacity, space for 36 cans. The non-slip handles make it easy to carry, and there's even a fish ruler on top to measure your catch.<a class="view-deal button" href="https://www.amazon.com/Igloo-Latitude-Marine-Ultra-Cooler/dp/B0BRL9S8L9" target="_blank" rel="nofollow" data-dimension112="02cbb8ec-a152-11f1-aa95-b976e406a246" data-action="Deal Block" data-label="Marine Cooler 25qt" data-dimension48="Marine Cooler 25qt" data-dimension25="$31">View Deal</a></p></div><div class="product"><a data-dimension112="02cbb950-a152-11f1-bff0-a75b4eee8e7e" data-action="Deal Block" data-label="Marine Cooler 54qt" data-dimension48="Marine Cooler 54qt" data-dimension25="$54" href="https://www.amazon.com/Igloo-Marine-Ultra-Cooler-54-Quart/dp/B006H0L5TM" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:68.87%;"><img id="NBBUrFXtznQezDxoyyFSUd" name="Marine Cooler" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/NBBUrFXtznQezDxoyyFSUd-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1033" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-Marine-Ultra-Cooler-54-Quart/dp/B006H0L5TM" target="_blank" rel="nofollow" data-dimension112="02cbb950-a152-11f1-bff0-a75b4eee8e7e" data-action="Deal Block" data-label="Marine Cooler 54qt" data-dimension48="Marine Cooler 54qt" data-dimension25="$54">Marine Cooler 54qt: was $79 now $54</a></strong><br />This 54qt cooler is now on sale for $54 — a great discount. Our <a href="https://www.tomsguide.com/home/igloo-marine-ultra-cooler-review">Igloo Marine Ultra 54 review</a> said this cooler is very lightweight and keeps cold for two days straight. It's also easy to clean, which is a bonus.<a class="view-deal button" href="https://www.amazon.com/Igloo-Marine-Ultra-Cooler-54-Quart/dp/B006H0L5TM" target="_blank" rel="nofollow" data-dimension112="02cbb950-a152-11f1-bff0-a75b4eee8e7e" data-action="Deal Block" data-label="Marine Cooler 54qt" data-dimension48="Marine Cooler 54qt" data-dimension25="$54">View Deal</a></p></div><div class="product"><a data-dimension112="02cbb9be-a152-11f1-abe0-8d6a1e2a9aa2" data-action="Deal Block" data-label="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension48="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension25="$78" href="https://www.amazon.com/STANLEY-Julienne-Handles-Insulated-BPA-Free/dp/B0DZ35RDQ1?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1104px;"><p class="vanilla-image-block" style="padding-top:135.87%;"><img id="x2qTyESabmeEFV8zDktVG6" name="Stanley cooler" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/x2qTyESabmeEFV8zDktVG6-1920-80.jpg" mos="" align="middle" fullscreen="" width="1104" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/STANLEY-Julienne-Handles-Insulated-BPA-Free/dp/B0DZ35RDQ1?" target="_blank" rel="nofollow" data-dimension112="02cbb9be-a152-11f1-abe0-8d6a1e2a9aa2" data-action="Deal Block" data-label="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension48="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension25="$78">All Day Julienne Soft Cooler Bag and Lunch Box: was $140 now $78</a></strong><br />Need a new cooler for spring roadtrips, barbecues or beach days? This Stanley cooler bag is the perfect pick. It's currently only $78 and comes in a variety of vibrant colors that are perfect for summer. It fits up to 10 cans and will keep your food and drinks cold for hours. <a class="view-deal button" href="https://www.amazon.com/STANLEY-Julienne-Handles-Insulated-BPA-Free/dp/B0DZ35RDQ1?" target="_blank" rel="nofollow" data-dimension112="02cbb9be-a152-11f1-abe0-8d6a1e2a9aa2" data-action="Deal Block" data-label="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension48="All Day Julienne Soft Cooler Bag and Lunch Box" data-dimension25="$78">View Deal</a></p></div><div class="product"><a data-dimension112="02cbba2c-a152-11f1-835b-f5cf27696925" data-action="Deal Block" data-label="Classic Series Cooler 70qt" data-dimension48="Classic Series Cooler 70qt" data-dimension25="$67" href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:695px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="LLC8U9mUmqjs4623esUzGJ" name="Colemand Classic Cooler 70-quart" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/LLC8U9mUmqjs4623esUzGJ-1920-80.png" mos="" align="middle" fullscreen="" width="695" height="695" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow" data-dimension112="02cbba2c-a152-11f1-835b-f5cf27696925" data-action="Deal Block" data-label="Classic Series Cooler 70qt" data-dimension48="Classic Series Cooler 70qt" data-dimension25="$67">Classic Series Cooler 70qt: was $94 now $67</a></strong><br />The <a href="https://www.tomsguide.com/home/coleman-classic-cooler-review">Coleman Classic Cooler</a> isn't as fancy as some other brands, but this 70-quart version offers excellent capacity at a budget price. And that's why we recommend it as the best budget cooler in our buying guide. It can hold 100 cans, and doubles up as a seat — and if you're looking for a cooler to keep your catch on ice, it even has a fish ruler. It doesn't come with wheels, but with a discount we don't think you can ask for more.<a class="view-deal button" href="https://www.amazon.com/Coleman-Insulated-Portable-Leak-Proof-Capacity/dp/B0BLY5KZTG?" target="_blank" rel="nofollow" data-dimension112="02cbba2c-a152-11f1-835b-f5cf27696925" data-action="Deal Block" data-label="Classic Series Cooler 70qt" data-dimension48="Classic Series Cooler 70qt" data-dimension25="$67">View Deal</a></p></div><div class="product"><a data-dimension112="02cbba90-a152-11f1-babc-d3f24349b766" data-action="Deal Block" data-label="Polar Hard Coolers" data-dimension48="Polar Hard Coolers" data-dimension25="$115" href="https://www.amazon.com/Igloo-Polar-Cooler-120-Quart-White/dp/B004QILD6W" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:73.78%;"><img id="jFjwwiBUq7xKUtoEtNoUw3" name="Igloo coolers" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/jFjwwiBUq7xKUtoEtNoUw3-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="501" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-Polar-Cooler-120-Quart-White/dp/B004QILD6W" target="_blank" rel="nofollow" data-dimension112="02cbba90-a152-11f1-babc-d3f24349b766" data-action="Deal Block" data-label="Polar Hard Coolers" data-dimension48="Polar Hard Coolers" data-dimension25="$115">Polar Hard Coolers: was $129 now $115</a></strong><br />Perfect for your next roadtrip, family picnic or sporting event, this 120 qt. cooler features dual snap-fit latches to keep contents secure during transportation. It's also super easy to carry thanks to its swing-up handles. It even features a drain plug for easy draining. The cooler will retain ice for up to 5 days. <a class="view-deal button" href="https://www.amazon.com/Igloo-Polar-Cooler-120-Quart-White/dp/B004QILD6W" target="_blank" rel="nofollow" data-dimension112="02cbba90-a152-11f1-babc-d3f24349b766" data-action="Deal Block" data-label="Polar Hard Coolers" data-dimension48="Polar Hard Coolers" data-dimension25="$115">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbafe-a152-11f1-80a2-47f9511d1c8c" data-action="Deal Block" data-label="Iceless Thermoelectric Cooler" data-dimension48="Iceless Thermoelectric Cooler" data-dimension25="$145" href="https://www.amazon.com/Igloo-Portable-Electric-Coolers-Electrice/dp/B007ZYH4BM" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:122.24%;"><img id="fJtZwsva8iP3YAdyrUhXTP" name="Iceless Cooler" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fJtZwsva8iP3YAdyrUhXTP-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="830" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Igloo-Portable-Electric-Coolers-Electrice/dp/B007ZYH4BM" target="_blank" rel="nofollow" data-dimension112="02cbbafe-a152-11f1-80a2-47f9511d1c8c" data-action="Deal Block" data-label="Iceless Thermoelectric Cooler" data-dimension48="Iceless Thermoelectric Cooler" data-dimension25="$145">Iceless Thermoelectric Cooler: was $164 now $145</a></strong><br />This Igloo Iceless cooler is an ideal addition to any camping trip or road trip when you don't want to deal with ice. All you have to do is plug it into any 12V DC receptacle (cigarette lighter) and you'll be able to keep all your favorite drinks and snacks cold.<a class="view-deal button" href="https://www.amazon.com/Igloo-Portable-Electric-Coolers-Electrice/dp/B007ZYH4BM" target="_blank" rel="nofollow" data-dimension112="02cbbafe-a152-11f1-80a2-47f9511d1c8c" data-action="Deal Block" data-label="Iceless Thermoelectric Cooler" data-dimension48="Iceless Thermoelectric Cooler" data-dimension25="$145">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbb62-a152-11f1-8518-331e6fff5308" data-action="Deal Block" data-label="Pro Heavy-Duty 45qt" data-dimension48="Pro Heavy-Duty 45qt" data-dimension25="$149" href="https://www.amazon.com/Coleman-Ultra-Light-Extra-Thick-Insulation-Capacity/dp/B0DMW2Z6BP/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:71.47%;"><img id="e8w69SnKSZqpx46AUUAeY5" name="Coleman Pro" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/e8w69SnKSZqpx46AUUAeY5-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1072" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Coleman-Ultra-Light-Extra-Thick-Insulation-Capacity/dp/B0DMW2Z6BP/" target="_blank" rel="nofollow" data-dimension112="02cbbb62-a152-11f1-8518-331e6fff5308" data-action="Deal Block" data-label="Pro Heavy-Duty 45qt" data-dimension48="Pro Heavy-Duty 45qt" data-dimension25="$149">Pro Heavy-Duty 45qt: was $199 now $149</a></strong><br />The Coleman Pro 45qt is designed to be 30% lighter than other coolers of the same capacity, meaning you'll be able to carry your fully loaded cooler more easily. The cooler holds up to 74 cans without ice and stays cold for up to 4 days thanks to its fully insulated lid and body.<a class="view-deal button" href="https://www.amazon.com/Coleman-Ultra-Light-Extra-Thick-Insulation-Capacity/dp/B0DMW2Z6BP/" target="_blank" rel="nofollow" data-dimension112="02cbbb62-a152-11f1-8518-331e6fff5308" data-action="Deal Block" data-label="Pro Heavy-Duty 45qt" data-dimension48="Pro Heavy-Duty 45qt" data-dimension25="$149">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbbd0-a152-11f1-9777-090e704862a7" data-action="Deal Block" data-label="Backpack Cooler" data-dimension48="Backpack Cooler" data-dimension25="$179" href="https://www.amazon.com/Ninja-Backpack-FrostVault-Leakproof-FF124CS/dp/B0F4Y5NDKM" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:464px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="WW5AWCoTo6gey3CoZ7CHzk" name="Screenshot 2025-07-07 153631" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/WW5AWCoTo6gey3CoZ7CHzk-1920-80.jpg" mos="" align="middle" fullscreen="" width="464" height="464" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>If you have a smaller pack-up and can skip the wheels, Ninja's backpack cooler is just the ticket. It has a built-in cold dry zone to keep food dry and separate at under 40°F, holds ice for up to 24 hours, and has a top lid and side opening for easier access. It holds up to 24 cans, or 16 cans with ice. It even has a built in bottle opener.<a class="view-deal button" href="https://www.amazon.com/Ninja-Backpack-FrostVault-Leakproof-FF124CS/dp/B0F4Y5NDKM" target="_blank" rel="nofollow" data-dimension112="02cbbbd0-a152-11f1-9777-090e704862a7" data-action="Deal Block" data-label="Backpack Cooler" data-dimension48="Backpack Cooler" data-dimension25="$179">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbc52-a152-11f1-865b-913939bb659d" data-action="Deal Block" data-label="Hopper Flip 12 Soft Sided Cooler" data-dimension48="Hopper Flip 12 Soft Sided Cooler" data-dimension25="$200" href="https://www.amazon.com/dp/B0G62KNZFF?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1418px;"><p class="vanilla-image-block" style="padding-top:65.66%;"><img id="ezMMD2GC3rvaXXG9KUPRDA" name="yeti cooler" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ezMMD2GC3rvaXXG9KUPRDA-1920-80.jpg" mos="" align="middle" fullscreen="" width="1418" height="931" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B0G62KNZFF?" target="_blank" rel="nofollow" data-dimension112="02cbbc52-a152-11f1-865b-913939bb659d" data-action="Deal Block" data-label="Hopper Flip 12 Soft Sided Cooler" data-dimension48="Hopper Flip 12 Soft Sided Cooler" data-dimension25="$200">Hopper Flip 12 Soft Sided Cooler: was $250 now $200</a></strong><br />This soft-sided cooler is perfect for day trips, picnics or outdoor adventures, and it's not too heavy to carry around. Compact and portable, it holds up to 13 cans and features a leakproof zipper, making it a must-have for on-the-go convenience.<a class="view-deal button" href="https://www.amazon.com/dp/B0G62KNZFF?" target="_blank" rel="nofollow" data-dimension112="02cbbc52-a152-11f1-865b-913939bb659d" data-action="Deal Block" data-label="Hopper Flip 12 Soft Sided Cooler" data-dimension48="Hopper Flip 12 Soft Sided Cooler" data-dimension25="$200">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbcb6-a152-11f1-952f-a109ca1c1321" data-action="Deal Block" data-label="Hopper M Series Backpack" data-dimension48="Hopper M Series Backpack" data-dimension25="$260" href="https://www.amazon.com/YETI-Hopper-Backpack-Cooler-MagShield/dp/B0DCW87YSY" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:94.55%;"><img id="W2bVFcrWaEYWduVsWR9Dri" name="YETI cooler backpack" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/W2bVFcrWaEYWduVsWR9Dri-1920-80.jpg" mos="" align="middle" fullscreen="" width="679" height="642" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/YETI-Hopper-Backpack-Cooler-MagShield/dp/B0DCW87YSY" target="_blank" rel="nofollow" data-dimension112="02cbbcb6-a152-11f1-952f-a109ca1c1321" data-action="Deal Block" data-label="Hopper M Series Backpack" data-dimension48="Hopper M Series Backpack" data-dimension25="$260">Hopper M Series Backpack: was $325 now $260</a></strong><br />If you love adventure almost as much as you love beer, this convenient and secure backpack cooler is a must-have. The YETI Hopper can carry up to 36 cans of your favorite beverage while keeping your hands free — and most importantly, your drinks ice cold.<a class="view-deal button" href="https://www.amazon.com/YETI-Hopper-Backpack-Cooler-MagShield/dp/B0DCW87YSY" target="_blank" rel="nofollow" data-dimension112="02cbbcb6-a152-11f1-952f-a109ca1c1321" data-action="Deal Block" data-label="Hopper M Series Backpack" data-dimension48="Hopper M Series Backpack" data-dimension25="$260">View Deal</a></p></div><div class="product"><a data-dimension112="02cbbd24-a152-11f1-82ad-bdd976aea89d" data-action="Deal Block" data-label="Roadie 48 Wheeled Cooler" data-dimension48="Roadie 48 Wheeled Cooler" data-dimension25="$340" href="https://www.amazon.com/YETI-Roadie-Wheeled-Retractable-Periscope/dp/B0G62KNNXM/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:926px;"><p class="vanilla-image-block" style="padding-top:161.99%;"><img id="4aLY8r3baTcT4isb6MCJK8" name="YETI Roadie 48" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4aLY8r3baTcT4isb6MCJK8-1920-80.jpg" mos="" align="middle" fullscreen="" width="926" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/YETI-Roadie-Wheeled-Retractable-Periscope/dp/B0G62KNNXM/" target="_blank" rel="nofollow" data-dimension112="02cbbd24-a152-11f1-82ad-bdd976aea89d" data-action="Deal Block" data-label="Roadie 48 Wheeled Cooler" data-dimension48="Roadie 48 Wheeled Cooler" data-dimension25="$340">Roadie 48 Wheeled Cooler: was $425 now $340</a></strong><br />Looking for a cooler that you can easily wheel around? This YETI Roadie the perfect find — especially right now since it rarely goes on sale. It can hold everything from wine bottles and soda cans to a whole watermelon. <a class="view-deal button" href="https://www.amazon.com/YETI-Roadie-Wheeled-Retractable-Periscope/dp/B0G62KNNXM/" target="_blank" rel="nofollow" data-dimension112="02cbbd24-a152-11f1-82ad-bdd976aea89d" data-action="Deal Block" data-label="Roadie 48 Wheeled Cooler" data-dimension48="Roadie 48 Wheeled Cooler" data-dimension25="$340">View Deal</a></p></div><h3 class="article-body__section" id="section-more-deals"><span>More Deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=outdoor&amp;view_mode=savings_squad&amp;widget_title=Top+Deals+Handpicked+by+Our+Editors&amp;widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&amp;bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function getTimeAgo(dateString) {        if (!dateString) return '';        const date = new Date(dateString);        const now = new Date();        const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);        if (diffInSeconds < 60) return 'Just now';        const diffInMinutes = Math.floor(diffInSeconds / 60);        if (diffInMinutes < 60) return `${diffInMinutes} min${diffInMinutes > 1 ? 's' : ''} ago`;        const diffInHours = Math.floor(diffInMinutes / 60);        if (diffInHours < 24) return `${diffInHours} hr${diffInHours > 1 ? 's' : ''} ago`;        const diffInDays = Math.floor(diffInHours / 24);        if (diffInDays < 30) return `${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`;        const diffInMonths = Math.floor(diffInDays / 30);        if (diffInMonths < 12) return `${diffInMonths} mo${diffInMonths > 1 ? 's' : ''} ago`;        const diffInYears = Math.floor(diffInDays / 365);        return `${diffInYears} yr${diffInYears > 1 ? 's' : ''} ago`;      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;      position: relative;      z-index: 20;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      margin: 0 auto;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {      display: grid;      width: 100%;      grid-template-columns: repeat(4, 1fr);      gap: 12px;      margin: 0 auto;      max-width: 800px;    }                 .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;      width: 100%;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      width: 100%;      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }    @container tg-df (max-width: 768px) {      .tg-df-filters-container {      position: relative;      width: 100%;      max-width: 800px;    }    .tg-df-scroll-btn {      display: none;      position: absolute;      top: 50%;      transform: translateY(-50%);      width: 32px;      height: 32px;      background: white;      border: 1px solid var(--tg-df-border);      border-radius: 50%;      align-items: center;      justify-content: center;      cursor: pointer;      z-index: 10;      box-shadow: 0 2px 8px rgba(0,0,0,0.1);      color: var(--tg-df-text-primary);      padding: 0;    }    .tg-df-scroll-btn svg {      width: 16px;      height: 16px;    }    .tg-df-scroll-btn:hover {      background: #f4f4f4;    }    .tg-df-scroll-btn.left {      left: 0px;    }    .tg-df-scroll-btn.right {      right: 0px;    }    @container tg-df (max-width: 768px) {      .tg-df-scroll-btn {        display: flex;        top: 22px; /* vertically center within the 44px high filter buttons */      }    }    .tg-df-filters {        width: 100%;        margin: 0;        margin-bottom: -320px;        padding: 0 16px 320px 16px;        display: flex;        flex-wrap: nowrap;        gap: 8px;        overflow-x: auto;        overflow-y: hidden;        pointer-events: none;        scrollbar-width: none;        -webkit-overflow-scrolling: touch;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }      .tg-df-sort-wrapper {        pointer-events: auto;        flex: 0 0 auto;        width: 175px;        min-width: 175px;      }    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 120px;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 16px 16px 8px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }                  .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;        width: auto;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;      width: 100vw;      max-width: 1200px;      position: relative;      left: 50%;      transform: translateX(-50%);    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 14px;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    .tg-df-grid-wrapper { position: relative; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn {      display: inline-flex;      align-items: center;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.40);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #1f69ff; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #0056e0; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }    .tg-df-savings-squad-header { margin-bottom: 24px; text-align: center; display: none; }    .tg-df-banner-img-desktop { display: block; width: 100%; height: auto; margin-bottom: 32px; }    .tg-df-banner-img-mobile { display: none; width: 100%; height: auto; margin-bottom: 32px; }    @container tg-df (max-width: 600px) {      .tg-df-banner-img-desktop { display: none; }      .tg-df-banner-img-mobile { display: block; }    }    .tg-df-header-title { font-size: 28px; font-weight: 700; color: var(--tg-df-text); margin: 32px 0 12px 0; line-height: 1.3; }    .tg-df-header-subtitle { font-size: 16px; color: var(--tg-df-text-muted); margin: 0 0 32px 0; line-height: 1.5; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3Cdiv class="tg-df-savings-squad-header" id="tg-df-savings-squad-header">      \x3Cpicture>        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/xkh2og7m3d1778189998.png" alt="Deals Banner" class="tg-df-banner-img-desktop" />        \x3Cimg src="https://cdn.mos.cms.futurecdn.net/flexiimages/gmak6rtdf41778245089.png" alt="Deals Banner Mobile" class="tg-df-banner-img-mobile" />      \x3C/picture>      \x3Cdiv class="tg-df-header-text">        \x3Ch2 class="tg-df-header-title" id="tg-df-header-title">Editor's Choice Deals\x3C/h2>        \x3Cp class="tg-df-header-subtitle" id="tg-df-header-subtitle">Discover the best discounts currently available, curated daily by the Tom's Guide Savings Squad.\x3C/p>      \x3C/div>    \x3C/div>    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Televisions" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/wcMxTsHgqu3roMbAx7RLnT-132-100.png" alt="TVs" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">TVs\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Phones" data-pr="over50">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/G3KGaRGzj24F6PUsw4bWpT-132-100.png" alt="Phones" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Phones\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Computing" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/znNvsLzx8NEgNkD9HSFSnT-132-100.png" alt="Computing" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Computing\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Gaming" data-pr="all">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/Pgew8yaRQeZFHqHjTzvBnT-132-100.png" alt="Gaming" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Gaming\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Mattresses" data-pr="over500">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/cW7xsaLyesxkHFVSiC4kmT-132-100.png" alt="Mattresses" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Mattresses\x3C/span>            \x3C/div>                      \x3Cdiv class="tg-df-roundel tg-df-carousel-cat" data-query="Audio" data-pr="over30">              \x3Cdiv class="tg-df-roundel-img-box">                 \x3Cimg src="https://cdn.mos.cms.futurecdn.net/pCvBVHuhaQVjKt3VgCjbqT-132-100.png" alt="Audio" />              \x3C/div>              \x3Cspan class="tg-df-roundel-label">Audio\x3C/span>            \x3C/div>                  \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E      \x3Cdiv class="tg-df-top-bar" id="tg-df-top-bar" style="position: relative; z-index: 100; margin: 0 auto 20px;">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>      \x3C/div>    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">              \x3Cdiv class="tg-df-filters-container" style="position: relative; width: 100%; max-width: 800px; margin: 0 auto;">          \x3Cbutton class="tg-df-scroll-btn left" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: -200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M15 18l-6-6 6-6"/>\x3C/svg>          \x3C/button>          \x3Cbutton class="tg-df-scroll-btn right" style="display: none;" onclick="this.parentElement.querySelector('.tg-df-filters').scrollBy({left: 200, behavior: 'smooth'})">            \x3Csvg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\x3Cpath d="M9 18l6-6-6-6"/>\x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-filters">          \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>          \x3C/div>        \x3C/div>        \x3C/div>      \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();        }        getViewMode() {          console.log("DEBUG getViewMode -> override:", this.viewModeOverride, "editorMode:", this.editorMode);          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          console.log("[DEBUG] applyLayoutMode CALLED! mode=", mode);          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          const showHeaderDetails = params.get('show_header_details') !== 'false';          const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          const topBarDiv = this.root.querySelector('#tg-df-top-bar');          const headerElement = this.root.querySelector('#tg-df-savings-squad-header');          if (headerElement) {             headerElement.style.display = (mode === 'savings_squad' && showHeaderDetails) ? 'block' : 'none';          }          if (mode === 'carousel') {             this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (topBarDiv) topBarDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.add('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (topBarDiv) topBarDiv.style.display = 'block';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!this.viewModeOverride && initialViewMode) {            this.viewModeOverride = initialViewMode;          }          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Gaming laptops';          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button, .tg-df-container .tg-df-card-cta { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover, .tg-df-container .tg-df-card-cta:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (this.viewModeSelect && params.has('view_mode')) {            this.viewModeSelect.value = params.get('view_mode');          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'date_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }          const headerTitleEl = this.root.querySelector('#tg-df-header-title');          const headerSubtitleEl = this.root.querySelector('#tg-df-header-subtitle');          if (params.has('widget_title') && headerTitleEl) {             headerTitleEl.textContent = params.get('widget_title');          }          if (params.has('widget_subtitle') && headerSubtitleEl) {             headerSubtitleEl.textContent = params.get('widget_subtitle');          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            if (this.getViewMode() === 'savings_squad') {              this.searchInput.value = '';            } else {              this.searchInput.value = this.currentQuery;            }          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'date_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const handleFiltersScroll = () => {            const filters = this.root.querySelector('.tg-df-filters');            const leftBtn = this.root.querySelector('.tg-df-scroll-btn.left');            const rightBtn = this.root.querySelector('.tg-df-scroll-btn.right');            if (filters && leftBtn && rightBtn) {              const { scrollLeft, scrollWidth, clientWidth } = filters;              leftBtn.style.display = scrollLeft > 0 ? 'flex' : 'none';              rightBtn.style.display = Math.ceil(scrollLeft + clientWidth) < scrollWidth - 5 ? 'flex' : 'none';            }          };          const filters = this.root.querySelector('.tg-df-filters');          if (filters) {            filters.addEventListener('scroll', handleFiltersScroll);            window.addEventListener('resize', handleFiltersScroll);            setTimeout(handleFiltersScroll, 100);                        // Also call after rendering dropdowns            const origRenderCategories = this.renderCategories;            if (origRenderCategories) {               this.renderCategories = (...args) => {                 origRenderCategories.apply(this, args);                 setTimeout(handleFiltersScroll, 50);               };            }          }                const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          const showAutocomplete = () => {             if (this.getViewMode() !== 'savings_squad' || !this.autocompleteDropdown || !this.airedaleTags) return;                          let terms = this.airedaleTags;             if (this.airedaleBrands) {                terms = terms.concat(this.airedaleBrands.map(b => b.formatted_value));             }             terms = [...new Set(terms)];                          const query = this.searchInput.value.trim();             let matches = [];             if (query.length > 0) {                 matches = terms.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase());             } else {                 matches = terms;             }                          if (matches.length > 0) {                 this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                 this.autocompleteDropdown.classList.add('active');             } else {                 this.autocompleteDropdown.classList.remove('active');             }          };          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('focus', showAutocomplete);            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              showAutocomplete();              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  if (this.getViewMode() === 'savings_squad') {                    this.activeDealTag = null;                    this.currentQuery = '';                    if (this.categoryFilter) this.categoryFilter.value = 'all';                    this.fetchDeals('');                  } else {                    this.deals = [];                    this.render();                  }                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                                let isTag = false;                if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;                if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;                this.activeDealTag = isTag ? query : null;                                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   if (query.length === 0 && this.getViewMode() === 'savings_squad') {                       if (this.categoryFilter) this.categoryFilter.value = 'all';                   }                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   if (this.categoryFilter && this.airedaleTags.includes(tag)) {                       this.categoryFilter.value = tag;                   }                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                            let isTag = false;              if (this.airedaleTags && this.airedaleTags.includes(query)) isTag = true;              if (this.airedaleBrands && this.airedaleBrands.some(b => b.formatted_value === query)) isTag = true;              this.activeDealTag = isTag ? query : null;                            this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 if (query.length === 0 && this.getViewMode() === 'savings_squad') {                     if (this.categoryFilter) this.categoryFilter.value = 'all';                 }                 this.fetchDeals(query);              }            });          }          if(this.sortSelect && this.sortSelect.querySelector('option[value="date_desc"]') === null) {              const option = document.createElement('option');              option.value = "date_desc";              option.text = "Newest First";              this.sortSelect.insertBefore(option, this.sortSelect.firstChild);          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               if (val) {                 this.currentQuery = val;               } else {                 if (this.searchInput && this.currentQuery === document.querySelector('#tg-df-brand-trigger')?.getAttribute('data-active-brand')) {                     // don't clear current query if a brand is selected                 } else if (this.searchInput) {                     this.currentQuery = '';                     this.searchInput.value = '';                 }               }               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = 'date_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const rewrittenLink = cardLink.getAttribute('href');                const revenueId = cardLink.getAttribute('data-revenue-id');                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getRowsLimit() {          if (this.rowsSelect && this.rowsSelect.value) return parseInt(this.rowsSelect.value, 10);          let configSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {             configSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {             configSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(configSource);          if (params.has('rows')) return parseInt(params.get('rows'), 10) || 12;          return 12;        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }        async fetchDeals(query) {          this.showLoading();          this.deals = [];          this.displayLimit = this.getRowsLimit();                    try {            console.log("getViewMode returns:", this.getViewMode());            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad();            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query);               } else {                 await this.fetchHawkDeals(query);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const siteParam = this.website || 'tomsguide';            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=${siteParam}&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (!this.activeDealTag && this.currentQuery) {             const tagMatch = this.airedaleTags.find(t => t.toLowerCase() === this.currentQuery.toLowerCase());             if (tagMatch) {                this.activeDealTag = tagMatch;             }          }          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const siteParam = this.website || 'tomsguide';             const url = `https://airedale.futurecdn.net/feeds/feed_1781000519267.json?site=${siteParam}&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let seenUrls = new Set();                    let overallBrandsCounts = {};                    // First pass: extract ALL brands from topArticles so the dropdown has all options          topArticles.forEach((article) => {             if (!article.articlepage) return;             let pageData = [];             try { pageData = JSON.parse(article.articlepage[0]); } catch(e){ console.warn(e); }             const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');             savingsSquad.forEach((block) => {                const data = block.data || {};                if (data.brand) {                   const cleanBrand = data.brand.replace(/^\d+\.\s*/, '').trim();                   overallBrandsCounts[cleanBrand] = (overallBrandsCounts[cleanBrand] || 0) + 1;                }             });          });          targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim();                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                if (externalUrl) {                   if (seenUrls.has(externalUrl)) return;                  seenUrls.add(externalUrl);                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || '',                   authorName: article.articleauthortext ? article.articleauthortext[0] : (article.articleauthor ? article.articleauthor[0] : ''),                   authorRole: article.articleauthorrole ? article.articleauthorrole[0] : '',                   authorImage: article.articleauthormedia ? article.articleauthormedia[0] : '',                   documentUrl: article.documenturl ? article.documenturl[0] : '',                   modifiedDate: article.contentmodifieddate || article.modifieddate || ''                });             });          });                    const airedaleBrandsList = Object.keys(overallBrandsCounts).map(b => ({              formatted_value: b,              count: overallBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    url.searchParams.append('rows', this.getRowsLimit().toString());          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = this.getRowsLimit();          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: item.name || item.title || item.model_name || item.product_name || 'Unknown Product',            brand: item.brand || '',            productName: item.model_name || item.product_name || item.name || '',            merchant: item.merchant_name || item.merchant || item.retailer || 'Retailer',            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : 'date_desc';          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                ${_div}              ${_div}              \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin:0; border-radius:0;">${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const rewrittenLink = btn.getAttribute('href');                const revenueId = btn.getAttribute('data-revenue-id');                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)}${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = 'View Deal';              if (isSavingsSquadMode) {                priceGroupHtml = ``;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = isSavingsSquadMode ? `` : `                \x3Cdiv class="tg-df-card-price-group">                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                          \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                          \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                            var c = this.parentNode;                            if (this.dataset.expanded === 'true') {                              var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                              if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                              pd.style.display = '-webkit-box';                              pd.style.webkitLineClamp = '3';                              this.textContent = 'READ MORE';                              this.style.position = 'absolute';                              this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                              this.style.paddingLeft = '16px';                              this.dataset.expanded = 'false';                            } else {                              var pd = this.previousElementSibling;                              pd.style.display = 'inline';                              pd.style.webkitLineClamp = 'unset';                              this.textContent = 'READ LESS';                              this.style.position = 'static';                              this.style.background = 'transparent';                              this.style.paddingLeft = '4px';                              this.dataset.expanded = 'true';                              pd.appendChild(this);                            }                          ">READ MORE${_button}                        \x3C/div>` : ''}                      ${_div}                    ${_div}                    ${deal.authorName ? `                      \x3Cdiv class="tg-df-author-line-mobile" style="padding: 0 0 12px 0; background: transparent;">                         \x3Cdiv style="display: flex; align-items: center; gap: 12px;">                            ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="40" height="40" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 40px; min-height: 40px;">` : ''}                            \x3Cdiv style="display: flex; flex-direction: column;">                               \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">\x3Cspan style="color: #FF6600;">${this.escapeHTML(deal.merchant)}${_span} deal recommended by:${_div}                               \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.3;">                                  \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                  ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                  ${deal.modifiedDate ? `\x3Cdiv style="color: var(--tg-df-text-muted); margin-top: 2px;">${getTimeAgo(deal.modifiedDate)}${_div}` : ''}                               ${_div}                            ${_div}                         ${_div}                      ${_div}                    ` : ''}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>View Deal${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                  \x3Cdiv class="tg-df-card-merchant-wrapper" style="position: absolute; bottom: 0; right: 0; background: transparent; padding: 8px 12px; z-index: 10;">                     \x3Cspan class="tg-df-card-merchant-pill" style="text-align: right; margin-bottom: 0;" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" disable-tracking="true" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cdiv class="tg-df-card-desc-container" style="margin-bottom: 12px; position: relative;">                    \x3Cp class="tg-df-card-desc-content" style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${this.escapeHTML(deal.description)}${_p}                    \x3Cbutton type="button" class="tg-df-card-desc-btn" style="display: none; appearance: none; border: none; color: #000000; font-size: 11px; font-weight: 700; text-transform: uppercase; cursor: pointer; font-family: inherit; position: absolute; bottom: 2px; right: 0; background: linear-gradient(to right, transparent, #fff 20%, #fff); padding: 0 0 0 16px;" onclick="                      var c = this.parentNode;                      if (this.dataset.expanded === 'true') {                        var pd = (c.tagName === 'P') ? c : this.previousElementSibling;                        if (c.tagName === 'P') { c.parentNode.appendChild(this); pd = c; }                        pd.style.display = '-webkit-box';                        pd.style.webkitLineClamp = '3';                        this.textContent = 'READ MORE';                        this.style.position = 'absolute';                        this.style.background = 'linear-gradient(to right, transparent, #fff 20%, #fff)';                        this.style.paddingLeft = '16px';                        this.dataset.expanded = 'false';                      } else {                        var pd = this.previousElementSibling;                        pd.style.display = 'inline';                        pd.style.webkitLineClamp = 'unset';                        this.textContent = 'READ LESS';                        this.style.position = 'static';                        this.style.background = 'transparent';                        this.style.paddingLeft = '4px';                        this.dataset.expanded = 'true';                        pd.appendChild(this);                      }                    ">READ MORE${_button}                  \x3C/div>` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${deal.authorName ? `                    \x3Cdiv class="tg-df-author-line-desktop" style="padding: 0 0 ${isSavingsSquadMode ? 0 : 12}px 0;">                       \x3Cdiv style="display: flex; align-items: center; gap: 10px;">                          ${deal.authorImage ? `\x3Cimg src="${this.escapeHTML(deal.authorImage)}" alt="${this.escapeHTML(deal.authorName)}" class="tg-df-author-img" width="36" height="36" style="border-radius: 50%; object-fit: cover; flex-shrink: 0; aspect-ratio: 1 / 1; min-width: 36px; min-height: 36px;">` : ''}                          \x3Cdiv style="display: flex; flex-direction: column;">                             \x3Cdiv style="font-size: 10px; color: var(--tg-df-text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; font-weight: 600;">Recommended by:${_div}                             \x3Cdiv style="font-size: 11px; color: var(--tg-df-text); line-height: 1.2;">                                \x3Cstrong>\x3Ca href="https://www.tomsguide.com/${this.escapeHTML(deal.documentUrl || '').replace(/^\/+/, '')}" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit; border-bottom: 1px dotted var(--tg-df-text-muted);">${this.escapeHTML(deal.authorName)}${_a}${_strong}                                ${deal.authorRole && !['null', 'nul', 'undefined'].includes(String(deal.authorRole).toLowerCase()) ? ` • ${this.escapeHTML(deal.authorRole)}` : ''}                                ${deal.modifiedDate ? `\x3Cspan style="color: var(--tg-df-text-muted);"> • ${getTimeAgo(deal.modifiedDate)}${_span}` : ''}                             ${_div}                          ${_div}                       ${_div}                    ${_div}                    ` : ''}                    ${priceGroupHtml}                  ${_div}                ${_div}                \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta" style="text-decoration: none; border-radius: 0;">${ctaText}${_a}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit) {            dealsHtml += `              \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer;">Load More${_button}              ${_div}            `;          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }          setTimeout(() => {            const contents = this.root.querySelectorAll('.tg-df-card-desc-content');            contents.forEach(p => {              if (p.scrollHeight > p.clientHeight || p.scrollHeight > 60) {                if (p.nextElementSibling) {                  p.nextElementSibling.style.display = 'block';                }              }            });                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));          }, 50);          const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              this.displayLimit += this.getRowsLimit();              this.render();            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Enter the Vitamix Nano: Could it be the answer to perfectly blended single-serve smoothies? ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Vitamix makes some of the <a href="https://www.tomsguide.com/best-picks/best-blenders">best blenders</a> on the market — our testing at Tom’s Guide consistently proves it — but the brand’s premium price tags often put them out of reach.</p><p>However, that just changed with the launch of the Vitamix Nano. The brand is re-entering the single-serve market with a compact, personal blender design for the health-conscious in mind, and it’s available for <a href="https://www.vitamix.com/us/en_us" target="_blank" rel="nofollow">$199 at Vitamix</a>.</p><h2 id="single-serve-smoothies">Single-serve smoothies</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="bYv4sFXPAXKQ25oCFkmWTc" name="Vitamix Nano" alt="Vitamix Nano" src="https://cdn.mos.cms.futurecdn.net/bYv4sFXPAXKQ25oCFkmWTc-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Vitamix)</span></figcaption></figure><p>The compact Nano isn’t designed for big elaborate feasts. Instead, it focuses on the essentials: creating smoothies and frozen drinks with a small footprint that won’t overcrowd your countertop.</p><p>Although you don’t get all the multi-functions of other Vitamix blenders, such as the <a href="https://www.tomsguide.com/home/home-appliances/vitamix-ascent-x2-blender-review">Vitamix Ascent X2</a>, which takes the top spot in our <a href="https://www.tomsguide.com/best-picks/best-blenders">best blenders buying guide</a>, you don’t get short-changed on performance. The Vitamix Nano has a single purpose.</p><div class="product"><a data-dimension112="196edacc-9fac-11f1-a0b9-e9e3c8c2a9ea" data-action="Deal Block" data-label="Nano" data-dimension48="Nano" data-dimension25="$199" href="https://www.vitamix.com/us/en_us/products/nano" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="qRJet8VAb3tngGTe3hwQ39" name="Vitamix Nano" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/qRJet8VAb3tngGTe3hwQ39-1920-80.png" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.vitamix.com/us/en_us/products/nano" target="_blank" rel="nofollow" data-dimension112="196edacc-9fac-11f1-a0b9-e9e3c8c2a9ea" data-action="Deal Block" data-label="Nano" data-dimension48="Nano" data-dimension25="$199">Nano: $199</a></strong><br />The Vitamix personal, single-serve blender that thinks while it blends. Select the SmoothiePilot setting, and the blender will automatically adjust the speed and timing to achieve the right texture. Or, opt for the variable speed for a personalized choice.  <a class="view-deal button" href="https://www.vitamix.com/us/en_us/products/nano" target="_blank" rel="nofollow" data-dimension112="196edacc-9fac-11f1-a0b9-e9e3c8c2a9ea" data-action="Deal Block" data-label="Nano" data-dimension48="Nano" data-dimension25="$199">View Deal</a></p></div><h2 id="intelligent-blending">Intelligent blending</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3NBt4nQV6d8iYABTmherzA" name="Vitamix Nano" alt="Vitamix Nano" src="https://cdn.mos.cms.futurecdn.net/3NBt4nQV6d8iYABTmherzA-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Vitamix)</span></figcaption></figure><p>At the heart of the Vitamix Nano is SmoothiePilot — the brand’s first adaptive smoothie feature. So what exactly does that mean? It senses what’s happening inside the cup and automatically selects the optimal blend program, adjusting the speed and duration to deliver a smooth result, whether making a smoothie or frozen cocktail.</p><p>Laura Ostenkamp, vice president of sales and marketing at Vitamix, says, in short, it "blends every time with no guesswork required."</p><p>Does this put an end to pausing mid-blend to check and stir the ingredients, and to finding unexpected lumps in your cocktails? We’ll have to see how it performs once we receive a unit to test. </p><h2 id="the-vitamix-nano-what-do-you-get">The Vitamix Nano: What do you get?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ZfwKLjkxXTXkmTGBABPzQc" name="Vitamix Nano" alt="Vitamix Nano" src="https://cdn.mos.cms.futurecdn.net/ZfwKLjkxXTXkmTGBABPzQc-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Vitamix)</span></figcaption></figure><p>So what does this compact <strong>20-ounce cup</strong> blender offer, and is it worth paying $199 for the privilege? Vitamix says it comes with a high-powered <strong>1,000-watt motor</strong> and <strong>hardened stainless steel blades</strong> to tackle tough ingredients like ice and frozen fruit. </p><p>What’s more, the technology takes away all the hard work, making the controls simple: select <strong>SmoothiePilot</strong> for a perfectly smooth drink, or select <strong>variable speed</strong> for your preferred texture. </p><p>You also get <strong>two cups with lids</strong>, so you can blend your drinks and go, or keep one in the refrigerator for later.<br /><br />Cleaning a blender can be notoriously tricky, but once you’ve made your drink, clean up is easy. According to Vitamix, it <strong>self-cleans in 30 seconds</strong>; just add hot water and a drop of dish soap; there’s no need to disassemble the unit. But, for an easy life, it’s also <strong>dishwasher-safe</strong>. </p><p>And if you’re wondering whether you have enough space for another gadget on your countertop, the Vitamix Nano is mini. It measures just 8.5 inches x 5.5 inches at the base, and stands 15.3 inches tall. </p><p>The only choice you’ll have to make apart from selecting SmoothiePilot or the variable control is whether to buy the white or black version. My money is on the black, although I’d like to see a few punchy candy colors introduced in the future.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/kitchen-dining/vitamix-just-released-an-entry-level-version-of-our-all-time-favorite-blender">Vitamix just released an entry-level version of our all-time favorite blender</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/ninja-blast-max-review">I made smoothies, shakes and pancake batter in Ninja's most powerful portable blender — here's my verdict</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/i-threw-out-my-nutribullet-blender-after-testing-this-beast-personal-blender-heres-why">I threw out my Nutribullet blender after testing this Beast personal blender — here's why</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/kitchen-dining/enter-the-vitamix-nano-could-it-be-the-answer-to-perfectly-blended-single-serve-smoothies</link>
                                                                            <description>
                            <![CDATA[ Vitamix just launched a new personal blender with intelligent tech: Is it worth $199? ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">9o2Ahgvh7Wwc68qQbD48Tk</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/YgkcnUArksceTGzwaftMU3-1920-80.png" type="image/png" length="0"></enclosure>
                                                                        <pubDate>Mon, 24 Aug 2026 13:53:29 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Kitchen & Dining]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                <author><![CDATA[ camilla.sharman@futurenet.com (Camilla Sharman) ]]></author>                    <dc:creator><![CDATA[ Camilla Sharman ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/nY4nvWzofHKHpvzAqN5LVH-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Camilla is the Homes Staff Writer and covers everything to do with homes and gardens. She has a wealth of editorial experience, mounting over 30 years, and covers news and features, tests products for reviews and compiles buying guides.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Her work has appeared in business and consumer titles, including Ideal Home, Real Homes, House Beautiful, Homebuilding &amp;amp; Renovation, and Kitchen &amp;amp; Bathroom Business. She’s even appeared on the cover of Your Home, writing about her own house renovation.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Although she’s obsessed with decorating her home, she also enjoys baking and trying out the latest kitchen appliances. But when she’s not inside, you’ll find her pottering about in her yard, tending to her vegetable patch or taking in her prized hydrangeas. She also enjoys keeping fit, and if she&#039;s not on a spin bike trying to keep up with the class, she&#039;ll be in the pool, or trying to perfect her headstand in a yoga class.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/png" url="https://cdn.mos.cms.futurecdn.net/YgkcnUArksceTGzwaftMU3-1920-80.png">
                                                            <media:credit><![CDATA[Vitamix]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Vitamix Nano in black]]></media:description>                                                            <media:text><![CDATA[Vitamix Nano in black]]></media:text>
                                <media:title type="plain"><![CDATA[Vitamix Nano in black]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/YgkcnUArksceTGzwaftMU3-1920-80.png" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Vitamix makes some of the <a href="https://www.tomsguide.com/best-picks/best-blenders">best blenders</a> on the market — our testing at Tom’s Guide consistently proves it — but the brand’s premium price tags often put them out of reach.</p><p>However, that just changed with the launch of the Vitamix Nano. The brand is re-entering the single-serve market with a compact, personal blender design for the health-conscious in mind, and it’s available for <a href="https://www.vitamix.com/us/en_us" target="_blank" rel="nofollow">$199 at Vitamix</a>.</p><h2 id="single-serve-smoothies">Single-serve smoothies</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="bYv4sFXPAXKQ25oCFkmWTc" name="Vitamix Nano" alt="Vitamix Nano" src="https://cdn.mos.cms.futurecdn.net/bYv4sFXPAXKQ25oCFkmWTc-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Vitamix)</span></figcaption></figure><p>The compact Nano isn’t designed for big elaborate feasts. Instead, it focuses on the essentials: creating smoothies and frozen drinks with a small footprint that won’t overcrowd your countertop.</p><p>Although you don’t get all the multi-functions of other Vitamix blenders, such as the <a href="https://www.tomsguide.com/home/home-appliances/vitamix-ascent-x2-blender-review">Vitamix Ascent X2</a>, which takes the top spot in our <a href="https://www.tomsguide.com/best-picks/best-blenders">best blenders buying guide</a>, you don’t get short-changed on performance. The Vitamix Nano has a single purpose.</p><div class="product"><a data-dimension112="196edacc-9fac-11f1-a0b9-e9e3c8c2a9ea" data-action="Deal Block" data-label="Nano" data-dimension48="Nano" data-dimension25="$199" href="https://www.vitamix.com/us/en_us/products/nano" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="qRJet8VAb3tngGTe3hwQ39" name="Vitamix Nano" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/qRJet8VAb3tngGTe3hwQ39-1920-80.png" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.vitamix.com/us/en_us/products/nano" target="_blank" rel="nofollow" data-dimension112="196edacc-9fac-11f1-a0b9-e9e3c8c2a9ea" data-action="Deal Block" data-label="Nano" data-dimension48="Nano" data-dimension25="$199">Nano: $199</a></strong><br />The Vitamix personal, single-serve blender that thinks while it blends. Select the SmoothiePilot setting, and the blender will automatically adjust the speed and timing to achieve the right texture. Or, opt for the variable speed for a personalized choice.  <a class="view-deal button" href="https://www.vitamix.com/us/en_us/products/nano" target="_blank" rel="nofollow" data-dimension112="196edacc-9fac-11f1-a0b9-e9e3c8c2a9ea" data-action="Deal Block" data-label="Nano" data-dimension48="Nano" data-dimension25="$199">View Deal</a></p></div><h2 id="intelligent-blending">Intelligent blending</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3NBt4nQV6d8iYABTmherzA" name="Vitamix Nano" alt="Vitamix Nano" src="https://cdn.mos.cms.futurecdn.net/3NBt4nQV6d8iYABTmherzA-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Vitamix)</span></figcaption></figure><p>At the heart of the Vitamix Nano is SmoothiePilot — the brand’s first adaptive smoothie feature. So what exactly does that mean? It senses what’s happening inside the cup and automatically selects the optimal blend program, adjusting the speed and duration to deliver a smooth result, whether making a smoothie or frozen cocktail.</p><p>Laura Ostenkamp, vice president of sales and marketing at Vitamix, says, in short, it "blends every time with no guesswork required."</p><p>Does this put an end to pausing mid-blend to check and stir the ingredients, and to finding unexpected lumps in your cocktails? We’ll have to see how it performs once we receive a unit to test. </p><h2 id="the-vitamix-nano-what-do-you-get">The Vitamix Nano: What do you get?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ZfwKLjkxXTXkmTGBABPzQc" name="Vitamix Nano" alt="Vitamix Nano" src="https://cdn.mos.cms.futurecdn.net/ZfwKLjkxXTXkmTGBABPzQc-1920-80.png" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Vitamix)</span></figcaption></figure><p>So what does this compact <strong>20-ounce cup</strong> blender offer, and is it worth paying $199 for the privilege? Vitamix says it comes with a high-powered <strong>1,000-watt motor</strong> and <strong>hardened stainless steel blades</strong> to tackle tough ingredients like ice and frozen fruit. </p><p>What’s more, the technology takes away all the hard work, making the controls simple: select <strong>SmoothiePilot</strong> for a perfectly smooth drink, or select <strong>variable speed</strong> for your preferred texture. </p><p>You also get <strong>two cups with lids</strong>, so you can blend your drinks and go, or keep one in the refrigerator for later.<br /><br />Cleaning a blender can be notoriously tricky, but once you’ve made your drink, clean up is easy. According to Vitamix, it <strong>self-cleans in 30 seconds</strong>; just add hot water and a drop of dish soap; there’s no need to disassemble the unit. But, for an easy life, it’s also <strong>dishwasher-safe</strong>. </p><p>And if you’re wondering whether you have enough space for another gadget on your countertop, the Vitamix Nano is mini. It measures just 8.5 inches x 5.5 inches at the base, and stands 15.3 inches tall. </p><p>The only choice you’ll have to make apart from selecting SmoothiePilot or the variable control is whether to buy the white or black version. My money is on the black, although I’d like to see a few punchy candy colors introduced in the future.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/kitchen-dining/vitamix-just-released-an-entry-level-version-of-our-all-time-favorite-blender">Vitamix just released an entry-level version of our all-time favorite blender</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/ninja-blast-max-review">I made smoothies, shakes and pancake batter in Ninja's most powerful portable blender — here's my verdict</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/i-threw-out-my-nutribullet-blender-after-testing-this-beast-personal-blender-heres-why">I threw out my Nutribullet blender after testing this Beast personal blender — here's why</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I've got a fly infestation — here's the hack I found to tackle the problem for good ]]></title>
                                                                                                <dc:content><![CDATA[ <p>I'm sure I'm not the only one that has noticed there's <em>a lot</em> more flies this year. Or, at least it feels like it when they buzz directly into my home as soon as I seem to open a door or window. </p><p>Not only are they seriously annoying, but they're also disease spreaders, can multiple very fast, and some of them even bite (depending on the species).</p><p>So, when I realized that the fly situation in my home was getting a little out of hand, I wanted to make sure I did something about it. Fortunately, my social media algorithm must've heard me talking about the flies because it started popping up with solutions.</p><p>And there was one TikTok in particular that caught my eye. Here's the hack I've been using to keep flies away from my home – and it's a real treat to hear no more incessant buzzing.</p>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@mrsclarehoops/video/7398806180191145249" data-video-id="7398806180191145249" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@mrsclarehoops" href="https://www.tiktok.com/@mrsclarehoops">@mrsclarehoops</a>                            <p></p><a target="_blank" title="♬ Im a Believer - harrisonparker.wildb" href="https://www.tiktok.com/music/Im-a-Believer-7009403574811740934">♬ Im a Believer - harrisonparker.wildb</a></section>                    </blockquote></div>                <h2 id="how-it-works-2">How it works</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4657px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="GxioKV5LbvNSmLdam6YWKW" name="shutterstock_1078037726.jpg" alt="House flies" src="https://cdn.mos.cms.futurecdn.net/GxioKV5LbvNSmLdam6YWKW-1920-80.jpg" mos="" align="middle" fullscreen="" width="4657" height="2620" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Influencer <a href="https://www.tiktok.com/@mrsclarehoops" target="_blank" rel="nofollow">@mrsclarehoops</a> has over 250k followers on her TikTok account where she posts a variety of easy, thrifty and helpful crafts and DIY tips and tricks.</p><p>And she posted a video titled: "Today yrs old when you found this natural fruit fly repellent," where she holds up a little bundle of helpful, natural and eco-friendly kitchen staples.</p><p>Using mint, lavender, and <a href="https://www.tomsguide.com/home/gardening/rosemary-plant-turning-brown-start-with-the-scratch-test-to-save-it">rosemary</a>, she creates a small bouquet to place around the home, especially in areas where you'd find food sources like the kitchen.</p><p>Flies hate all three of these items because they produce strong-scented oils and aromas that these particular insects don't like. Even better? It's also a great deterrent for mosquitoes, ants, moths, and spiders!</p><p>You may well have these in your home already, but if not, it's a great excuse to go foraging, ask friends or family, or head to the nearest grocery shop.</p><h2 id="other-ways-to-get-rid-of-flies">Other ways to get rid of flies</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1600px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="qEhXgrmhww7wWMjQrQQQ2E" name="shutterstock_2009370605 fruit fly on apple" alt="Fruit fly traps" src="https://cdn.mos.cms.futurecdn.net/qEhXgrmhww7wWMjQrQQQ2E-1920-80.jpg" mos="" align="middle" fullscreen="" width="1600" height="900" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Using this TikTok hack is certainly not the only thing you can do to get rid of flies in your home though. Most importantly, you'll want to make sure that all your food is covered, your bins and any trash are sealed properly, and cleaning up any crumbs is kept on top of. </p><p>If you let organic waste litter your home, flies will come to feed on it. Take away their food, reduce the chance of them coming in looking for it. </p><p>Removing all of these things should do the trick, but there's always the little bundles of mint, rosemary and lavender to use as an extra layer of defense. And there's <a href="https://www.tomsguide.com/home/say-goodbye-to-kitchen-trash-flies-the-one-kitchen-staple-that-stops-them-in-their-tracks">other kitchen staples to deter flies</a> that you can try, too.</p><p>If you notice the natural route isn't quite working for you, there's always specific fly sprays and pesticides that you can turn to, if you want. </p><p>Ultimately, if you put in preventative measures in the first place, the flies won't come. It's only if you allow them into your home and don't do anything about it that you'll begin to notice them spreading <em>fast</em>. And I for one certainly don't want that.</p><div class="product"><a data-dimension112="e72e2956-9573-11f1-8938-b90a648d638f" data-action="Deal Block" data-label="Insecticide Spray" data-dimension48="Insecticide Spray" data-dimension25="$7.28" href="https://www.amazon.com/Stem-Kills-Ants-Roaches-Flies/dp/B09GD81Q4S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="fECtRJbyZPJz9wBMGALgYZ" name="fly_spray_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fECtRJbyZPJz9wBMGALgYZ-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Stem-Kills-Ants-Roaches-Flies/dp/B09GD81Q4S" target="_blank" rel="nofollow" data-dimension112="e72e2956-9573-11f1-8938-b90a648d638f" data-action="Deal Block" data-label="Insecticide Spray" data-dimension48="Insecticide Spray" data-dimension25="$7.28">Insecticide Spray: $7.28</a></strong><br />This plant-based active ingredient bug spray is perfect for targeting not only flies, but ants and roaches too. Safe to use around people and pets (when used as directed), it's a solution for those wanting something stronger without fully committing to chemical-heavy bug sprays.<a class="view-deal button" href="https://www.amazon.com/Stem-Kills-Ants-Roaches-Flies/dp/B09GD81Q4S" target="_blank" rel="nofollow" data-dimension112="e72e2956-9573-11f1-8938-b90a648d638f" data-action="Deal Block" data-label="Insecticide Spray" data-dimension48="Insecticide Spray" data-dimension25="$7.28">View Deal</a></p></div><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/expert-shares-clever-ice-cube-hack-that-could-banish-flies-from-your-yard-this-summer">Expert shares clever ice cube hack that could banish flies from your yard this summer</a></li><li><a href="https://www.tomsguide.com/home/i-tried-3-ways-of-getting-rid-of-fruit-flies-on-amazon-and-theres-a-clear-winner">I finally banished fruit flies for good using this $7 gadget from Amazon</a></li><li><a href="https://www.tomsguide.com/home/flies-ruining-your-summer-heres-how-to-stop-them-with-one-simple-trick">House flies ruining your summer? Keep them out with these plants</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/ive-got-a-fly-infestation-heres-the-hack-i-found-to-tackle-the-problem-for-good</link>
                                                                            <description>
                            <![CDATA[ Flies in your home are ridiculously hard to ignore. Aside from their annoying buzzing, they're also a gross addition to your family. Fortunately, I've found a hack that'll send them packing. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">kD3Jxhzu7w9MVPJVttob9j</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/DTrHeKrpHcyqunYXpuhVyg-1920-80.png" type="image/png" length="0"></enclosure>
                                                                        <pubDate>Mon, 24 Aug 2026 08:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/png" url="https://cdn.mos.cms.futurecdn.net/DTrHeKrpHcyqunYXpuhVyg-1920-80.png">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Flies on meat]]></media:description>                                                            <media:text><![CDATA[Flies on meat]]></media:text>
                                <media:title type="plain"><![CDATA[Flies on meat]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/DTrHeKrpHcyqunYXpuhVyg-1920-80.png" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I'm sure I'm not the only one that has noticed there's <em>a lot</em> more flies this year. Or, at least it feels like it when they buzz directly into my home as soon as I seem to open a door or window. </p><p>Not only are they seriously annoying, but they're also disease spreaders, can multiple very fast, and some of them even bite (depending on the species).</p><p>So, when I realized that the fly situation in my home was getting a little out of hand, I wanted to make sure I did something about it. Fortunately, my social media algorithm must've heard me talking about the flies because it started popping up with solutions.</p><p>And there was one TikTok in particular that caught my eye. Here's the hack I've been using to keep flies away from my home – and it's a real treat to hear no more incessant buzzing.</p>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@mrsclarehoops/video/7398806180191145249" data-video-id="7398806180191145249" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@mrsclarehoops" href="https://www.tiktok.com/@mrsclarehoops">@mrsclarehoops</a>                            <p></p><a target="_blank" title="♬ Im a Believer - harrisonparker.wildb" href="https://www.tiktok.com/music/Im-a-Believer-7009403574811740934">♬ Im a Believer - harrisonparker.wildb</a></section>                    </blockquote></div>                <h2 id="how-it-works-2">How it works</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4657px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="GxioKV5LbvNSmLdam6YWKW" name="shutterstock_1078037726.jpg" alt="House flies" src="https://cdn.mos.cms.futurecdn.net/GxioKV5LbvNSmLdam6YWKW-1920-80.jpg" mos="" align="middle" fullscreen="" width="4657" height="2620" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Influencer <a href="https://www.tiktok.com/@mrsclarehoops" target="_blank" rel="nofollow">@mrsclarehoops</a> has over 250k followers on her TikTok account where she posts a variety of easy, thrifty and helpful crafts and DIY tips and tricks.</p><p>And she posted a video titled: "Today yrs old when you found this natural fruit fly repellent," where she holds up a little bundle of helpful, natural and eco-friendly kitchen staples.</p><p>Using mint, lavender, and <a href="https://www.tomsguide.com/home/gardening/rosemary-plant-turning-brown-start-with-the-scratch-test-to-save-it">rosemary</a>, she creates a small bouquet to place around the home, especially in areas where you'd find food sources like the kitchen.</p><p>Flies hate all three of these items because they produce strong-scented oils and aromas that these particular insects don't like. Even better? It's also a great deterrent for mosquitoes, ants, moths, and spiders!</p><p>You may well have these in your home already, but if not, it's a great excuse to go foraging, ask friends or family, or head to the nearest grocery shop.</p><h2 id="other-ways-to-get-rid-of-flies">Other ways to get rid of flies</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1600px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="qEhXgrmhww7wWMjQrQQQ2E" name="shutterstock_2009370605 fruit fly on apple" alt="Fruit fly traps" src="https://cdn.mos.cms.futurecdn.net/qEhXgrmhww7wWMjQrQQQ2E-1920-80.jpg" mos="" align="middle" fullscreen="" width="1600" height="900" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Using this TikTok hack is certainly not the only thing you can do to get rid of flies in your home though. Most importantly, you'll want to make sure that all your food is covered, your bins and any trash are sealed properly, and cleaning up any crumbs is kept on top of. </p><p>If you let organic waste litter your home, flies will come to feed on it. Take away their food, reduce the chance of them coming in looking for it. </p><p>Removing all of these things should do the trick, but there's always the little bundles of mint, rosemary and lavender to use as an extra layer of defense. And there's <a href="https://www.tomsguide.com/home/say-goodbye-to-kitchen-trash-flies-the-one-kitchen-staple-that-stops-them-in-their-tracks">other kitchen staples to deter flies</a> that you can try, too.</p><p>If you notice the natural route isn't quite working for you, there's always specific fly sprays and pesticides that you can turn to, if you want. </p><p>Ultimately, if you put in preventative measures in the first place, the flies won't come. It's only if you allow them into your home and don't do anything about it that you'll begin to notice them spreading <em>fast</em>. And I for one certainly don't want that.</p><div class="product"><a data-dimension112="e72e2956-9573-11f1-8938-b90a648d638f" data-action="Deal Block" data-label="Insecticide Spray" data-dimension48="Insecticide Spray" data-dimension25="$7.28" href="https://www.amazon.com/Stem-Kills-Ants-Roaches-Flies/dp/B09GD81Q4S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="fECtRJbyZPJz9wBMGALgYZ" name="fly_spray_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fECtRJbyZPJz9wBMGALgYZ-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Stem-Kills-Ants-Roaches-Flies/dp/B09GD81Q4S" target="_blank" rel="nofollow" data-dimension112="e72e2956-9573-11f1-8938-b90a648d638f" data-action="Deal Block" data-label="Insecticide Spray" data-dimension48="Insecticide Spray" data-dimension25="$7.28">Insecticide Spray: $7.28</a></strong><br />This plant-based active ingredient bug spray is perfect for targeting not only flies, but ants and roaches too. Safe to use around people and pets (when used as directed), it's a solution for those wanting something stronger without fully committing to chemical-heavy bug sprays.<a class="view-deal button" href="https://www.amazon.com/Stem-Kills-Ants-Roaches-Flies/dp/B09GD81Q4S" target="_blank" rel="nofollow" data-dimension112="e72e2956-9573-11f1-8938-b90a648d638f" data-action="Deal Block" data-label="Insecticide Spray" data-dimension48="Insecticide Spray" data-dimension25="$7.28">View Deal</a></p></div><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/expert-shares-clever-ice-cube-hack-that-could-banish-flies-from-your-yard-this-summer">Expert shares clever ice cube hack that could banish flies from your yard this summer</a></li><li><a href="https://www.tomsguide.com/home/i-tried-3-ways-of-getting-rid-of-fruit-flies-on-amazon-and-theres-a-clear-winner">I finally banished fruit flies for good using this $7 gadget from Amazon</a></li><li><a href="https://www.tomsguide.com/home/flies-ruining-your-summer-heres-how-to-stop-them-with-one-simple-trick">House flies ruining your summer? Keep them out with these plants</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Want to attract hummingbirds to your yard? It turns out there's a sweet spot for hanging your feeder ]]></title>
                                                                                                <dc:content><![CDATA[ <p>I've got two bird feeders in my garden already, but I recently learned I need one more. Why? Well, there's a special one specifically designed to <a href="https://www.tomsguide.com/home/gardening/the-reason-hummingbirds-return-to-your-yard-and-how-to-keep-them-coming-back">attract hummingbirds</a> – and I'd <em>love</em> to have more of these adorable, vibrant birds coming to visit.</p><p>Not only are they lovely to look at, showing off their unique flying moves from hoovering in midair to flying backward, but they're also great pollinators, boosting your garden's ecosystem for the better.</p><p>But, while I've figured out the type of feeder I need, designed to hold liquid sugar water with flower shapes to suit their long beaks, I've also discovered that there's a sweet spot on where you should hang them – and fortunately, it's pretty simple.</p><p>So, if you're like me and are eager to attract hummingbirds to your outside space, here's everything you need to know about exactly where it should go for the best chance at attracting these feathered friends.</p><h2 id="where-should-i-hang-my-feeder">Where should I hang my feeder?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="agdtUiiJ9qrmUeVwCN9AmF" name="shutterstock_2244875367" alt="Hummingbird feeder" src="https://cdn.mos.cms.futurecdn.net/agdtUiiJ9qrmUeVwCN9AmF-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>When hanging your hummingbird feeder, it turns out it's the height that's <em>really</em> important. For this, you want to aim for about 6 feet off the ground. This is a sweet spot for hummingbirds as it's high enough to stay away from predators (namely cats) so acts as a safe space for them to settle down and eat.</p><p>But, you want to make sure you're not placing it <em>too</em> high. This would put it away from natural food sources in your yard like flowers and shrubs, as well as opportunities for water.</p><p>They also won't be looking for a feeder up that high, especially if it's away from where they'd usually travel. As well as height though, there's a couple of other things to consider when hanging up your feeder. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4807px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="YmEVmVK6myh7xSVdGjjjvB" name="shutterstock_2015085041.jpg" alt="Hummingbird drinking water" src="https://cdn.mos.cms.futurecdn.net/YmEVmVK6myh7xSVdGjjjvB-1920-80.jpg" mos="" align="middle" fullscreen="" width="4807" height="2704" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Keeping it away from windows so they don't crash into the glass  is also important, as well as putting it in a shaded area with a touch of sun so that the nectar stays fresh. If you leave it in direct sunlight, the nectar can spoil and make the hummingbirds sick.</p><p>Something even better you can do? The <a href="https://www.fws.gov/story/hummingbirds-north-america" target="_blank" rel="nofollow">U.S. Fish and Wildlife Service</a> recommends growing specific plants to attract hummingbirds to your yard: "Hummingbirds prefer to nest near a ready supply of nectar and other food like insects, so you can encourage them to live in or near your home or business by maintaining some shrubbery and deciduous trees in which they can seek protective cover."</p><p>"As seasons change, it can also help to leave any leaf litter on the ground as it becomes important habitat for many of the insects and spiders they also eat."</p><h2 id="what-to-put-in-your-hummingbird-feeder">What to put in your hummingbird feeder</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@hiddenacrehome/video/7609911443441323278" data-video-id="7609911443441323278" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@hiddenacrehome" href="https://www.tiktok.com/@hiddenacrehome">@hiddenacrehome</a>                            <p></p><a target="_blank" title="♬ Everywhere - Fleetwood Mac" href="https://www.tiktok.com/music/Everywhere-6884304532432587525">♬ Everywhere - Fleetwood Mac</a></section>                    </blockquote></div>                <p>Yes, hummingbirds like to eat leaves, spiders and flowers, but that's not what you should be putting in your feeder. </p><p>If you're wondering what you to put in them instead to lure in these little birds, there's plenty of advice online, but TikTok helped me out once again with some top tips. Creator <a href="https://www.tiktok.com/@hiddenacrehome" target="_blank" rel="nofollow">@hiddenacrehome</a> has shared a simple recipe with almost 80 thousand views and counting that seems like an easy solution.</p><p>All you need is a 4:1 ratio mix of water and sugar. So, with 4 cups of water, add 1 cup of sugar. Give it a good shake and use it to refill your hummingbird feeder whenever needed.</p><p>A sweet treat paired with a sweet spot should hopefully attract more hummingbirds to your yard, but you'll still need to have a little patience and be sure to keep the noise levels down. They scare easily.</p><div class="product"><a data-dimension112="9c9cf980-955f-11f1-bb1e-874fc57f39b5" data-action="Deal Block" data-label="2-Pack Hummingbird Feeder" data-dimension48="2-Pack Hummingbird Feeder" data-dimension25="$19.99" href="https://www.amazon.com/Hummingbird-Feeder-Leakproof-Plastic-Mouth/dp/B07Q777DKY" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="vvduuP9w9UNUY4jmWtBf66" name="hummingbird_feeders_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/vvduuP9w9UNUY4jmWtBf66-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Hummingbird-Feeder-Leakproof-Plastic-Mouth/dp/B07Q777DKY" target="_blank" rel="nofollow" data-dimension112="9c9cf980-955f-11f1-bb1e-874fc57f39b5" data-action="Deal Block" data-label="2-Pack Hummingbird Feeder" data-dimension48="2-Pack Hummingbird Feeder" data-dimension25="$19.99">2-Pack Hummingbird Feeder: $19.99</a></strong><br />Why have one hummingbird feeder when you can have two? This double pack contains 5 feeding ports on each feeder, as well as a built-in ant guard, circular perch, wide mouth and easy-to-fill base.<a class="view-deal button" href="https://www.amazon.com/Hummingbird-Feeder-Leakproof-Plastic-Mouth/dp/B07Q777DKY" target="_blank" rel="nofollow" data-dimension112="9c9cf980-955f-11f1-bb1e-874fc57f39b5" data-action="Deal Block" data-label="2-Pack Hummingbird Feeder" data-dimension48="2-Pack Hummingbird Feeder" data-dimension25="$19.99">View Deal</a></p></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XpmN8e"></div>                            </div>                            <script src="https://kwizly.com/embed/XpmN8e.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/dont-make-this-hummingbird-mistake-why-you-need-to-think-beyond-the-color-red">Don’t make this hummingbird mistake — why you need to think beyond the color red</a></li><li><a href="https://www.tomsguide.com/home/gardening/hummingbirds-love-this-one-plant-and-it-blooms-in-fall-and-winter">This one plant is the secret to attracting hummingbirds to your yard in September</a></li><li><a href="https://www.tomsguide.com/home/protect-visiting-hummingbirds-from-summer-heat-in-just-3-easy-steps">3 easy steps to protect visiting hummingbirds from the summer heat</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/gardening/want-to-attract-hummingbirds-to-your-yard-it-turns-out-theres-a-sweet-spot-for-hanging-your-feeder</link>
                                                                            <description>
                            <![CDATA[ Buying a special feeder to attract hummingbirds to your outdoor space is one thing, but making sure you hang it in the right place is also just as important. Here's everything you need to know about finding that sweet spot. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">LwFHQC3isW2U2X4VLwYPsV</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/6tM6rYBKomquuM47hPC7GE-1920-80.png" type="image/png" length="0"></enclosure>
                                                                        <pubDate>Wed, 19 Aug 2026 10:30:00 +0000</pubDate>                                                                                                                                <updated>Thu, 27 Aug 2026 08:22:15 +0000</updated>
                                                                                                                                            <category><![CDATA[Gardening]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/png" url="https://cdn.mos.cms.futurecdn.net/6tM6rYBKomquuM47hPC7GE-1920-80.png">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Bee hummingbird in flight]]></media:description>                                                            <media:text><![CDATA[Bee hummingbird in flight]]></media:text>
                                <media:title type="plain"><![CDATA[Bee hummingbird in flight]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/6tM6rYBKomquuM47hPC7GE-1920-80.png" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I've got two bird feeders in my garden already, but I recently learned I need one more. Why? Well, there's a special one specifically designed to <a href="https://www.tomsguide.com/home/gardening/the-reason-hummingbirds-return-to-your-yard-and-how-to-keep-them-coming-back">attract hummingbirds</a> – and I'd <em>love</em> to have more of these adorable, vibrant birds coming to visit.</p><p>Not only are they lovely to look at, showing off their unique flying moves from hoovering in midair to flying backward, but they're also great pollinators, boosting your garden's ecosystem for the better.</p><p>But, while I've figured out the type of feeder I need, designed to hold liquid sugar water with flower shapes to suit their long beaks, I've also discovered that there's a sweet spot on where you should hang them – and fortunately, it's pretty simple.</p><p>So, if you're like me and are eager to attract hummingbirds to your outside space, here's everything you need to know about exactly where it should go for the best chance at attracting these feathered friends.</p><h2 id="where-should-i-hang-my-feeder">Where should I hang my feeder?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="agdtUiiJ9qrmUeVwCN9AmF" name="shutterstock_2244875367" alt="Hummingbird feeder" src="https://cdn.mos.cms.futurecdn.net/agdtUiiJ9qrmUeVwCN9AmF-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>When hanging your hummingbird feeder, it turns out it's the height that's <em>really</em> important. For this, you want to aim for about 6 feet off the ground. This is a sweet spot for hummingbirds as it's high enough to stay away from predators (namely cats) so acts as a safe space for them to settle down and eat.</p><p>But, you want to make sure you're not placing it <em>too</em> high. This would put it away from natural food sources in your yard like flowers and shrubs, as well as opportunities for water.</p><p>They also won't be looking for a feeder up that high, especially if it's away from where they'd usually travel. As well as height though, there's a couple of other things to consider when hanging up your feeder. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4807px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="YmEVmVK6myh7xSVdGjjjvB" name="shutterstock_2015085041.jpg" alt="Hummingbird drinking water" src="https://cdn.mos.cms.futurecdn.net/YmEVmVK6myh7xSVdGjjjvB-1920-80.jpg" mos="" align="middle" fullscreen="" width="4807" height="2704" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Keeping it away from windows so they don't crash into the glass  is also important, as well as putting it in a shaded area with a touch of sun so that the nectar stays fresh. If you leave it in direct sunlight, the nectar can spoil and make the hummingbirds sick.</p><p>Something even better you can do? The <a href="https://www.fws.gov/story/hummingbirds-north-america" target="_blank" rel="nofollow">U.S. Fish and Wildlife Service</a> recommends growing specific plants to attract hummingbirds to your yard: "Hummingbirds prefer to nest near a ready supply of nectar and other food like insects, so you can encourage them to live in or near your home or business by maintaining some shrubbery and deciduous trees in which they can seek protective cover."</p><p>"As seasons change, it can also help to leave any leaf litter on the ground as it becomes important habitat for many of the insects and spiders they also eat."</p><h2 id="what-to-put-in-your-hummingbird-feeder">What to put in your hummingbird feeder</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@hiddenacrehome/video/7609911443441323278" data-video-id="7609911443441323278" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@hiddenacrehome" href="https://www.tiktok.com/@hiddenacrehome">@hiddenacrehome</a>                            <p></p><a target="_blank" title="♬ Everywhere - Fleetwood Mac" href="https://www.tiktok.com/music/Everywhere-6884304532432587525">♬ Everywhere - Fleetwood Mac</a></section>                    </blockquote></div>                <p>Yes, hummingbirds like to eat leaves, spiders and flowers, but that's not what you should be putting in your feeder. </p><p>If you're wondering what you to put in them instead to lure in these little birds, there's plenty of advice online, but TikTok helped me out once again with some top tips. Creator <a href="https://www.tiktok.com/@hiddenacrehome" target="_blank" rel="nofollow">@hiddenacrehome</a> has shared a simple recipe with almost 80 thousand views and counting that seems like an easy solution.</p><p>All you need is a 4:1 ratio mix of water and sugar. So, with 4 cups of water, add 1 cup of sugar. Give it a good shake and use it to refill your hummingbird feeder whenever needed.</p><p>A sweet treat paired with a sweet spot should hopefully attract more hummingbirds to your yard, but you'll still need to have a little patience and be sure to keep the noise levels down. They scare easily.</p><div class="product"><a data-dimension112="9c9cf980-955f-11f1-bb1e-874fc57f39b5" data-action="Deal Block" data-label="2-Pack Hummingbird Feeder" data-dimension48="2-Pack Hummingbird Feeder" data-dimension25="$19.99" href="https://www.amazon.com/Hummingbird-Feeder-Leakproof-Plastic-Mouth/dp/B07Q777DKY" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="vvduuP9w9UNUY4jmWtBf66" name="hummingbird_feeders_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/vvduuP9w9UNUY4jmWtBf66-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Hummingbird-Feeder-Leakproof-Plastic-Mouth/dp/B07Q777DKY" target="_blank" rel="nofollow" data-dimension112="9c9cf980-955f-11f1-bb1e-874fc57f39b5" data-action="Deal Block" data-label="2-Pack Hummingbird Feeder" data-dimension48="2-Pack Hummingbird Feeder" data-dimension25="$19.99">2-Pack Hummingbird Feeder: $19.99</a></strong><br />Why have one hummingbird feeder when you can have two? This double pack contains 5 feeding ports on each feeder, as well as a built-in ant guard, circular perch, wide mouth and easy-to-fill base.<a class="view-deal button" href="https://www.amazon.com/Hummingbird-Feeder-Leakproof-Plastic-Mouth/dp/B07Q777DKY" target="_blank" rel="nofollow" data-dimension112="9c9cf980-955f-11f1-bb1e-874fc57f39b5" data-action="Deal Block" data-label="2-Pack Hummingbird Feeder" data-dimension48="2-Pack Hummingbird Feeder" data-dimension25="$19.99">View Deal</a></p></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XpmN8e"></div>                            </div>                            <script src="https://kwizly.com/embed/XpmN8e.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/dont-make-this-hummingbird-mistake-why-you-need-to-think-beyond-the-color-red">Don’t make this hummingbird mistake — why you need to think beyond the color red</a></li><li><a href="https://www.tomsguide.com/home/gardening/hummingbirds-love-this-one-plant-and-it-blooms-in-fall-and-winter">This one plant is the secret to attracting hummingbirds to your yard in September</a></li><li><a href="https://www.tomsguide.com/home/protect-visiting-hummingbirds-from-summer-heat-in-just-3-easy-steps">3 easy steps to protect visiting hummingbirds from the summer heat</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Don't let bugs hitch a ride — how to safely bring fresh flowers indoors ]]></title>
                                                                                                <dc:content><![CDATA[ <p>As the sunny weather brings out vibrant blooms and luscious leaves in my garden, I find myself fighting the urge to bring every single one of them indoors so I can enjoy them all day long. </p><p>Fortunately, I know that would be excessive, but that doesn't stop me from bringing <em>some</em> of them inside. Cutting fresh flowers from my garden and moving them into vases around my home is one of my favorite things to do in the summer. After all, why would I spend money on bouquets when I've got my own flower shop waiting in my garden?</p><p>But, I've learnt some hard lessons along the way, mainly when it comes to inviting bugs into my home riding the petals and stems of the flowers I want to enjoy. To avoid common mistakes, here's 5 top tips for bringing fresh flowers indoors.</p><h2 id="1-choose-the-right-time-of-day">1. Choose the right time of day</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1672px;"><p class="vanilla-image-block" style="padding-top:56.28%;"><img id="783t8a3fEEqvVwBG4eE2zg" name="Amanda Caswell's garden" alt="Amanda Caswell's Garden" src="https://cdn.mos.cms.futurecdn.net/783t8a3fEEqvVwBG4eE2zg-1920-80.png" mos="" align="middle" fullscreen="" width="1672" height="941" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>While you can cut fresh flowers from your garden at any time of day, there's definitely moments that are better than others. First thing in the morning or in the late evening are two of the best opportunities you have and there's a couple of reasons for that.</p><p>Firstly, you're doing it before it gets too hot or when the sun is cooling down. This way you're giving them a better chance of not wilting too quickly from the loss of water. </p><p>Secondly, insects aren't as active as these times of days so it's less likely that you'll be bringing them indoors.</p><h2 id="2-do-as-much-of-it-outside-as-possible">2. Do as much of it outside as possible</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:620px;"><p class="vanilla-image-block" style="padding-top:65.16%;"><img id="tPctm6bmxh3fLfKPv4oSaU" name="argos garden" alt="Argos Fixed Log Edging Regular - Pack Of 2" src="https://cdn.mos.cms.futurecdn.net/tPctm6bmxh3fLfKPv4oSaU-1920-80.jpg" mos="" align="middle" fullscreen="" width="620" height="404" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Argos)</span></figcaption></figure><p>When it comes to cutting fresh flowers, of course you'll be doing it outside at first, but you'll want to spend a bit more time out there then you might initially think. </p><p>This tip is a catch-all for the other tips I'm about to cover, too, meaning you should do pretty much all of the work outside. This will ensure you give any insects and pollen time to drop off in the best place – rather than inside your home.</p><h2 id="3-strip-the-lower-leaves-away">3. Strip the lower leaves away</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="GJnUW6XaPtP9QxiDcskv77" name="shutterstock_2011615187" alt="Cutting flower stem at an angle with a clean pair of pruning shears" src="https://cdn.mos.cms.futurecdn.net/GJnUW6XaPtP9QxiDcskv77-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>As you'd do with any shop-bought flowers, it's best to strip away the lower leaves from each stem. When you buy them, doing this avoids the leaves stagnating and rotting in the water. </p><p>When you're cutting them from your garden, this is also the case <em>but</em> with the added benefit of getting rid of any insect stragglers clinging on or any messy soil that could dirty up your home.</p><h2 id="4-give-them-a-good-shake">4. Give them a good shake</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3200px;"><p class="vanilla-image-block" style="padding-top:56.28%;"><img id="2hhK2vb3vKC8a72Fx5hq3g" name="shutterstock_2155781169 primrose flowers" alt="Flowers that love the rain primrose flowers" src="https://cdn.mos.cms.futurecdn.net/2hhK2vb3vKC8a72Fx5hq3g-1920-80.jpg" mos="" align="middle" fullscreen="" width="3200" height="1801" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>It's also a good idea to give your flowers a little shake, emphasis on the <em>little</em>. You don't want to destroy the flowers or risk shaking off the lovely petals, but you also want to give any insects the chance to jump ship.</p><p>It's best to do this with the flowers facing downwards as insects can easily hide inside the petals and leaves that are curled upwards.</p><h2 id="5-soak-them-in-cold-water">5. Soak them in cold water</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:59.60%;"><img id="BnM9Wsw62ueQqr3rjBdtDk" name="Daffodils in a vase of cold water" alt="Daffodils in a vase of cold water" src="https://cdn.mos.cms.futurecdn.net/BnM9Wsw62ueQqr3rjBdtDk-1920-80.jpg" mos="" align="middle" fullscreen="" width="1510" height="900" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>It's especially handy to have a bucket of cold water by your side when you're cutting your fresh flowers to soak them in. This will help give them a quick wash to remove any excess soil, insects, or anything else you don't want inside your home.</p><p>If you've had enough time outside, you can also put the bucket in your bathtub or even run some water into the bath to clean them for around 30 minutes before putting them in a vase. Then, you can enjoy your outdoor flowers without worrying about extra visitors in your home.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/outdoors/dont-throw-them-out-3-ways-to-use-banana-peels-in-the-garden">Don't throw them out — 3 ways to use banana peels in the garden</a></li><li><a href="https://www.tomsguide.com/home/outdoors/gardeners-urged-to-leave-a-bowl-of-beer-in-the-yard-this-summer-heres-why">Gardeners urged to leave a bowl of beer in the yard this summer — here's why</a></li><li><a href="https://www.tomsguide.com/how-to/how-to-get-rid-of-fruit-flies-fast">How to get rid of fruit flies fast</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/gardening/dont-let-bugs-hitch-a-ride-how-to-safely-bring-fresh-flowers-indoors</link>
                                                                            <description>
                            <![CDATA[ Cutting fresh flowers from your garden to bring indoors is a lovely task, but not if you're not doing it quite right. Here's 5 top tips for a seamless transfer from garden to vase. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">5CXAK4HoaUTZ28KhCwQSbH</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/urymG9Y4Pdk7SfbaxFjanA-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 17 Aug 2026 05:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gardening]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/urymG9Y4Pdk7SfbaxFjanA-1920-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Roses to cut from garden]]></media:description>                                                            <media:text><![CDATA[Roses to cut from garden]]></media:text>
                                <media:title type="plain"><![CDATA[Roses to cut from garden]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/urymG9Y4Pdk7SfbaxFjanA-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As the sunny weather brings out vibrant blooms and luscious leaves in my garden, I find myself fighting the urge to bring every single one of them indoors so I can enjoy them all day long. </p><p>Fortunately, I know that would be excessive, but that doesn't stop me from bringing <em>some</em> of them inside. Cutting fresh flowers from my garden and moving them into vases around my home is one of my favorite things to do in the summer. After all, why would I spend money on bouquets when I've got my own flower shop waiting in my garden?</p><p>But, I've learnt some hard lessons along the way, mainly when it comes to inviting bugs into my home riding the petals and stems of the flowers I want to enjoy. To avoid common mistakes, here's 5 top tips for bringing fresh flowers indoors.</p><h2 id="1-choose-the-right-time-of-day">1. Choose the right time of day</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1672px;"><p class="vanilla-image-block" style="padding-top:56.28%;"><img id="783t8a3fEEqvVwBG4eE2zg" name="Amanda Caswell's garden" alt="Amanda Caswell's Garden" src="https://cdn.mos.cms.futurecdn.net/783t8a3fEEqvVwBG4eE2zg-1920-80.png" mos="" align="middle" fullscreen="" width="1672" height="941" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>While you can cut fresh flowers from your garden at any time of day, there's definitely moments that are better than others. First thing in the morning or in the late evening are two of the best opportunities you have and there's a couple of reasons for that.</p><p>Firstly, you're doing it before it gets too hot or when the sun is cooling down. This way you're giving them a better chance of not wilting too quickly from the loss of water. </p><p>Secondly, insects aren't as active as these times of days so it's less likely that you'll be bringing them indoors.</p><h2 id="2-do-as-much-of-it-outside-as-possible">2. Do as much of it outside as possible</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:620px;"><p class="vanilla-image-block" style="padding-top:65.16%;"><img id="tPctm6bmxh3fLfKPv4oSaU" name="argos garden" alt="Argos Fixed Log Edging Regular - Pack Of 2" src="https://cdn.mos.cms.futurecdn.net/tPctm6bmxh3fLfKPv4oSaU-1920-80.jpg" mos="" align="middle" fullscreen="" width="620" height="404" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Argos)</span></figcaption></figure><p>When it comes to cutting fresh flowers, of course you'll be doing it outside at first, but you'll want to spend a bit more time out there then you might initially think. </p><p>This tip is a catch-all for the other tips I'm about to cover, too, meaning you should do pretty much all of the work outside. This will ensure you give any insects and pollen time to drop off in the best place – rather than inside your home.</p><h2 id="3-strip-the-lower-leaves-away">3. Strip the lower leaves away</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="GJnUW6XaPtP9QxiDcskv77" name="shutterstock_2011615187" alt="Cutting flower stem at an angle with a clean pair of pruning shears" src="https://cdn.mos.cms.futurecdn.net/GJnUW6XaPtP9QxiDcskv77-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>As you'd do with any shop-bought flowers, it's best to strip away the lower leaves from each stem. When you buy them, doing this avoids the leaves stagnating and rotting in the water. </p><p>When you're cutting them from your garden, this is also the case <em>but</em> with the added benefit of getting rid of any insect stragglers clinging on or any messy soil that could dirty up your home.</p><h2 id="4-give-them-a-good-shake">4. Give them a good shake</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3200px;"><p class="vanilla-image-block" style="padding-top:56.28%;"><img id="2hhK2vb3vKC8a72Fx5hq3g" name="shutterstock_2155781169 primrose flowers" alt="Flowers that love the rain primrose flowers" src="https://cdn.mos.cms.futurecdn.net/2hhK2vb3vKC8a72Fx5hq3g-1920-80.jpg" mos="" align="middle" fullscreen="" width="3200" height="1801" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>It's also a good idea to give your flowers a little shake, emphasis on the <em>little</em>. You don't want to destroy the flowers or risk shaking off the lovely petals, but you also want to give any insects the chance to jump ship.</p><p>It's best to do this with the flowers facing downwards as insects can easily hide inside the petals and leaves that are curled upwards.</p><h2 id="5-soak-them-in-cold-water">5. Soak them in cold water</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:59.60%;"><img id="BnM9Wsw62ueQqr3rjBdtDk" name="Daffodils in a vase of cold water" alt="Daffodils in a vase of cold water" src="https://cdn.mos.cms.futurecdn.net/BnM9Wsw62ueQqr3rjBdtDk-1920-80.jpg" mos="" align="middle" fullscreen="" width="1510" height="900" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>It's especially handy to have a bucket of cold water by your side when you're cutting your fresh flowers to soak them in. This will help give them a quick wash to remove any excess soil, insects, or anything else you don't want inside your home.</p><p>If you've had enough time outside, you can also put the bucket in your bathtub or even run some water into the bath to clean them for around 30 minutes before putting them in a vase. Then, you can enjoy your outdoor flowers without worrying about extra visitors in your home.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/outdoors/dont-throw-them-out-3-ways-to-use-banana-peels-in-the-garden">Don't throw them out — 3 ways to use banana peels in the garden</a></li><li><a href="https://www.tomsguide.com/home/outdoors/gardeners-urged-to-leave-a-bowl-of-beer-in-the-yard-this-summer-heres-why">Gardeners urged to leave a bowl of beer in the yard this summer — here's why</a></li><li><a href="https://www.tomsguide.com/how-to/how-to-get-rid-of-fruit-flies-fast">How to get rid of fruit flies fast</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ How often should you actually clean your shower head? My plumber husband reveals his top expert tips ]]></title>
                                                                                                <dc:content><![CDATA[ <p>I've always struggled with tasks around my home that require manual work. I'm much more of a writer than a do-er.</p><p>Fortunately, I married a plumber who's not only good at what he does, but he also has the mindset to fix almost anything around our home.</p><p>And while he might be fed up of me asking questions, I just can't stop. I've asked him to share his expert insight on <a href="https://www.tomsguide.com/home/my-husbands-a-plumber-and-these-are-the-3-expert-approved-tips-he-says-every-homeowner-should-know">3 costly mistakes you could be making</a> and he's given his advice on <a href="https://www.tomsguide.com/home/kitchen-dining/people-are-using-dish-soap-to-break-down-drain-blockages-i-asked-a-plumber-if-its-a-good-idea">whether dish soap can fix your clogged drain</a>, but there's plenty more to <em>tap</em> into. </p><p>Recently, after noticing the water wasn't coming out of our shower head as well as it used to, I asked him: "How often should you clean your shower head?" And he had some <em>very</em> interesting things to say about it. Here's his expert advice, shared without the  housecall fee.</p><h2 id="why-you-need-to-clean-your-shower-head">Why you need to clean your shower head</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2976px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="8e7Y4N9RYGdfxbfmxQu9cc" name="Clean.jpg" alt="Clean shower head" src="https://cdn.mos.cms.futurecdn.net/8e7Y4N9RYGdfxbfmxQu9cc-1920-80.jpg" mos="" align="middle" fullscreen="" width="2976" height="1674" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>As I mentioned, I felt compelled to ask this question when I noticed the shower head wasn't expelling water out of all the holes. Or, if it was, some of them were spraying in a totally different direction.</p><p>When I asked him why, he explained: "The waterways are small, so they get scaled up easily and water doesn’t come out.”</p><p>And, if they're only partially blocked with debris and built-up limescale, that can easily lead to the waterway not working at all, or spraying out incorrectly rather than straight down.</p><p>But, while I asked if it was a problem with the actual pressure, he said it was unlikely: "Pressure and flow rate are different. The pressure doesn’t fluctuate like the flow rate does. </p><p>"Pressure is the force of the water through the pipe and the flow rate is how much water comes out. If you’ve got a shower head with 100 holes but 50 of them are blocked, your pressure is still the same but your flow rate is half what it should be."</p><h2 id="how-often-should-you-clean-your-shower-head">How often should you clean your shower head</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5990px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="nQPgobL78wf6oSWiryT7Ge" name="Shower heads - crop.jpg" alt="Shower head in a modern bathroom dispensing water" src="https://cdn.mos.cms.futurecdn.net/nQPgobL78wf6oSWiryT7Ge-1920-80.jpg" mos="" align="middle" fullscreen="" width="5990" height="3369" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>With these things in mind, it was clear I needed to clean my shower head thoroughly. After all, it had been a while since I had. So, I asked him, how often should I be doing it? </p><p>He advised: "It depends on whether you live in a notoriously hard water area or not as that changes how often you should be cleaning it. If it’s a hard water area, do it more regularly. And if you notice it’s getting blocked up, that’s the best sign to clean it.”</p><p>This means the answer can range from every couple of weeks to more like every month or so, but generally if you notice it getting clogged up then it's definitely time to give it a clean.</p><p>My plumber husband recommends Viakal or a white vinegar and water solution (which he backed up when <a href="https://www.tomsguide.com/home/this-tiktok-hack-claims-vinegar-will-clean-your-shower-head-i-asked-my-plumber-husband-if-it-actually-works">I tried out this TikTok shower head cleaning hack</a>) to give your shower head a good clean.</p><p>But, that doesn't always mean the problem will be solved, he says: "If you’ve cleaned it and the flow rate is still poor, it could be scaled up inside and will need replacing."</p><div class="product"><a data-dimension112="91981cec-948b-11f1-b35b-f37ea9d69439" data-action="Deal Block" data-label="500ml Limescale Spray" data-dimension48="500ml Limescale Spray" data-dimension25="$9.99" href="https://www.amazon.com/Viakal-83194-Limescale-Spray-500g/dp/B004P1403S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="3RyjSuffd95yiUMUPPnfi6" name="viakal_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/3RyjSuffd95yiUMUPPnfi6-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Viakal-83194-Limescale-Spray-500g/dp/B004P1403S" target="_blank" rel="nofollow" data-dimension112="91981cec-948b-11f1-b35b-f37ea9d69439" data-action="Deal Block" data-label="500ml Limescale Spray" data-dimension48="500ml Limescale Spray" data-dimension25="$9.99">500ml Limescale Spray: was $13.75 now $9.99</a></strong><br />Viakal is a cleaner that specifically targets limescale. There's even a shower head on the packaging. If you've got some stubborn limescale on your shower head, leave it to soak for up to 5 minutes. If it's a regular clean, a simple spray and wipe away will work fine.<a class="view-deal button" href="https://www.amazon.com/Viakal-83194-Limescale-Spray-500g/dp/B004P1403S" target="_blank" rel="nofollow" data-dimension112="91981cec-948b-11f1-b35b-f37ea9d69439" data-action="Deal Block" data-label="500ml Limescale Spray" data-dimension48="500ml Limescale Spray" data-dimension25="$9.99">View Deal</a></p></div><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/this-tiktok-hack-claims-vinegar-will-clean-your-shower-head-i-asked-my-plumber-husband-if-it-actually-works">This TikTok hack claims vinegar will clean your shower head — I asked my plumber husband if it actually works</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/people-are-using-dish-soap-to-break-down-drain-blockages-i-asked-a-plumber-if-its-a-good-idea">You asked: Can dish soap fix your clogged drain? A plumber explains the facts</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/households-urged-not-to-pour-boiling-water-down-drains-this-winter-i-asked-a-plumber-what-to-do-instead">Households urged not to pour boiling water down drains this winter — I asked a plumber what to do instead</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/how-often-should-you-actually-clean-your-shower-head-my-plumber-husband-reveals-his-top-expert-tips</link>
                                                                            <description>
                            <![CDATA[ Cleaning your shower head feels like one of those chores you put off, but it definitely shouldn't be. Here's what my plumber husband had to say about how often you should be cleaning it and why. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">DV7CiMAQqTFapUmU2gfeuT</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/9ZT8MHLETGFdabnXPh7hac-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 15 Aug 2026 10:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/9ZT8MHLETGFdabnXPh7hac-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[limescale on shower head]]></media:description>                                                            <media:text><![CDATA[limescale on shower head]]></media:text>
                                <media:title type="plain"><![CDATA[limescale on shower head]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/9ZT8MHLETGFdabnXPh7hac-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I've always struggled with tasks around my home that require manual work. I'm much more of a writer than a do-er.</p><p>Fortunately, I married a plumber who's not only good at what he does, but he also has the mindset to fix almost anything around our home.</p><p>And while he might be fed up of me asking questions, I just can't stop. I've asked him to share his expert insight on <a href="https://www.tomsguide.com/home/my-husbands-a-plumber-and-these-are-the-3-expert-approved-tips-he-says-every-homeowner-should-know">3 costly mistakes you could be making</a> and he's given his advice on <a href="https://www.tomsguide.com/home/kitchen-dining/people-are-using-dish-soap-to-break-down-drain-blockages-i-asked-a-plumber-if-its-a-good-idea">whether dish soap can fix your clogged drain</a>, but there's plenty more to <em>tap</em> into. </p><p>Recently, after noticing the water wasn't coming out of our shower head as well as it used to, I asked him: "How often should you clean your shower head?" And he had some <em>very</em> interesting things to say about it. Here's his expert advice, shared without the  housecall fee.</p><h2 id="why-you-need-to-clean-your-shower-head">Why you need to clean your shower head</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2976px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="8e7Y4N9RYGdfxbfmxQu9cc" name="Clean.jpg" alt="Clean shower head" src="https://cdn.mos.cms.futurecdn.net/8e7Y4N9RYGdfxbfmxQu9cc-1920-80.jpg" mos="" align="middle" fullscreen="" width="2976" height="1674" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>As I mentioned, I felt compelled to ask this question when I noticed the shower head wasn't expelling water out of all the holes. Or, if it was, some of them were spraying in a totally different direction.</p><p>When I asked him why, he explained: "The waterways are small, so they get scaled up easily and water doesn’t come out.”</p><p>And, if they're only partially blocked with debris and built-up limescale, that can easily lead to the waterway not working at all, or spraying out incorrectly rather than straight down.</p><p>But, while I asked if it was a problem with the actual pressure, he said it was unlikely: "Pressure and flow rate are different. The pressure doesn’t fluctuate like the flow rate does. </p><p>"Pressure is the force of the water through the pipe and the flow rate is how much water comes out. If you’ve got a shower head with 100 holes but 50 of them are blocked, your pressure is still the same but your flow rate is half what it should be."</p><h2 id="how-often-should-you-clean-your-shower-head">How often should you clean your shower head</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5990px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="nQPgobL78wf6oSWiryT7Ge" name="Shower heads - crop.jpg" alt="Shower head in a modern bathroom dispensing water" src="https://cdn.mos.cms.futurecdn.net/nQPgobL78wf6oSWiryT7Ge-1920-80.jpg" mos="" align="middle" fullscreen="" width="5990" height="3369" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>With these things in mind, it was clear I needed to clean my shower head thoroughly. After all, it had been a while since I had. So, I asked him, how often should I be doing it? </p><p>He advised: "It depends on whether you live in a notoriously hard water area or not as that changes how often you should be cleaning it. If it’s a hard water area, do it more regularly. And if you notice it’s getting blocked up, that’s the best sign to clean it.”</p><p>This means the answer can range from every couple of weeks to more like every month or so, but generally if you notice it getting clogged up then it's definitely time to give it a clean.</p><p>My plumber husband recommends Viakal or a white vinegar and water solution (which he backed up when <a href="https://www.tomsguide.com/home/this-tiktok-hack-claims-vinegar-will-clean-your-shower-head-i-asked-my-plumber-husband-if-it-actually-works">I tried out this TikTok shower head cleaning hack</a>) to give your shower head a good clean.</p><p>But, that doesn't always mean the problem will be solved, he says: "If you’ve cleaned it and the flow rate is still poor, it could be scaled up inside and will need replacing."</p><div class="product"><a data-dimension112="91981cec-948b-11f1-b35b-f37ea9d69439" data-action="Deal Block" data-label="500ml Limescale Spray" data-dimension48="500ml Limescale Spray" data-dimension25="$9.99" href="https://www.amazon.com/Viakal-83194-Limescale-Spray-500g/dp/B004P1403S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="3RyjSuffd95yiUMUPPnfi6" name="viakal_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/3RyjSuffd95yiUMUPPnfi6-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Viakal-83194-Limescale-Spray-500g/dp/B004P1403S" target="_blank" rel="nofollow" data-dimension112="91981cec-948b-11f1-b35b-f37ea9d69439" data-action="Deal Block" data-label="500ml Limescale Spray" data-dimension48="500ml Limescale Spray" data-dimension25="$9.99">500ml Limescale Spray: was $13.75 now $9.99</a></strong><br />Viakal is a cleaner that specifically targets limescale. There's even a shower head on the packaging. If you've got some stubborn limescale on your shower head, leave it to soak for up to 5 minutes. If it's a regular clean, a simple spray and wipe away will work fine.<a class="view-deal button" href="https://www.amazon.com/Viakal-83194-Limescale-Spray-500g/dp/B004P1403S" target="_blank" rel="nofollow" data-dimension112="91981cec-948b-11f1-b35b-f37ea9d69439" data-action="Deal Block" data-label="500ml Limescale Spray" data-dimension48="500ml Limescale Spray" data-dimension25="$9.99">View Deal</a></p></div><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/this-tiktok-hack-claims-vinegar-will-clean-your-shower-head-i-asked-my-plumber-husband-if-it-actually-works">This TikTok hack claims vinegar will clean your shower head — I asked my plumber husband if it actually works</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/people-are-using-dish-soap-to-break-down-drain-blockages-i-asked-a-plumber-if-its-a-good-idea">You asked: Can dish soap fix your clogged drain? A plumber explains the facts</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/households-urged-not-to-pour-boiling-water-down-drains-this-winter-i-asked-a-plumber-what-to-do-instead">Households urged not to pour boiling water down drains this winter — I asked a plumber what to do instead</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ ‘Where other robot vacuums feel like a useful addition to the home, this one feels like a necessity’ — this review is a love letter to the Dreame X60 Max Ultra Complete ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Looking for the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuum</a>? Don’t worry, I found it. It’s the Dreame X60 Max Ultra Complete. I’ve been seriously blown away by this robovac’s impressive vacuuming and mopping capabilities. </p><p>It has some of the best features I’ve ever used on a robot vacuum, including extendable mop arms and a side sweeper, climbing technology, plus onboard cameras for enhanced object detection and even pet photography. </p><p>My only qualm would be the large size of the base station, which may be problematic if you’re short on space. But to find out more about why I love this fantastic robot vacuum, you can keep reading this full Dreame X60 Max Ultra Complete review. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-specs"><span>Dreame X60 Max Ultra Complete review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/DREAME-Ultra-Thin-Refilling-Self-Cleaning-Avoidance/dp/B0GF7FJJDN" target="_blank" rel="nofollow">$1,699</a> / <a href="https://www.amazon.co.uk/dreame-Ultra-Complete-Vacuum-UltraExtend/dp/B0H4RQ2BK9" target="_blank" rel="nofollow">£1,299</a> </p></td></tr><tr><td class="firstcol " ><p><strong>Robot dimensions</strong></p></td><td  ><p>13.8 x 13.8 x 3.5 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Dock dimensions</strong></p></td><td  ><p>15.7 x 18.0 x 15.4 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Robot weight</strong></p></td><td  ><p>10.4 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Base weight</strong></p></td><td  ><p>23.4 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Maximum suction power</strong></p></td><td  ><p>42000Pa</p></td></tr><tr><td class="firstcol " ><p><strong>Mapping</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Mop function</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Self-emptying</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Self-cleaning/drying</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Onboard dust bin capacity</strong></p></td><td  ><p>310ml</p></td></tr><tr><td class="firstcol " ><p><strong>Dock dust bin capacity</strong></p></td><td  ><p>3.2L</p></td></tr><tr><td class="firstcol " ><p><strong>Onboard water tank capacity</strong></p></td><td  ><p>80ml</p></td></tr><tr><td class="firstcol " ><p><strong>Dock water tank capacity</strong></p></td><td  ><p>4.2L</p></td></tr><tr><td class="firstcol " ><p><strong>App</strong></p></td><td  ><p>DreameHome</p></td></tr><tr><td class="firstcol " ><p><strong>Battery</strong></p></td><td  ><p>5000mAh</p></td></tr><tr><td class="firstcol " ><p><strong>Runtime</strong></p></td><td  ><p>242 minutes</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-price-availability"><span>Dreame X60 Max Ultra Complete review: Price &amp; availability</span></h2><p>The Dreame X60 Max Ultra Complete is available for <a href="https://www.amazon.com/DREAME-Ultra-Thin-Refilling-Self-Cleaning-Avoidance/dp/B0GF7FJJDN" target="_blank" rel="nofollow">$1,699 from Amazon U.S.</a> or for <a href="https://www.amazon.co.uk/dreame-Ultra-Complete-Vacuum-UltraExtend/dp/B0H4RQ2BK9" target="_blank" rel="nofollow">£1,299 from Amazon U.K.</a>, where it’s called the Dreame X60 Pro Ultra Complete. You can pick up this vacuum in Black or White. This is the most expensive robot vacuum cleaner you can buy from Dreame, as it’s the flagship model with the most advanced features. </p><p>I’ve also tested a few other robot vacuums from Dreame, including the <a href="https://www.tomsguide.com/home/dreame-d10-plus-gen-2-review">D10 Plus Gen 2</a>, which is much cheaper at $299, but still offers impressive performance. </p><p>In the same price range as the X60 Max, the <a href="https://www.tomsguide.com/home/home-appliances/roborock-saros-20-review">Roborock Saros 20</a> costs $1,599 and leaves floors absolutely spotless. For ease of use, I’d recommend the Saros 20, but the X60 Max offers more premium features. </p><p>If you’re looking for something a bit smaller than the X60 Max and the Saros 20, consider the <a href="https://www.tomsguide.com/home/roborock-qrevo-curv-review">Roborock Qrevo Curv</a>, priced at $1,799, which features smart home compatibility and high suction power.</p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-design"><span>Dreame X60 Max Ultra Complete review: Design </span></h2><p>The X60 Max has the most futuristic look of any robot vacuum I’ve tested — and I’ve tested a lot. The docking station is large, but that’s a testament to its power. It measures 15.7 x 18.0 x 15.4 inches and weighs 23.4 pounds. It can automatically fill the robot’s water, empty it, and auto-empty the dust collection bin. It also washes the mops after use and dries them with hot air afterwards. </p><p>There are many robot vacuums out there with base stations that can take care of themselves. But these are premium models, including the Roborock Saros 20 and the <a href="https://www.tomsguide.com/home/home-appliances/shark-powerdetect-2-in-1-thermacharged-nevertouch-review">Shark PowerDetect 2-in-1 ThermaCharged NeverTouch</a> ($1,199), so you’ll always be paying a premium price for such features. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="u9xYe7LkU2NZ8tE7T7VBve" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/u9xYe7LkU2NZ8tE7T7VBve-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The X60 Max’s vacuum measures 13.8 x 13.8 x 3.5 inches and weighs 10.4 pounds, which is around the same as most other robot vacuums on the market. </p><p>The robot has a detangling rotating brush and two circular mop pads at the back, which clean using hot water. Much like other robovacs, the Dreame has a side-sweeping brush. But it stands out from the crowd because it can extend to 12cm and get into hard-to-reach places. The mop pads also extend to 18cm to hit corners with ease. This is the most thorough mopping I’ve achieved with a robovac. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="bVkJxU3muZVyYBy2G263ae" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/bVkJxU3muZVyYBy2G263ae-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>It also has small wheels that extend underneath to lift it over obstacles. These include stairs or other immovable objects up to 10cm. This was impressive to witness in action. </p><p>The vacuum also comes with a small brush. At first, I thought this was to clean the robot vacuum — I pictured Monica in Friends, when she cleans her large vacuum with a handheld one. But alas, I was wrong: it’s for something far cooler. This small brush attaches to the vacuum’s arm to clean baseboards as it moves around the edges of the room. So I no longer have to follow up vacuuming with dusting. A real win. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-app"><span>Dreame X60 Max Ultra Complete review: App</span></h2><p>I’ve said it before, but I’ll say it again: the DreameHome app is one of my favorites. When you initially set up the device, you get a walkthrough of all the functions — and this vacuum has<em> a lot</em>. But everything felt digestible, and it didn’t overwhelm me at all. With help from the app, this feels like an accessible robot vacuum for all experience levels. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="TBQhuYiGZsAKCVdhZpfLfe" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/TBQhuYiGZsAKCVdhZpfLfe-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>From the app, you can control cleaning routines, patterns, suction power and water flow. Mapping is also set up within the app, and it’s easy to manage rooms by naming them, plus you can have multiple maps for different floors in your house. </p><p>The app is free to download from the App Store on Android or iOS. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-mapping"><span>Dreame X60 Max Ultra Complete review: Mapping </span></h2><p>Mapping on the X60 Max is very efficient. When setting up the vacuum, I chose the quick mapping option, and it took 10 minutes to draw up detailed maps of my home. This was easy and virtually silent. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="B4J5ZGbCvPG4ursUm7bFgf" name="Dreame app" alt="Screenshots from the Dreame app when using the Dreame X60 Max Ultra Complete" src="https://cdn.mos.cms.futurecdn.net/B4J5ZGbCvPG4ursUm7bFgf-1920-80.jpg" mos="" align="middle" fullscreen="" width="1510" height="850" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Dreame)</span></figcaption></figure><p>I also like the mapping technology you get with Roborock devices, but the Dreame app is more user-friendly. </p><p>The Dreame robot uses ultrasonic technology to map the room and could even identify what type of flooring is in each room. This meant it knew where to mop and where to only vacuum, so I didn’t have to set zones manually. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="tutAUTVuEB2QNvechhhCDe" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/tutAUTVuEB2QNvechhhCDe-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Object detection and avoidance are also impressive. The X60 has a bumper but also uses dual 120º AI cameras to map its surroundings. You can also use the robot vacuum for video calls to check on your pets while you’re away, and it will automatically capture pictures of your pets while cleaning. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-cleaning"><span>Dreame X60 Max Ultra Complete review: Cleaning</span></h2><p>The Dreame X60 Max Ultra Complete performed best on hard floors, but I was very impressed with its performance on carpet too. It has a maximum suction power of 42,000Pa, which is very impressive. For example, the Roborock Saros 20 has a suction power of 36,000Pa. However, it’s worth noting that the 42,000Pa suction power of the Dreame is only active when you manually select the highest suction in the app. </p><h3 id="vacuuming-2">Vacuuming</h3><p>I tested the vacuuming capabilities of the Dreame X60 Max Ultra Complete using our standardized lab testing criteria before testing at home. I was very impressed with its performance throughout — a testament to the 42,000Pa suction power.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="4WAkeycxPovYThdM6trsue" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/4WAkeycxPovYThdM6trsue-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p><strong>Hardwood floor:</strong></p><p>The Dreame X60 Max Ultra Complete managed to pick up everything I threw at it. From hair to tiny seeds, the powerful suction proved that this vacuum really is worth the price tag. </p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Dustbin weight before</strong></p></td><td  ><p><strong>Dustbin weight after</strong></p></td><td  ><p><strong>Percentage of debris picked up</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Hair (5g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>35.4g</p></td><td  ><p>100%</p></td></tr><tr><td class="firstcol " ><p><strong>Rice Krispies (20g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>50.4g</p></td><td  ><p>100%</p></td></tr><tr><td class="firstcol " ><p><strong>Flax seeds (20g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>50.4g</p></td><td  ><p>100%</p></td></tr></tbody></table></div><p>I think the reason the vacuum was able to get every last bit of debris was the extendable sweeper arm, which made sure everything was rounded up from the edges of the room. </p><p><strong>Carpet:</strong></p><p>It even performs well on carpeted flooring. It suffered a very small reduction in performance with hair and larger debris, as is to be expected on carpet, but it still makes them look clean. </p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Dustbin weight before</strong></p></td><td  ><p><strong>Dustbin weight after</strong></p></td><td  ><p><strong>Percentage of debris picked up</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Hair (5g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>35.2g</p></td><td  ><p>96%</p></td></tr><tr><td class="firstcol " ><p><strong>Rice Krispies (20g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>50.1g</p></td><td  ><p>98.5%</p></td></tr><tr><td class="firstcol " ><p><strong>Flax seeds (20g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>50.4g</p></td><td  ><p>100%</p></td></tr></tbody></table></div><p>I was mostly impressed by how well it performed when picking up hair. When I tested the Dreame D10 Plus Gen 2, it only picked up 40% of the hair from the carpet; it’s well worth splurging on the flagship X60 if you have pets who shed a lot of fur.</p><h3 id="mopping-2">Mopping</h3><p>To test the mopping capabilities of the robovac, I put soy sauce, mayonnaise and some mud on the floor and left them to dry. The Dreame X60 Max Ultra Complete did an excellent job. I couldn’t see any mess left on the floor, and when I touched the floor, there wasn’t any sort of sticky feeling that some mopping vacuums can leave behind. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="RUNHrworx3VuXxgi6UQA3f" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/RUNHrworx3VuXxgi6UQA3f-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The combination of the Dreame multisurface cleaner and the 104ºF water does a great job of cleaning the floor. Using hot water to clean kills more bacteria and makes it a lot easier for the mops to lift grime from the floor.</p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-storage-maintenance"><span>Dreame X60 Max Ultra Complete review: Storage &amp; maintenance</span></h2><p>Since the base station of the Dreame X60 Max Ultra Complete is on the larger side, you need somewhere for the vacuum to dock that won’t cause a hindrance in your home. But it also needs to be near a power outlet, since the cord is only 3.9 feet long. This wasn’t an issue for me, but if you don’t have an outlet nearby, it will be tricky to set up the vacuum.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.30%;"><img id="xizK9bhQJ9tYAn8XDimP7e" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/xizK9bhQJ9tYAn8XDimP7e-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1126" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The X60 is very easy to maintain and can look after itself with self-emptying, cleaning, and drying for up to 100 days, depending on usage. The top of the base station lifts to reveal a clean and dirty water tank, and the bottom front panel can be removed to reveal the dust bag along with a small pot for detergent. It’s very easy to change the water and refill the detergent, so upkeep was a breeze. The bag is also easy to swap out with a few clicks.</p><p>On the robot vacuum, the anti-tangle brush worked well, and I didn’t have to manually clean off any hair from the rotary brush. It’s easy to change the mop pads just by clicking them into place. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="X6WsZ3ZrE9LvkW5cyghqKe" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/X6WsZ3ZrE9LvkW5cyghqKe-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The robot vacuum comes with replacement parts, including a rotary brush, sweepers and mops so you can keep the X60 Max looking brand new. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-verdict"><span>Dreame X60 Max Ultra Complete review: Verdict</span></h2><p>The Dreame X60 Max Ultra Complete has become my new gold standard when it comes to robot vacuums. It provides exceptional vacuum performance and impressive mopping skills that can be modified in the user-friendly app to suit your home’s daily needs and schedule. </p><p>The smart features on the robot, like the built-in camera, enhanced object detection, extendable arms, and heated water mopping, make this a worthwhile purchase for anyone who needs an extra pair of hands around the house. My only issue is that the dock is on the larger side, but the size supports up to 100 days of self-maintenance, so it’s a good trade-off. </p><p>Where other robot vacuums feel like a useful addition to the home, this one feels like a necessity. </p> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/dreame-x60-max-ultra-complete-review</link>
                                                                            <description>
                            <![CDATA[ The Dreame X60 Max Ultra Complete is the robot vacuum by which all others must be measured. Yes. It’s that good. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Dhf2mD3VTja2wXWN8anpYB</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/G2RA52Tmfk3LBzFahCVUae-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 14 Aug 2026 15:07:01 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/G2RA52Tmfk3LBzFahCVUae-1920-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Dreame X60 Max Ultra Complete in white photographed on gray carpet.]]></media:description>                                                            <media:text><![CDATA[Dreame X60 Max Ultra Complete in white photographed on gray carpet.]]></media:text>
                                <media:title type="plain"><![CDATA[Dreame X60 Max Ultra Complete in white photographed on gray carpet.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/G2RA52Tmfk3LBzFahCVUae-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Looking for the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuum</a>? Don’t worry, I found it. It’s the Dreame X60 Max Ultra Complete. I’ve been seriously blown away by this robovac’s impressive vacuuming and mopping capabilities. </p><p>It has some of the best features I’ve ever used on a robot vacuum, including extendable mop arms and a side sweeper, climbing technology, plus onboard cameras for enhanced object detection and even pet photography. </p><p>My only qualm would be the large size of the base station, which may be problematic if you’re short on space. But to find out more about why I love this fantastic robot vacuum, you can keep reading this full Dreame X60 Max Ultra Complete review. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-specs"><span>Dreame X60 Max Ultra Complete review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/DREAME-Ultra-Thin-Refilling-Self-Cleaning-Avoidance/dp/B0GF7FJJDN" target="_blank" rel="nofollow">$1,699</a> / <a href="https://www.amazon.co.uk/dreame-Ultra-Complete-Vacuum-UltraExtend/dp/B0H4RQ2BK9" target="_blank" rel="nofollow">£1,299</a> </p></td></tr><tr><td class="firstcol " ><p><strong>Robot dimensions</strong></p></td><td  ><p>13.8 x 13.8 x 3.5 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Dock dimensions</strong></p></td><td  ><p>15.7 x 18.0 x 15.4 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Robot weight</strong></p></td><td  ><p>10.4 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Base weight</strong></p></td><td  ><p>23.4 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Maximum suction power</strong></p></td><td  ><p>42000Pa</p></td></tr><tr><td class="firstcol " ><p><strong>Mapping</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Mop function</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Self-emptying</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Self-cleaning/drying</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Onboard dust bin capacity</strong></p></td><td  ><p>310ml</p></td></tr><tr><td class="firstcol " ><p><strong>Dock dust bin capacity</strong></p></td><td  ><p>3.2L</p></td></tr><tr><td class="firstcol " ><p><strong>Onboard water tank capacity</strong></p></td><td  ><p>80ml</p></td></tr><tr><td class="firstcol " ><p><strong>Dock water tank capacity</strong></p></td><td  ><p>4.2L</p></td></tr><tr><td class="firstcol " ><p><strong>App</strong></p></td><td  ><p>DreameHome</p></td></tr><tr><td class="firstcol " ><p><strong>Battery</strong></p></td><td  ><p>5000mAh</p></td></tr><tr><td class="firstcol " ><p><strong>Runtime</strong></p></td><td  ><p>242 minutes</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-price-availability"><span>Dreame X60 Max Ultra Complete review: Price &amp; availability</span></h2><p>The Dreame X60 Max Ultra Complete is available for <a href="https://www.amazon.com/DREAME-Ultra-Thin-Refilling-Self-Cleaning-Avoidance/dp/B0GF7FJJDN" target="_blank" rel="nofollow">$1,699 from Amazon U.S.</a> or for <a href="https://www.amazon.co.uk/dreame-Ultra-Complete-Vacuum-UltraExtend/dp/B0H4RQ2BK9" target="_blank" rel="nofollow">£1,299 from Amazon U.K.</a>, where it’s called the Dreame X60 Pro Ultra Complete. You can pick up this vacuum in Black or White. This is the most expensive robot vacuum cleaner you can buy from Dreame, as it’s the flagship model with the most advanced features. </p><p>I’ve also tested a few other robot vacuums from Dreame, including the <a href="https://www.tomsguide.com/home/dreame-d10-plus-gen-2-review">D10 Plus Gen 2</a>, which is much cheaper at $299, but still offers impressive performance. </p><p>In the same price range as the X60 Max, the <a href="https://www.tomsguide.com/home/home-appliances/roborock-saros-20-review">Roborock Saros 20</a> costs $1,599 and leaves floors absolutely spotless. For ease of use, I’d recommend the Saros 20, but the X60 Max offers more premium features. </p><p>If you’re looking for something a bit smaller than the X60 Max and the Saros 20, consider the <a href="https://www.tomsguide.com/home/roborock-qrevo-curv-review">Roborock Qrevo Curv</a>, priced at $1,799, which features smart home compatibility and high suction power.</p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-design"><span>Dreame X60 Max Ultra Complete review: Design </span></h2><p>The X60 Max has the most futuristic look of any robot vacuum I’ve tested — and I’ve tested a lot. The docking station is large, but that’s a testament to its power. It measures 15.7 x 18.0 x 15.4 inches and weighs 23.4 pounds. It can automatically fill the robot’s water, empty it, and auto-empty the dust collection bin. It also washes the mops after use and dries them with hot air afterwards. </p><p>There are many robot vacuums out there with base stations that can take care of themselves. But these are premium models, including the Roborock Saros 20 and the <a href="https://www.tomsguide.com/home/home-appliances/shark-powerdetect-2-in-1-thermacharged-nevertouch-review">Shark PowerDetect 2-in-1 ThermaCharged NeverTouch</a> ($1,199), so you’ll always be paying a premium price for such features. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="u9xYe7LkU2NZ8tE7T7VBve" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/u9xYe7LkU2NZ8tE7T7VBve-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The X60 Max’s vacuum measures 13.8 x 13.8 x 3.5 inches and weighs 10.4 pounds, which is around the same as most other robot vacuums on the market. </p><p>The robot has a detangling rotating brush and two circular mop pads at the back, which clean using hot water. Much like other robovacs, the Dreame has a side-sweeping brush. But it stands out from the crowd because it can extend to 12cm and get into hard-to-reach places. The mop pads also extend to 18cm to hit corners with ease. This is the most thorough mopping I’ve achieved with a robovac. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="bVkJxU3muZVyYBy2G263ae" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/bVkJxU3muZVyYBy2G263ae-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>It also has small wheels that extend underneath to lift it over obstacles. These include stairs or other immovable objects up to 10cm. This was impressive to witness in action. </p><p>The vacuum also comes with a small brush. At first, I thought this was to clean the robot vacuum — I pictured Monica in Friends, when she cleans her large vacuum with a handheld one. But alas, I was wrong: it’s for something far cooler. This small brush attaches to the vacuum’s arm to clean baseboards as it moves around the edges of the room. So I no longer have to follow up vacuuming with dusting. A real win. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-app"><span>Dreame X60 Max Ultra Complete review: App</span></h2><p>I’ve said it before, but I’ll say it again: the DreameHome app is one of my favorites. When you initially set up the device, you get a walkthrough of all the functions — and this vacuum has<em> a lot</em>. But everything felt digestible, and it didn’t overwhelm me at all. With help from the app, this feels like an accessible robot vacuum for all experience levels. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="TBQhuYiGZsAKCVdhZpfLfe" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/TBQhuYiGZsAKCVdhZpfLfe-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>From the app, you can control cleaning routines, patterns, suction power and water flow. Mapping is also set up within the app, and it’s easy to manage rooms by naming them, plus you can have multiple maps for different floors in your house. </p><p>The app is free to download from the App Store on Android or iOS. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-mapping"><span>Dreame X60 Max Ultra Complete review: Mapping </span></h2><p>Mapping on the X60 Max is very efficient. When setting up the vacuum, I chose the quick mapping option, and it took 10 minutes to draw up detailed maps of my home. This was easy and virtually silent. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="B4J5ZGbCvPG4ursUm7bFgf" name="Dreame app" alt="Screenshots from the Dreame app when using the Dreame X60 Max Ultra Complete" src="https://cdn.mos.cms.futurecdn.net/B4J5ZGbCvPG4ursUm7bFgf-1920-80.jpg" mos="" align="middle" fullscreen="" width="1510" height="850" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Dreame)</span></figcaption></figure><p>I also like the mapping technology you get with Roborock devices, but the Dreame app is more user-friendly. </p><p>The Dreame robot uses ultrasonic technology to map the room and could even identify what type of flooring is in each room. This meant it knew where to mop and where to only vacuum, so I didn’t have to set zones manually. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="tutAUTVuEB2QNvechhhCDe" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/tutAUTVuEB2QNvechhhCDe-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Object detection and avoidance are also impressive. The X60 has a bumper but also uses dual 120º AI cameras to map its surroundings. You can also use the robot vacuum for video calls to check on your pets while you’re away, and it will automatically capture pictures of your pets while cleaning. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-cleaning"><span>Dreame X60 Max Ultra Complete review: Cleaning</span></h2><p>The Dreame X60 Max Ultra Complete performed best on hard floors, but I was very impressed with its performance on carpet too. It has a maximum suction power of 42,000Pa, which is very impressive. For example, the Roborock Saros 20 has a suction power of 36,000Pa. However, it’s worth noting that the 42,000Pa suction power of the Dreame is only active when you manually select the highest suction in the app. </p><h3 id="vacuuming-2">Vacuuming</h3><p>I tested the vacuuming capabilities of the Dreame X60 Max Ultra Complete using our standardized lab testing criteria before testing at home. I was very impressed with its performance throughout — a testament to the 42,000Pa suction power.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="4WAkeycxPovYThdM6trsue" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/4WAkeycxPovYThdM6trsue-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p><strong>Hardwood floor:</strong></p><p>The Dreame X60 Max Ultra Complete managed to pick up everything I threw at it. From hair to tiny seeds, the powerful suction proved that this vacuum really is worth the price tag. </p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Dustbin weight before</strong></p></td><td  ><p><strong>Dustbin weight after</strong></p></td><td  ><p><strong>Percentage of debris picked up</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Hair (5g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>35.4g</p></td><td  ><p>100%</p></td></tr><tr><td class="firstcol " ><p><strong>Rice Krispies (20g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>50.4g</p></td><td  ><p>100%</p></td></tr><tr><td class="firstcol " ><p><strong>Flax seeds (20g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>50.4g</p></td><td  ><p>100%</p></td></tr></tbody></table></div><p>I think the reason the vacuum was able to get every last bit of debris was the extendable sweeper arm, which made sure everything was rounded up from the edges of the room. </p><p><strong>Carpet:</strong></p><p>It even performs well on carpeted flooring. It suffered a very small reduction in performance with hair and larger debris, as is to be expected on carpet, but it still makes them look clean. </p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Dustbin weight before</strong></p></td><td  ><p><strong>Dustbin weight after</strong></p></td><td  ><p><strong>Percentage of debris picked up</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Hair (5g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>35.2g</p></td><td  ><p>96%</p></td></tr><tr><td class="firstcol " ><p><strong>Rice Krispies (20g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>50.1g</p></td><td  ><p>98.5%</p></td></tr><tr><td class="firstcol " ><p><strong>Flax seeds (20g)</strong></p></td><td  ><p>30.4g</p></td><td  ><p>50.4g</p></td><td  ><p>100%</p></td></tr></tbody></table></div><p>I was mostly impressed by how well it performed when picking up hair. When I tested the Dreame D10 Plus Gen 2, it only picked up 40% of the hair from the carpet; it’s well worth splurging on the flagship X60 if you have pets who shed a lot of fur.</p><h3 id="mopping-2">Mopping</h3><p>To test the mopping capabilities of the robovac, I put soy sauce, mayonnaise and some mud on the floor and left them to dry. The Dreame X60 Max Ultra Complete did an excellent job. I couldn’t see any mess left on the floor, and when I touched the floor, there wasn’t any sort of sticky feeling that some mopping vacuums can leave behind. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="RUNHrworx3VuXxgi6UQA3f" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/RUNHrworx3VuXxgi6UQA3f-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The combination of the Dreame multisurface cleaner and the 104ºF water does a great job of cleaning the floor. Using hot water to clean kills more bacteria and makes it a lot easier for the mops to lift grime from the floor.</p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-storage-maintenance"><span>Dreame X60 Max Ultra Complete review: Storage &amp; maintenance</span></h2><p>Since the base station of the Dreame X60 Max Ultra Complete is on the larger side, you need somewhere for the vacuum to dock that won’t cause a hindrance in your home. But it also needs to be near a power outlet, since the cord is only 3.9 feet long. This wasn’t an issue for me, but if you don’t have an outlet nearby, it will be tricky to set up the vacuum.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.30%;"><img id="xizK9bhQJ9tYAn8XDimP7e" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/xizK9bhQJ9tYAn8XDimP7e-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1126" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The X60 is very easy to maintain and can look after itself with self-emptying, cleaning, and drying for up to 100 days, depending on usage. The top of the base station lifts to reveal a clean and dirty water tank, and the bottom front panel can be removed to reveal the dust bag along with a small pot for detergent. It’s very easy to change the water and refill the detergent, so upkeep was a breeze. The bag is also easy to swap out with a few clicks.</p><p>On the robot vacuum, the anti-tangle brush worked well, and I didn’t have to manually clean off any hair from the rotary brush. It’s easy to change the mop pads just by clicking them into place. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="X6WsZ3ZrE9LvkW5cyghqKe" name="Dreame X60 Max Ultra Complete" alt="Dreame X60 Max Ultra Complete in white photographed on gray carpet." src="https://cdn.mos.cms.futurecdn.net/X6WsZ3ZrE9LvkW5cyghqKe-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The robot vacuum comes with replacement parts, including a rotary brush, sweepers and mops so you can keep the X60 Max looking brand new. </p><h2 class="article-body__section" id="section-dreame-x60-max-ultra-complete-review-verdict"><span>Dreame X60 Max Ultra Complete review: Verdict</span></h2><p>The Dreame X60 Max Ultra Complete has become my new gold standard when it comes to robot vacuums. It provides exceptional vacuum performance and impressive mopping skills that can be modified in the user-friendly app to suit your home’s daily needs and schedule. </p><p>The smart features on the robot, like the built-in camera, enhanced object detection, extendable arms, and heated water mopping, make this a worthwhile purchase for anyone who needs an extra pair of hands around the house. My only issue is that the dock is on the larger side, but the size supports up to 100 days of self-maintenance, so it’s a good trade-off. </p><p>Where other robot vacuums feel like a useful addition to the home, this one feels like a necessity. </p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The two common household products you should never use to clean your patio — according to an expert ]]></title>
                                                                                                <dc:content><![CDATA[ <p>During summer, our outdoor areas get a lot more use. And while it's wonderful to be enjoying the patio area with friends and family, I know my patio has started to get a little messy. While I cleaned it up in spring, it's desperately asking me to give it another good scrub. But, it turns out, I may have made a common mistake before that I definitely want to avoid.</p><p>While I followed <a href="https://www.tomsguide.com/how-to/how-to-clean-your-patio-without-a-pressure-washer">7 simple steps to cleaning my patio without a pressure washer</a>, I then grabbed a household item that, according to an expert, I should be avoiding. </p><p>And it turns out there's another item on the 'no-no' list that I should steer clear of too. Here are the patio cleaning mistakes you can avoid this summer when it's time to clean up dirt, spills, and general wear, thanks to expert advice.</p><h2 id="avoid-these-two-household-items">Avoid these two household items</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4920px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="sMd8gCbGmyEvMxzfUpq5PZ" name="White vinegar - crop.jpg" alt="White vinegar" src="https://cdn.mos.cms.futurecdn.net/sMd8gCbGmyEvMxzfUpq5PZ-1920-80.jpg" mos="" align="middle" fullscreen="" width="4920" height="2768" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Morgan Smith, director at porcelain garden tiles company <a href="https://www.pegseostone.co.uk/external-porcelain/porcelain-paving/" target="_blank">Pegseo Stone</a>, has advised there are two common products that people use when cleaning the patio that shouldn't be – white vinegar and bleach. While I use white vinegar for <a href="https://www.tomsguide.com/home/this-zero-effort-vinegar-hack-is-a-total-game-changer-for-cleaning-your-microwave">'zero-effort' hacks like cleaning my microwave</a>, it turns out the patio is one place I shouldn't take it.</p><p>Smith says: "White vinegar is highly acidic, so using it on certain patio materials can damage the surface itself rather than simply removing dirt." These certain materials include limestone and other calcareous pavers.</p><p>But, you should also be careful that you're not causing harm to any grass or flowerbeds nearby, Smith adds: "Any vinegar that runs into nearby borders can also damage grass and plants, meaning it can harm both the patio and the surrounding garden."</p><p>The same applies for bleach. As Smith explains, while it may give you a visual improvement, over time it can cause "lasting surface damage and further maintenance costs."</p><p>So, next time you head out to clean your patio, think before grabbing the white vinegar or bleach.</p><h2 id="what-to-use-instead">What to use instead</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="iZUM4Tsn4qFvMkCejPHxHG" name="patio-deck-feature.jpg" alt="Patio Furniture" src="https://cdn.mos.cms.futurecdn.net/iZUM4Tsn4qFvMkCejPHxHG-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Fortunately, there's an even simpler household item that you can use that shouldn't cause any damage to your patio – and that's an easy soap and water solution.</p><p>"Using warm water and soap is an effective option for general patio cleaning, particularly when used with a hard-bristled brush," Smith advises. "Start cleaning from the corners of the paving and move gradually inwards, allowing each section to be scrubbed and rinsed before moving on."</p><p>You'll want to opt for a soap that's eco-friendly though, meaning it avoids harmful chemicals to any flora, fauna and wildlife nearby.</p><div class="product"><a data-dimension112="e793b3e2-90b0-11f1-990b-554a576ccd9c" data-action="Deal Block" data-label="Stainless Steel Wire Scrub Brush" data-dimension48="Stainless Steel Wire Scrub Brush" data-dimension25="$19.99" href="https://www.amazon.com/Stainless-Concrete-Cleaning-Bristle-Scrubber/dp/B0D7BJG92R" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="24iCUUuKPnigxXseFNLLdS" name="scrub_brush_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/24iCUUuKPnigxXseFNLLdS-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Stainless-Concrete-Cleaning-Bristle-Scrubber/dp/B0D7BJG92R" target="_blank" rel="nofollow" data-dimension112="e793b3e2-90b0-11f1-990b-554a576ccd9c" data-action="Deal Block" data-label="Stainless Steel Wire Scrub Brush" data-dimension48="Stainless Steel Wire Scrub Brush" data-dimension25="$19.99">Stainless Steel Wire Scrub Brush: $19.99</a></strong><br />This heavy duty brush is perfect for patio cleaning, equipped with a long handle and steel wire bristles to work on durable hard surfaces. Extendable up to 59-inches, you can scrub away without having to keep bending over.<a class="view-deal button" href="https://www.amazon.com/Stainless-Concrete-Cleaning-Bristle-Scrubber/dp/B0D7BJG92R" target="_blank" rel="nofollow" data-dimension112="e793b3e2-90b0-11f1-990b-554a576ccd9c" data-action="Deal Block" data-label="Stainless Steel Wire Scrub Brush" data-dimension48="Stainless Steel Wire Scrub Brush" data-dimension25="$19.99">View Deal</a></p></div><p>Plus, if you're lucky enough to have a pressure washer handy, Smith says it's important to watch how forcefully you wash, advising: "too much force can damage the surface of the pavers."</p><p>Instead, Smith suggests sticking to a low-pressure setting and angling the pressure washer nozzle at 30-degrees, rather than pointing it directly at the pavers.</p><p>And one final tip is is to check the joints between each slab once you've done your cleaning: "Areas that have lost sand or pointing should be repaired to keep the paving secure and limit further deterioration."</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/outdoors/im-cleaning-my-patio-furniture-with-this-non-toxic-ingredient-and-it-also-works-wonders-on-your-grill">I'm cleaning my patio furniture with this non-toxic ingredient — and it also works wonders on your grill</a></li><li><a href="https://www.tomsguide.com/home/gardening/forget-power-washing-5-budget-friendly-hacks-to-get-your-backyard-sparkling-this-spring">Forget power washing: 5 budget-friendly hacks to get your backyard sparkling this spring</a></li><li><a href="https://www.tomsguide.com/home/5-tips-to-keep-your-deck-looking-great-all-summer">5 tips to keep your deck looking great all summer</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/outdoors/the-two-common-household-products-you-should-never-use-to-clean-your-patio-according-to-an-expert</link>
                                                                            <description>
                            <![CDATA[ Cleaning your patio this summer? You might want to think twice about what household items you're grabbing to do the job as you could be causing more harm than good. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">CgJW4QKemtR5T4PcjTJgDj</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/TpryphE45tZCEgsCN8RKZk-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 10 Aug 2026 05:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Outdoors]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/TpryphE45tZCEgsCN8RKZk-1920-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Spraying vinegar outside a front door ]]></media:description>                                                            <media:text><![CDATA[Spraying vinegar outside a front door ]]></media:text>
                                <media:title type="plain"><![CDATA[Spraying vinegar outside a front door ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/TpryphE45tZCEgsCN8RKZk-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>During summer, our outdoor areas get a lot more use. And while it's wonderful to be enjoying the patio area with friends and family, I know my patio has started to get a little messy. While I cleaned it up in spring, it's desperately asking me to give it another good scrub. But, it turns out, I may have made a common mistake before that I definitely want to avoid.</p><p>While I followed <a href="https://www.tomsguide.com/how-to/how-to-clean-your-patio-without-a-pressure-washer">7 simple steps to cleaning my patio without a pressure washer</a>, I then grabbed a household item that, according to an expert, I should be avoiding. </p><p>And it turns out there's another item on the 'no-no' list that I should steer clear of too. Here are the patio cleaning mistakes you can avoid this summer when it's time to clean up dirt, spills, and general wear, thanks to expert advice.</p><h2 id="avoid-these-two-household-items">Avoid these two household items</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4920px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="sMd8gCbGmyEvMxzfUpq5PZ" name="White vinegar - crop.jpg" alt="White vinegar" src="https://cdn.mos.cms.futurecdn.net/sMd8gCbGmyEvMxzfUpq5PZ-1920-80.jpg" mos="" align="middle" fullscreen="" width="4920" height="2768" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Morgan Smith, director at porcelain garden tiles company <a href="https://www.pegseostone.co.uk/external-porcelain/porcelain-paving/" target="_blank">Pegseo Stone</a>, has advised there are two common products that people use when cleaning the patio that shouldn't be – white vinegar and bleach. While I use white vinegar for <a href="https://www.tomsguide.com/home/this-zero-effort-vinegar-hack-is-a-total-game-changer-for-cleaning-your-microwave">'zero-effort' hacks like cleaning my microwave</a>, it turns out the patio is one place I shouldn't take it.</p><p>Smith says: "White vinegar is highly acidic, so using it on certain patio materials can damage the surface itself rather than simply removing dirt." These certain materials include limestone and other calcareous pavers.</p><p>But, you should also be careful that you're not causing harm to any grass or flowerbeds nearby, Smith adds: "Any vinegar that runs into nearby borders can also damage grass and plants, meaning it can harm both the patio and the surrounding garden."</p><p>The same applies for bleach. As Smith explains, while it may give you a visual improvement, over time it can cause "lasting surface damage and further maintenance costs."</p><p>So, next time you head out to clean your patio, think before grabbing the white vinegar or bleach.</p><h2 id="what-to-use-instead">What to use instead</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="iZUM4Tsn4qFvMkCejPHxHG" name="patio-deck-feature.jpg" alt="Patio Furniture" src="https://cdn.mos.cms.futurecdn.net/iZUM4Tsn4qFvMkCejPHxHG-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Fortunately, there's an even simpler household item that you can use that shouldn't cause any damage to your patio – and that's an easy soap and water solution.</p><p>"Using warm water and soap is an effective option for general patio cleaning, particularly when used with a hard-bristled brush," Smith advises. "Start cleaning from the corners of the paving and move gradually inwards, allowing each section to be scrubbed and rinsed before moving on."</p><p>You'll want to opt for a soap that's eco-friendly though, meaning it avoids harmful chemicals to any flora, fauna and wildlife nearby.</p><div class="product"><a data-dimension112="e793b3e2-90b0-11f1-990b-554a576ccd9c" data-action="Deal Block" data-label="Stainless Steel Wire Scrub Brush" data-dimension48="Stainless Steel Wire Scrub Brush" data-dimension25="$19.99" href="https://www.amazon.com/Stainless-Concrete-Cleaning-Bristle-Scrubber/dp/B0D7BJG92R" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="24iCUUuKPnigxXseFNLLdS" name="scrub_brush_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/24iCUUuKPnigxXseFNLLdS-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Stainless-Concrete-Cleaning-Bristle-Scrubber/dp/B0D7BJG92R" target="_blank" rel="nofollow" data-dimension112="e793b3e2-90b0-11f1-990b-554a576ccd9c" data-action="Deal Block" data-label="Stainless Steel Wire Scrub Brush" data-dimension48="Stainless Steel Wire Scrub Brush" data-dimension25="$19.99">Stainless Steel Wire Scrub Brush: $19.99</a></strong><br />This heavy duty brush is perfect for patio cleaning, equipped with a long handle and steel wire bristles to work on durable hard surfaces. Extendable up to 59-inches, you can scrub away without having to keep bending over.<a class="view-deal button" href="https://www.amazon.com/Stainless-Concrete-Cleaning-Bristle-Scrubber/dp/B0D7BJG92R" target="_blank" rel="nofollow" data-dimension112="e793b3e2-90b0-11f1-990b-554a576ccd9c" data-action="Deal Block" data-label="Stainless Steel Wire Scrub Brush" data-dimension48="Stainless Steel Wire Scrub Brush" data-dimension25="$19.99">View Deal</a></p></div><p>Plus, if you're lucky enough to have a pressure washer handy, Smith says it's important to watch how forcefully you wash, advising: "too much force can damage the surface of the pavers."</p><p>Instead, Smith suggests sticking to a low-pressure setting and angling the pressure washer nozzle at 30-degrees, rather than pointing it directly at the pavers.</p><p>And one final tip is is to check the joints between each slab once you've done your cleaning: "Areas that have lost sand or pointing should be repaired to keep the paving secure and limit further deterioration."</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/outdoors/im-cleaning-my-patio-furniture-with-this-non-toxic-ingredient-and-it-also-works-wonders-on-your-grill">I'm cleaning my patio furniture with this non-toxic ingredient — and it also works wonders on your grill</a></li><li><a href="https://www.tomsguide.com/home/gardening/forget-power-washing-5-budget-friendly-hacks-to-get-your-backyard-sparkling-this-spring">Forget power washing: 5 budget-friendly hacks to get your backyard sparkling this spring</a></li><li><a href="https://www.tomsguide.com/home/5-tips-to-keep-your-deck-looking-great-all-summer">5 tips to keep your deck looking great all summer</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I was an AI skeptic — until I started using it to identify plants ]]></title>
                                                                                                <dc:content><![CDATA[ <p>You’d think after several decades of gardening, few plants could catch me completely by surprise. Yet nature always finds a way to remind me how much there is left to discover. </p><p>During a visit to <a href="https://www.arundelcastle.org/" target="_blank">Arundel Castle and Gardens</a> in the U.K. this summer, I was completely captivated — first by the exquisite water garden, and then by a breathtaking bloom that left me spellbound, all quietly affirming why I do what I do. </p><p>Despite searching high and low for a plant label to identify the mysterious bloom, it remained unnamed. In this situation, my trusted go-to move is to snap a quick photo on my phone and post it on social, hoping one of my gardening followers can help.</p><p>But, as I am often surrounded by AI discussions at Tom’s Guide, I thought it was time to swap my social media shout-outs for a tech-driven answer. </p><p>Follow me on my journey to see whether artificial intelligence can become a reliable gardening companion, or whether I need to fall back on a seasoned gardener’s eye. And true to my aptitude at saving money, I used free apps during my experiment.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Ozr20O"></div>                            </div>                            <script src="https://kwizly.com/embed/Ozr20O.js" async=""></script><h2 id="what-happened-when-i-used-ai-to-identify-a-plant">What happened when I used AI to identify a plant?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5LBPRksRqAwNbvWJiZSysN" name="Cleome hassleriana, commonly known as spider flower" alt="Cleome hassleriana, commonly known as spider flower" src="https://cdn.mos.cms.futurecdn.net/5LBPRksRqAwNbvWJiZSysN-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Although I work within digital publishing, I’m not as tech-savvy as some of my Tom’s Guide colleagues, who can navigate digital tools with their eyes shut. But, thankfully, if you can upload a photo to social media, you’re already fully qualified to use AI to identify plants.</p><p>Before putting AI to work, you need a crisp, clear shot. Unlike a fellow gardener, a cluttered background will trip up an algorithm. It really won’t be happy if you ask it to identify a plant that’s included in a mixed border.</p><p>My tip is to frame a single flower in the center. Cutting out the clutter will give AI exactly what it needs for an accurate identification. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="hzMwQe8xKYr6bk8CbDTQtN" name="Closeup image of plant for AI identification" alt="Closeup image of plant for AI identification" src="https://cdn.mos.cms.futurecdn.net/hzMwQe8xKYr6bk8CbDTQtN-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><h2 id="using-google-gemini">Using Google Gemini</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:59.79%;"><img id="tKpN98LFZAmmyGKfqiTpC7" name="Gemini plants" alt="Google Gemini plant identification screen shots" src="https://cdn.mos.cms.futurecdn.net/tKpN98LFZAmmyGKfqiTpC7-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1148" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Having opened Google Gemini on my phone, I entered the prompt ‘identify this plant’. I thought it would instruct me to upload an image, but before doing so, it gave me instructions to either provide a photo or describe the plant, including specifics such as leaves and flowers, growth habitat and environment.</p><p>I then attached the image of the plant that I’d already taken. However, at this point you could take the photo; it doesn’t already have to be an image you already have stored on your phone.</p><p><strong>The results</strong><br />I didn’t even have time to blink before the results appeared. Apparently my mystery plant is a <em>Cleome hassleriana</em>, commonly known as the spider flower. </p><p><strong>Gemini responded with:</strong></p><p>"This plant is <strong>Cleome</strong> (botanical name <em>Cleome hassleriana</em> or <em>Tarenaya hassleriana</em>), commonly known as the <strong>Spider Flower</strong> or <strong>Spider Plant</strong>."</p><p>I wasn’t expecting any more than the name, and yes, Google Gemini was correct. But I was also given details on the plant’s key characteristics, including its flowers, foliage, growth habit, care and growing tips. Here's a snapshot of some of the details:</p><p>"<strong>Flowers: </strong>Bright pink, purple, or white terminal clusters featuring long, thread-like stamens that extend far beyond the petals, giving them a spider-like appearance."</p><p>I'll be sharing more on the beautiful spider flower in another article, as apparently it’s super easy to grow — as advised by my garden designer friend<a href="https://www.instagram.com/stevendigby/"> Steven Digby</a>, who often helps me out with my Instagram shout-outs. You won’t get this personalized advice on AI, but it will give you a good start.</p><h2 id="using-chatgpt">Using ChatGPT</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:59.79%;"><img id="XTaiWwA5Vfvwqvb475fUB7" name="ChatGPT plants" alt="ChatGPT plant identification screenshots" src="https://cdn.mos.cms.futurecdn.net/XTaiWwA5Vfvwqvb475fUB7-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1148" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p><strong>Using ChatGPT</strong><br />I entered the same instructions into ChatGPT to compare results. This time, unlike Gemini, ChatGPT gave me instructions on what to capture in the image, such as taking a photo of the whole plant and getting close-ups of the leaves, any flowers, fruits, or seed pods. </p><p>It also suggested capturing the stem or bark and adding any details about location, height and scent. However, from my understanding, it was expecting to identify the plant by a photo, rather than a description alone. </p><p><strong>ChatGPT responded with:</strong></p><p>"This looks like a <strong>spider flower</strong>, most likely Cleome hassleriana. The features that stand out are:</p><p><strong>• </strong>Bright pink flower clusters.<br /><strong>• </strong>Very long, thread-like stamens that give the flowers a "spidery" appearance.<br /><strong>• </strong>Tall, upright stems.<br /><strong>• </strong>Palmately compound leaves with several narrow leaflets."</p><p>ChatGPT was correct in its identification, and it did provide some additional details on the plant, but from a user perspective, I found Google Gemini’s information simpler to read. Splitting it into clear headings made it easier to digest.</p><p>That said, ChatGPT did pick up that there were other plants within the image, noticing rose leaves, and stated that although it identified rose bushes close by, it was confident in identifying the spider flower as the main plant. </p><p><strong>Other apps to try</strong><br />Although I decided to use Google Gemini, Mike Prospero, U.S. editor-in-chief at Tom’s Guide, previously used Google, Google Chrome and the Gemini app, and he takes you through how to use all three in his article on <a href="https://www.tomsguide.com/home/gardening/im-seriously-allergic-to-poison-ivy-this-gemini-feature-helps-me-when-im-weeding">identifying poison ivy using AI</a>.</p><div class="product"><a data-dimension112="c54d4466-925d-11f1-913d-c9d9014509d4" data-action="Deal Block" data-label="Garden Gloves (2-pack)" data-dimension48="Garden Gloves (2-pack)" data-dimension25="$9" href="https://www.amazon.com/dp/B07BD2GZW8?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:367px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="YyBJP4YUpLVNV4q2yKFfjS" name="Screenshot-2024-08-13-141525edit.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/YyBJP4YUpLVNV4q2yKFfjS-1920-80.jpg" mos="" align="middle" fullscreen="" width="367" height="367" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B07BD2GZW8?" target="_blank" rel="nofollow" data-dimension112="c54d4466-925d-11f1-913d-c9d9014509d4" data-action="Deal Block" data-label="Garden Gloves (2-pack)" data-dimension48="Garden Gloves (2-pack)" data-dimension25="$9">Garden Gloves (2-pack): $9</a></strong><br />These garden gloves are made of nylon and nitrile and come in three sizes — small, medium and large. They offer excellent non-slip properties, are comfortable around the wrist, breathable and machine washable. At Tom's Guide, we recommend them as the best overall gardening glove.<a class="view-deal button" href="https://www.amazon.com/dp/B07BD2GZW8?" target="_blank" rel="nofollow" data-dimension112="c54d4466-925d-11f1-913d-c9d9014509d4" data-action="Deal Block" data-label="Garden Gloves (2-pack)" data-dimension48="Garden Gloves (2-pack)" data-dimension25="$9">View Deal</a></p></div><h2 id="ai-versus-human-the-verdict">AI versus human: The verdict</h2><p>I was impressed with both Gemini and ChatGPT — each identified the mystery plant instantly from just a single photo, without any further hints.</p><p>I’m no longer skeptical about using AI to identify plants, and if you’re impatient and want to know the answer quickly, this tech delivers.</p><p>An algorithm won’t give the subtle, seasoned wisdom of an experienced gardener, such as my friend Digby’s advice on how this stunning annual is really easy to grow from seed. (Yes, I doubled my chances and uploaded the photo on social.) But if you want quick answers, it provides accurate plant identification.</p><p>My deep dive into AI came down to my new obsession with the spider flower, and now I know what it is and that it’s easy to grow; I’ll be adding it to my garden next year. </p><h2 id="how-else-can-ai-help-gardeners">How else can AI help gardeners?</h2><p>This is just the beginning of my gardening journey using AI. I'm already planning other ways to test how AI can help me in the garden, from assisting with planting plans to advising on heat-tolerant plants, and I’ll be sharing what I discover over the coming months. Let me know your thoughts and experiences of using AI in the garden in the comments below.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/stop-fighting-the-climate-expert-approved-tips-on-how-to-plant-for-hotter-summers">Stop fighting the climate: Expert-approved tips on how to plant for hotter summers</a></li><li><a href="https://www.tomsguide.com/home/gardening/7-easy-vegetables-to-plant-in-august-that-thrive-as-summer-fades">7 easy vegetables to plant in August that thrive as summer fades</a></li><li><a href="https://www.tomsguide.com/home/gardening/gardeners-are-ditching-lavender-for-this-tougher-long-blooming-shrub-and-it-doesnt-go-woody">Gardeners are ditching lavender for this tougher, long-blooming shrub — and it doesn’t go woody</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/outdoors/i-was-an-ai-skeptic-until-i-started-using-it-to-identify-plants</link>
                                                                            <description>
                            <![CDATA[ Can AI replace a seasoned gardener’s eye? I put it to the test. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">8CMDGoqBP6iopL3RDC5Eth</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/p2VmnszBebiNqnn4ZsqotR-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 09 Aug 2026 07:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Outdoors]]></category>
                                                    <category><![CDATA[AI]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                                                                <author><![CDATA[ camilla.sharman@futurenet.com (Camilla Sharman) ]]></author>                    <dc:creator><![CDATA[ Camilla Sharman ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/nY4nvWzofHKHpvzAqN5LVH-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Camilla is the Homes Staff Writer and covers everything to do with homes and gardens. She has a wealth of editorial experience, mounting over 30 years, and covers news and features, tests products for reviews and compiles buying guides.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Her work has appeared in business and consumer titles, including Ideal Home, Real Homes, House Beautiful, Homebuilding &amp;amp; Renovation, and Kitchen &amp;amp; Bathroom Business. She’s even appeared on the cover of Your Home, writing about her own house renovation.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Although she’s obsessed with decorating her home, she also enjoys baking and trying out the latest kitchen appliances. But when she’s not inside, you’ll find her pottering about in her yard, tending to her vegetable patch or taking in her prized hydrangeas. She also enjoys keeping fit, and if she&#039;s not on a spin bike trying to keep up with the class, she&#039;ll be in the pool, or trying to perfect her headstand in a yoga class.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/p2VmnszBebiNqnn4ZsqotR-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Cleome hassleriana, commonly known as spider flower]]></media:description>                                                            <media:text><![CDATA[Cleome hassleriana, commonly known as spider flower]]></media:text>
                                <media:title type="plain"><![CDATA[Cleome hassleriana, commonly known as spider flower]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/p2VmnszBebiNqnn4ZsqotR-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>You’d think after several decades of gardening, few plants could catch me completely by surprise. Yet nature always finds a way to remind me how much there is left to discover. </p><p>During a visit to <a href="https://www.arundelcastle.org/" target="_blank">Arundel Castle and Gardens</a> in the U.K. this summer, I was completely captivated — first by the exquisite water garden, and then by a breathtaking bloom that left me spellbound, all quietly affirming why I do what I do. </p><p>Despite searching high and low for a plant label to identify the mysterious bloom, it remained unnamed. In this situation, my trusted go-to move is to snap a quick photo on my phone and post it on social, hoping one of my gardening followers can help.</p><p>But, as I am often surrounded by AI discussions at Tom’s Guide, I thought it was time to swap my social media shout-outs for a tech-driven answer. </p><p>Follow me on my journey to see whether artificial intelligence can become a reliable gardening companion, or whether I need to fall back on a seasoned gardener’s eye. And true to my aptitude at saving money, I used free apps during my experiment.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Ozr20O"></div>                            </div>                            <script src="https://kwizly.com/embed/Ozr20O.js" async=""></script><h2 id="what-happened-when-i-used-ai-to-identify-a-plant">What happened when I used AI to identify a plant?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5LBPRksRqAwNbvWJiZSysN" name="Cleome hassleriana, commonly known as spider flower" alt="Cleome hassleriana, commonly known as spider flower" src="https://cdn.mos.cms.futurecdn.net/5LBPRksRqAwNbvWJiZSysN-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><p>Although I work within digital publishing, I’m not as tech-savvy as some of my Tom’s Guide colleagues, who can navigate digital tools with their eyes shut. But, thankfully, if you can upload a photo to social media, you’re already fully qualified to use AI to identify plants.</p><p>Before putting AI to work, you need a crisp, clear shot. Unlike a fellow gardener, a cluttered background will trip up an algorithm. It really won’t be happy if you ask it to identify a plant that’s included in a mixed border.</p><p>My tip is to frame a single flower in the center. Cutting out the clutter will give AI exactly what it needs for an accurate identification. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="hzMwQe8xKYr6bk8CbDTQtN" name="Closeup image of plant for AI identification" alt="Closeup image of plant for AI identification" src="https://cdn.mos.cms.futurecdn.net/hzMwQe8xKYr6bk8CbDTQtN-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future / Camilla Sharman)</span></figcaption></figure><h2 id="using-google-gemini">Using Google Gemini</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:59.79%;"><img id="tKpN98LFZAmmyGKfqiTpC7" name="Gemini plants" alt="Google Gemini plant identification screen shots" src="https://cdn.mos.cms.futurecdn.net/tKpN98LFZAmmyGKfqiTpC7-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1148" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Having opened Google Gemini on my phone, I entered the prompt ‘identify this plant’. I thought it would instruct me to upload an image, but before doing so, it gave me instructions to either provide a photo or describe the plant, including specifics such as leaves and flowers, growth habitat and environment.</p><p>I then attached the image of the plant that I’d already taken. However, at this point you could take the photo; it doesn’t already have to be an image you already have stored on your phone.</p><p><strong>The results</strong><br />I didn’t even have time to blink before the results appeared. Apparently my mystery plant is a <em>Cleome hassleriana</em>, commonly known as the spider flower. </p><p><strong>Gemini responded with:</strong></p><p>"This plant is <strong>Cleome</strong> (botanical name <em>Cleome hassleriana</em> or <em>Tarenaya hassleriana</em>), commonly known as the <strong>Spider Flower</strong> or <strong>Spider Plant</strong>."</p><p>I wasn’t expecting any more than the name, and yes, Google Gemini was correct. But I was also given details on the plant’s key characteristics, including its flowers, foliage, growth habit, care and growing tips. Here's a snapshot of some of the details:</p><p>"<strong>Flowers: </strong>Bright pink, purple, or white terminal clusters featuring long, thread-like stamens that extend far beyond the petals, giving them a spider-like appearance."</p><p>I'll be sharing more on the beautiful spider flower in another article, as apparently it’s super easy to grow — as advised by my garden designer friend<a href="https://www.instagram.com/stevendigby/"> Steven Digby</a>, who often helps me out with my Instagram shout-outs. You won’t get this personalized advice on AI, but it will give you a good start.</p><h2 id="using-chatgpt">Using ChatGPT</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:59.79%;"><img id="XTaiWwA5Vfvwqvb475fUB7" name="ChatGPT plants" alt="ChatGPT plant identification screenshots" src="https://cdn.mos.cms.futurecdn.net/XTaiWwA5Vfvwqvb475fUB7-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1148" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p><strong>Using ChatGPT</strong><br />I entered the same instructions into ChatGPT to compare results. This time, unlike Gemini, ChatGPT gave me instructions on what to capture in the image, such as taking a photo of the whole plant and getting close-ups of the leaves, any flowers, fruits, or seed pods. </p><p>It also suggested capturing the stem or bark and adding any details about location, height and scent. However, from my understanding, it was expecting to identify the plant by a photo, rather than a description alone. </p><p><strong>ChatGPT responded with:</strong></p><p>"This looks like a <strong>spider flower</strong>, most likely Cleome hassleriana. The features that stand out are:</p><p><strong>• </strong>Bright pink flower clusters.<br /><strong>• </strong>Very long, thread-like stamens that give the flowers a "spidery" appearance.<br /><strong>• </strong>Tall, upright stems.<br /><strong>• </strong>Palmately compound leaves with several narrow leaflets."</p><p>ChatGPT was correct in its identification, and it did provide some additional details on the plant, but from a user perspective, I found Google Gemini’s information simpler to read. Splitting it into clear headings made it easier to digest.</p><p>That said, ChatGPT did pick up that there were other plants within the image, noticing rose leaves, and stated that although it identified rose bushes close by, it was confident in identifying the spider flower as the main plant. </p><p><strong>Other apps to try</strong><br />Although I decided to use Google Gemini, Mike Prospero, U.S. editor-in-chief at Tom’s Guide, previously used Google, Google Chrome and the Gemini app, and he takes you through how to use all three in his article on <a href="https://www.tomsguide.com/home/gardening/im-seriously-allergic-to-poison-ivy-this-gemini-feature-helps-me-when-im-weeding">identifying poison ivy using AI</a>.</p><div class="product"><a data-dimension112="c54d4466-925d-11f1-913d-c9d9014509d4" data-action="Deal Block" data-label="Garden Gloves (2-pack)" data-dimension48="Garden Gloves (2-pack)" data-dimension25="$9" href="https://www.amazon.com/dp/B07BD2GZW8?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:367px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="YyBJP4YUpLVNV4q2yKFfjS" name="Screenshot-2024-08-13-141525edit.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/YyBJP4YUpLVNV4q2yKFfjS-1920-80.jpg" mos="" align="middle" fullscreen="" width="367" height="367" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/dp/B07BD2GZW8?" target="_blank" rel="nofollow" data-dimension112="c54d4466-925d-11f1-913d-c9d9014509d4" data-action="Deal Block" data-label="Garden Gloves (2-pack)" data-dimension48="Garden Gloves (2-pack)" data-dimension25="$9">Garden Gloves (2-pack): $9</a></strong><br />These garden gloves are made of nylon and nitrile and come in three sizes — small, medium and large. They offer excellent non-slip properties, are comfortable around the wrist, breathable and machine washable. At Tom's Guide, we recommend them as the best overall gardening glove.<a class="view-deal button" href="https://www.amazon.com/dp/B07BD2GZW8?" target="_blank" rel="nofollow" data-dimension112="c54d4466-925d-11f1-913d-c9d9014509d4" data-action="Deal Block" data-label="Garden Gloves (2-pack)" data-dimension48="Garden Gloves (2-pack)" data-dimension25="$9">View Deal</a></p></div><h2 id="ai-versus-human-the-verdict">AI versus human: The verdict</h2><p>I was impressed with both Gemini and ChatGPT — each identified the mystery plant instantly from just a single photo, without any further hints.</p><p>I’m no longer skeptical about using AI to identify plants, and if you’re impatient and want to know the answer quickly, this tech delivers.</p><p>An algorithm won’t give the subtle, seasoned wisdom of an experienced gardener, such as my friend Digby’s advice on how this stunning annual is really easy to grow from seed. (Yes, I doubled my chances and uploaded the photo on social.) But if you want quick answers, it provides accurate plant identification.</p><p>My deep dive into AI came down to my new obsession with the spider flower, and now I know what it is and that it’s easy to grow; I’ll be adding it to my garden next year. </p><h2 id="how-else-can-ai-help-gardeners">How else can AI help gardeners?</h2><p>This is just the beginning of my gardening journey using AI. I'm already planning other ways to test how AI can help me in the garden, from assisting with planting plans to advising on heat-tolerant plants, and I’ll be sharing what I discover over the coming months. Let me know your thoughts and experiences of using AI in the garden in the comments below.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/stop-fighting-the-climate-expert-approved-tips-on-how-to-plant-for-hotter-summers">Stop fighting the climate: Expert-approved tips on how to plant for hotter summers</a></li><li><a href="https://www.tomsguide.com/home/gardening/7-easy-vegetables-to-plant-in-august-that-thrive-as-summer-fades">7 easy vegetables to plant in August that thrive as summer fades</a></li><li><a href="https://www.tomsguide.com/home/gardening/gardeners-are-ditching-lavender-for-this-tougher-long-blooming-shrub-and-it-doesnt-go-woody">Gardeners are ditching lavender for this tougher, long-blooming shrub — and it doesn’t go woody</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Dualit Design Series Kettle review ]]></title>
                                                                                                <dc:content><![CDATA[ <p>As a tea-drinking Brit, I have big opinions on kettles, and the Dualit Design Series Kettle is a good option for most people’s homes. It has an aesthetic stainless steel design which is easy to maintain with regular cleaning. It has good heat retention and is easy and accurate to pour with. </p><p>Unfortunately, though, the window design makes it hard to read the measurements when filling the kettle. The boiling is also a little slow when compared to other kettles. </p><p>To find out more about the kitchen appliance, you can keep reading this full Dualit Design Series Kettle review. </p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-specs"><span>Dualit Design Series Kettle review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Dualit-72955-Design-Kettle-Black/dp/B00UHKSRMG" target="_blank" rel="nofollow">$178</a></p></td></tr><tr><td class="firstcol " ><p><strong>Capacity</strong></p></td><td  ><p>1.5L</p></td></tr><tr><td class="firstcol " ><p><strong>Rated power</strong></p></td><td  ><p>1.5kW</p></td></tr><tr><td class="firstcol " ><p><strong>Exterior material</strong></p></td><td  ><p>Stainless steel</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>9.4 x 8.6 x 5.5 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>3.2 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Features</strong></p></td><td  ><p>Interchangeable panels, Boil-dry protection, Pure pour spout</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-price-availability"><span>Dualit Design Series Kettle review: Price &amp; availability</span></h2><p>The Dualit Design Series Kettle is available to purchase from <a href="https://www.amazon.com/Dualit-72955-Design-Kettle-Black/dp/B00UHKSRMG" target="_blank" rel="nofollow">Amazon U.S. for $178</a> or directly from the <a href="https://us.dualit.com/products/design-series-kettle" target="_blank" rel="nofollow">Dualit online store for $179</a>. You can also purchase the kettle in the U.K., where it’s called the <a href="https://www.tomsguide.com/reviews/dualit-architect-kettle">Dualit Architect Kettle</a>. </p><p>The kettle has a stainless steel finish, but you can purchase <a href="https://www.dualit.com/products/architect-kettle-panels" target="_blank" rel="nofollow">interchangeable panels </a>for the bottom section from the Dualit store to make it your own. These include the colors Shadow, Metallic Silver, Copper, Brass, Evergreen and Eucalyptus. </p><p>Dualit also sells the <a href="https://www.tomsguide.com/home/home-appliances/dualit-classic-kettle-review">Classic Kettle</a> for $249, which is more of a fashion statement than a standard kettle. Its curved shape is much more interesting than the Design Series — the irony is not lost on me.</p><p>But you don’t need to spend the best part of $200 for a good kettle. I have also tested the <a href="https://www.tomsguide.com/home/home-appliances/dualit-classic-kettle-review">Cosori Electric Glass Kettle</a>, which, while not as dashing, is a fraction of the price at just $27. And honestly, it does just as good a job as the Design Series Kettle — you just have to be willing to put up with the odd leak while pouring, which isn’t a worry with the Dualit.</p><p>While the Dualit has a Pure pour spout to ensure zero leaks when pouring, if you need even more precision for drinks such as pour-over coffee, you may want to consider a gooseneck kettle such as the <a href="https://www.tomsguide.com/home/home-appliances/fellow-stagg-ekg-kettle-review">Fellow Stagg EKG</a> for $165. If you take your brews seriously, I’d recommend the Fellow over the Dualit.</p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-design-features"><span>Dualit Design Series Kettle review: Design &amp; features</span></h2><p>The Dualit Design Series Kettle is certainly eye-catching. It measures 9.4 x 8.6 x 5.5 inches, weighs 3.2 pounds, and has a reflective surface that will have you checking out your hair while the water boils. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="vQQ7jxTzikipJHUeGEbBHW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/vQQ7jxTzikipJHUeGEbBHW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>It can boil a maximum capacity of 1.5 liters, enough for six cups. However, you’ll find yourself playing a guessing game when filling it because of the design and positioning of the measurement window. The window has a fish-eye effect, warping the water as you peer through, and it sits directly in line with the handle, so you need to look around that too. </p><p>The handle extends down most of the body, making it easy to hold. At the top of the handle there’s a button to release the flat, hinged lid. This means you can open it without touching it, but to close it you’ll need to push it down. If you’ve already boiled the kettle once, be wary as this part can get very hot. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ugUvCUdXy2Q2SLczdobUiW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/ugUvCUdXy2Q2SLczdobUiW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The power switch is just below the handle at the base. This base is very cohesive with the rest of the kettle — it looks like one whole unit with the kettle on top. It has a three-foot power cord, so it is best set up near a power outlet. If you need to make this shorter, you can store the excess in the base.</p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-performance"><span>Dualit Design Series Kettle review: Performance </span></h2><p>I have to say, when testing the Dualit Design Series Kettle, I was a little confused. After testing the Dualit Classic Kettle, I was impressed at how fast it boiled the water. It boiled five cups in just two minutes and 35 seconds. The Design Series Kettle took three minutes and 11 seconds — a stark difference. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3TE8WQrPykucFMwxWgcVwW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/3TE8WQrPykucFMwxWgcVwW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>All of my testing conditions were the same, so if you want an appliance that won’t have you waiting around all day, spring for the more expensive Classic. You may be spending a little extra, but hey, you’ll get to enjoy life with your fresh brew instead of staring into your lifeless eyes in the kettle’s reflection as the water boils for an extra minute. Just me? Well, as a tea-drinking Brit, by the time I’ve made my daily quota, all of those minutes add up.</p><div ><table><tbody><tr><td class="firstcol " ><p><strong>Capacity</strong></p></td><td  ><p><strong>Boiling time</strong></p></td></tr><tr><td class="firstcol " ><p><strong>2 cups</strong></p></td><td  ><p>1 minute, 35 seconds</p></td></tr><tr><td class="firstcol " ><p><strong>3 cups</strong></p></td><td  ><p>2 minutes, 5 seconds</p></td></tr><tr><td class="firstcol " ><p><strong>4 cups </strong></p></td><td  ><p>2 minutes, 41 seconds</p></td></tr><tr><td class="firstcol " ><p><strong>5 cups </strong></p></td><td  ><p>3 minutes, 11 seconds</p></td></tr><tr><td class="firstcol " ><p><strong>Max</strong></p></td><td  ><p>3 minutes, 53 seconds</p></td></tr></tbody></table></div><p>I measured the temperature of the water immediately after boiling and got a reading of 209.3ºF/98.5ºC. This was very slightly cooler than the 210ºF/99.3ºC reading I got from the Classic Kettle. But the Design Series holds heat pretty well. After an hour, I got a reading of 161.1ºF/71.7ºC. So, if you wanted to reboil the water, you won’t be waiting for the full *checks notes* three minutes and 53 seconds — yikes. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ipma4RqBU5Rb5HruMitjYW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/ipma4RqBU5Rb5HruMitjYW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Pouring with the kettle is a dream. If you’re a little shaky when pouring, I would fully recommend this kettle. I encountered no spillages. And the water went exactly where I needed it to. It can be a little heavy when you fill it to the top, so I only ever filled it about halfway so I could still use it with ease. </p><p>The kettle isn’t too loud either, and gave me a reading of 76dB on the Decibel X app.</p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-storage-maintenance"><span>Dualit Design Series Kettle review: Storage &amp; maintenance </span></h2><p>The Dualit Design Series is a kettle, and as such, this is a generally straightforward affair. It’s easy to maintain; you’ll just find yourself wiping down the exterior more than your usual kettle given its reflective nature. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="iyrLxfLyPwcSnTSiRmWXuW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/iyrLxfLyPwcSnTSiRmWXuW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>If you live in a hard water area, you’ll also need to descale the kettle regularly. You can purchase descaling tablets for this or use natural <a href="https://www.tomsguide.com/home/how-to-clean-a-kettle-7-simple-steps">methods such as lemon juice or baking soda</a>. The spout of the kettle also has a removable limescale filter which is easy to remove, clean, and refit. </p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-verdict"><span>Dualit Design Series Kettle review: Verdict</span></h2><p>The Dualit Design Series Kettle is undeniably good-looking. The stainless steel finish is slick and will fit in with any kitchen. The kettle is also easy to maintain (if you don’t mind wiping it down a lot). It has good heat retention and is very easy to pour with. There were absolutely zero drips thanks to the Pure pour spout. </p><p>Unfortunately, it’s tricky to tell where the water has been filled up to because of the poor window design, and boiling is a little slow. It took a whole minute longer to boil the same volume of water as the Dualit Classic Kettle.</p><p>If sleek looks are your priority, this is a great kettle, but $178 is a lot of money to spend on a kettle that takes so long to boil. </p> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/kitchen-dining/dualit-design-series-kettle-review</link>
                                                                            <description>
                            <![CDATA[ The Dualit Design Series Kettle is eye-catching and prevents spills, but you may be waiting a while for it to boil. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">cXwSrBEZW5zGvnAtYzrL3k</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/fZnyhuNqg3ce68qXwPikvW-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 07 Aug 2026 15:00:39 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Kitchen & Dining]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/fZnyhuNqg3ce68qXwPikvW-1920-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Dualit Design Series Kettle photographed in front of a blue background]]></media:description>                                                            <media:text><![CDATA[Dualit Design Series Kettle photographed in front of a blue background]]></media:text>
                                <media:title type="plain"><![CDATA[Dualit Design Series Kettle photographed in front of a blue background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/fZnyhuNqg3ce68qXwPikvW-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As a tea-drinking Brit, I have big opinions on kettles, and the Dualit Design Series Kettle is a good option for most people’s homes. It has an aesthetic stainless steel design which is easy to maintain with regular cleaning. It has good heat retention and is easy and accurate to pour with. </p><p>Unfortunately, though, the window design makes it hard to read the measurements when filling the kettle. The boiling is also a little slow when compared to other kettles. </p><p>To find out more about the kitchen appliance, you can keep reading this full Dualit Design Series Kettle review. </p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-specs"><span>Dualit Design Series Kettle review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Dualit-72955-Design-Kettle-Black/dp/B00UHKSRMG" target="_blank" rel="nofollow">$178</a></p></td></tr><tr><td class="firstcol " ><p><strong>Capacity</strong></p></td><td  ><p>1.5L</p></td></tr><tr><td class="firstcol " ><p><strong>Rated power</strong></p></td><td  ><p>1.5kW</p></td></tr><tr><td class="firstcol " ><p><strong>Exterior material</strong></p></td><td  ><p>Stainless steel</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>9.4 x 8.6 x 5.5 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>3.2 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Features</strong></p></td><td  ><p>Interchangeable panels, Boil-dry protection, Pure pour spout</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-price-availability"><span>Dualit Design Series Kettle review: Price &amp; availability</span></h2><p>The Dualit Design Series Kettle is available to purchase from <a href="https://www.amazon.com/Dualit-72955-Design-Kettle-Black/dp/B00UHKSRMG" target="_blank" rel="nofollow">Amazon U.S. for $178</a> or directly from the <a href="https://us.dualit.com/products/design-series-kettle" target="_blank" rel="nofollow">Dualit online store for $179</a>. You can also purchase the kettle in the U.K., where it’s called the <a href="https://www.tomsguide.com/reviews/dualit-architect-kettle">Dualit Architect Kettle</a>. </p><p>The kettle has a stainless steel finish, but you can purchase <a href="https://www.dualit.com/products/architect-kettle-panels" target="_blank" rel="nofollow">interchangeable panels </a>for the bottom section from the Dualit store to make it your own. These include the colors Shadow, Metallic Silver, Copper, Brass, Evergreen and Eucalyptus. </p><p>Dualit also sells the <a href="https://www.tomsguide.com/home/home-appliances/dualit-classic-kettle-review">Classic Kettle</a> for $249, which is more of a fashion statement than a standard kettle. Its curved shape is much more interesting than the Design Series — the irony is not lost on me.</p><p>But you don’t need to spend the best part of $200 for a good kettle. I have also tested the <a href="https://www.tomsguide.com/home/home-appliances/dualit-classic-kettle-review">Cosori Electric Glass Kettle</a>, which, while not as dashing, is a fraction of the price at just $27. And honestly, it does just as good a job as the Design Series Kettle — you just have to be willing to put up with the odd leak while pouring, which isn’t a worry with the Dualit.</p><p>While the Dualit has a Pure pour spout to ensure zero leaks when pouring, if you need even more precision for drinks such as pour-over coffee, you may want to consider a gooseneck kettle such as the <a href="https://www.tomsguide.com/home/home-appliances/fellow-stagg-ekg-kettle-review">Fellow Stagg EKG</a> for $165. If you take your brews seriously, I’d recommend the Fellow over the Dualit.</p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-design-features"><span>Dualit Design Series Kettle review: Design &amp; features</span></h2><p>The Dualit Design Series Kettle is certainly eye-catching. It measures 9.4 x 8.6 x 5.5 inches, weighs 3.2 pounds, and has a reflective surface that will have you checking out your hair while the water boils. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="vQQ7jxTzikipJHUeGEbBHW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/vQQ7jxTzikipJHUeGEbBHW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>It can boil a maximum capacity of 1.5 liters, enough for six cups. However, you’ll find yourself playing a guessing game when filling it because of the design and positioning of the measurement window. The window has a fish-eye effect, warping the water as you peer through, and it sits directly in line with the handle, so you need to look around that too. </p><p>The handle extends down most of the body, making it easy to hold. At the top of the handle there’s a button to release the flat, hinged lid. This means you can open it without touching it, but to close it you’ll need to push it down. If you’ve already boiled the kettle once, be wary as this part can get very hot. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ugUvCUdXy2Q2SLczdobUiW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/ugUvCUdXy2Q2SLczdobUiW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The power switch is just below the handle at the base. This base is very cohesive with the rest of the kettle — it looks like one whole unit with the kettle on top. It has a three-foot power cord, so it is best set up near a power outlet. If you need to make this shorter, you can store the excess in the base.</p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-performance"><span>Dualit Design Series Kettle review: Performance </span></h2><p>I have to say, when testing the Dualit Design Series Kettle, I was a little confused. After testing the Dualit Classic Kettle, I was impressed at how fast it boiled the water. It boiled five cups in just two minutes and 35 seconds. The Design Series Kettle took three minutes and 11 seconds — a stark difference. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3TE8WQrPykucFMwxWgcVwW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/3TE8WQrPykucFMwxWgcVwW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>All of my testing conditions were the same, so if you want an appliance that won’t have you waiting around all day, spring for the more expensive Classic. You may be spending a little extra, but hey, you’ll get to enjoy life with your fresh brew instead of staring into your lifeless eyes in the kettle’s reflection as the water boils for an extra minute. Just me? Well, as a tea-drinking Brit, by the time I’ve made my daily quota, all of those minutes add up.</p><div ><table><tbody><tr><td class="firstcol " ><p><strong>Capacity</strong></p></td><td  ><p><strong>Boiling time</strong></p></td></tr><tr><td class="firstcol " ><p><strong>2 cups</strong></p></td><td  ><p>1 minute, 35 seconds</p></td></tr><tr><td class="firstcol " ><p><strong>3 cups</strong></p></td><td  ><p>2 minutes, 5 seconds</p></td></tr><tr><td class="firstcol " ><p><strong>4 cups </strong></p></td><td  ><p>2 minutes, 41 seconds</p></td></tr><tr><td class="firstcol " ><p><strong>5 cups </strong></p></td><td  ><p>3 minutes, 11 seconds</p></td></tr><tr><td class="firstcol " ><p><strong>Max</strong></p></td><td  ><p>3 minutes, 53 seconds</p></td></tr></tbody></table></div><p>I measured the temperature of the water immediately after boiling and got a reading of 209.3ºF/98.5ºC. This was very slightly cooler than the 210ºF/99.3ºC reading I got from the Classic Kettle. But the Design Series holds heat pretty well. After an hour, I got a reading of 161.1ºF/71.7ºC. So, if you wanted to reboil the water, you won’t be waiting for the full *checks notes* three minutes and 53 seconds — yikes. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ipma4RqBU5Rb5HruMitjYW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/ipma4RqBU5Rb5HruMitjYW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Pouring with the kettle is a dream. If you’re a little shaky when pouring, I would fully recommend this kettle. I encountered no spillages. And the water went exactly where I needed it to. It can be a little heavy when you fill it to the top, so I only ever filled it about halfway so I could still use it with ease. </p><p>The kettle isn’t too loud either, and gave me a reading of 76dB on the Decibel X app.</p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-storage-maintenance"><span>Dualit Design Series Kettle review: Storage &amp; maintenance </span></h2><p>The Dualit Design Series is a kettle, and as such, this is a generally straightforward affair. It’s easy to maintain; you’ll just find yourself wiping down the exterior more than your usual kettle given its reflective nature. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="iyrLxfLyPwcSnTSiRmWXuW" name="Dualit Design Series Kettle" alt="Dualit Design Series Kettle photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/iyrLxfLyPwcSnTSiRmWXuW-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>If you live in a hard water area, you’ll also need to descale the kettle regularly. You can purchase descaling tablets for this or use natural <a href="https://www.tomsguide.com/home/how-to-clean-a-kettle-7-simple-steps">methods such as lemon juice or baking soda</a>. The spout of the kettle also has a removable limescale filter which is easy to remove, clean, and refit. </p><h2 class="article-body__section" id="section-dualit-design-series-kettle-review-verdict"><span>Dualit Design Series Kettle review: Verdict</span></h2><p>The Dualit Design Series Kettle is undeniably good-looking. The stainless steel finish is slick and will fit in with any kitchen. The kettle is also easy to maintain (if you don’t mind wiping it down a lot). It has good heat retention and is very easy to pour with. There were absolutely zero drips thanks to the Pure pour spout. </p><p>Unfortunately, it’s tricky to tell where the water has been filled up to because of the poor window design, and boiling is a little slow. It took a whole minute longer to boil the same volume of water as the Dualit Classic Kettle.</p><p>If sleek looks are your priority, this is a great kettle, but $178 is a lot of money to spend on a kettle that takes so long to boil. </p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I put a battery-powered induction stove to the test — here’s what surprised me ]]></title>
                                                                                                <dc:content><![CDATA[ <p>The oil sizzled as I placed the scallops in the pan. On the counter next to me sat a tray of just-baked chocolate chip cookies, their aroma wafting through the air. In the oven, a tray of chicken thighs was slowly baking atop a mixture of Chinese vegetables, their juices infusing with the cabbage and boy choy beneath.</p><p>I was cooking it all on the Copper Charlie, an innovative induction stove that doesn’t require any special installation, thanks to a massive battery. And while it's an early adopter in the world of early adopters, it could represent the future of home appliances. </p><h2 id="renovation-is-the-mother-of-necessity">Renovation is the mother of necessity</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5CZATxc8HsbQamB9K4HAUe" name="Copper Charlie cooktop" alt="Copper Charlie cooktop" src="https://cdn.mos.cms.futurecdn.net/5CZATxc8HsbQamB9K4HAUe-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I tested out the range in the Brooklyn apartment of Ted Booth, who switched from a traditional gas oven to the Copper about a year ago. At the time, his building was facing a million-dollar renovation bill to upgrade the ancient gas pipes leading into, and threading through, the entire 33-unit building.</p><p>Rather than forcing the entire building to front the cost of fixing each unit’s gas line, the condo board gave each owner an option to switch to an induction stove. However, most induction stoves require a 220-volt electric line — which would have meant an equally expensive bill. </p><p>But there was an alternative: the Copper induction stove. This range has a large battery in the bottom, where the warming tray would sit. Not only does this provide a steady source of energy, even when the power goes out, but it also allows the stove to use a regular 110-volt outlet, so you can plug it in almost anywhere. </p><p>“To me, it was an opportunity to get off gas,” Booth said. “And, you can call me a bit of an early adopter, so it appealed to me that way.”</p><h3 class="article-body__section" id="section-modern-but-retro"><span>Modern but retro</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="4NxvG2P32duYnS62Mc5dFJ" name="Copper Charlie knobs" alt="Copper Charlie knobs" src="https://cdn.mos.cms.futurecdn.net/4NxvG2P32duYnS62Mc5dFJ-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><div><blockquote><p>"It's the most analog experience I've had with a tech product"</p><p>— Ted Booth</p></blockquote></div><p>While the Charlie uses a very new type of technology, and has Wi-Fi and can be updated over the internet, it’s surprisingly low on connected features. </p><p>“I like how simple it is,” Booth said. “It's connected to the Wi-Fi, it has a battery, but it's the most analog experience I've had with a tech product. You have the little light indicator on the side, and the screen shows you what it's doing — it's 350 degrees. That's all you need to know. It's great.  And then the two little switches for the light and convection.”</p><h3 class="article-body__section" id="section-the-cost-of-upgrading"><span>The cost of upgrading</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4032px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="YtFxSHTSXqXwf62mnYZtBP" name="Copper Charlie oven open" alt="Copper Charlie oven open" src="https://cdn.mos.cms.futurecdn.net/YtFxSHTSXqXwf62mnYZtBP-1920-80.jpg" mos="" align="middle" fullscreen="" width="4032" height="2268" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The Copper Charlie isn’t cheap. The <a href="https://copperhome.com/products/charlie?variant=42413374079069" target="_blank">base model, with black plastic knobs, costs $6,000</a>, while the model with black walnut knobs is $6,300. That’s more than twice as expensive as some popular models from <a href="https://www.bestbuy.com/product/lg-30-in-wide-6-3-cu-ft-slide-in-electric-induction-true-convect-range-with-5-elements-instaview-and-flex-control-knobs-stainless-steel/J7G5658LSF"><u>LG</u></a> and GE — though it should be noted the GE Cafe series can get up to $5,000. </p><p>The Charlie is not Energy Star-certified, so you can’t get any government rebates from that program, but there are several other local clean energy tax credits that can help ease the cost.</p><p>However, it did get the seal of approval from the New York City Housing Authority, which is installing <a href="https://www.nytimes.com/2026/01/16/nyregion/induction-stoves-housing-authority.html"><u>100 Copper Charlie stoves in apartments</u></a> throughout the city as a pilot program for lower-income residents, as all city-owned apartment buildings get converted from gas to electric.</p><p>“There are so many families that haven't had the ability to cook for years because they had their utility to get the gas shut off,” said Lisa Pickney, a professional chef who created the Official Dessert of the 1996 Atlanta Olympics, served on the Obama White House culinary team, and now works for Copper. </p><p>“And so they just gave them a hot plate and a rice cooker and a teapot. And it's just not right. They can't make a Thanksgiving turkey. So that kind of broke my heart. And now they'll be able to have Thanksgiving and do proper cooking now.” </p><p>The Copper Charlie isn’t the only induction stove of its kind; a rival company, the <a href="https://www.tomsguide.com/home/home-appliances/i-tried-out-an-induction-stove-that-works-even-when-the-power-goes-out"><u>Electra Induction Stove</u></a>, works in much the same way. Rather than the lithium ion batteries you might find in your phone or electric scooter, these stoves use a lithium phosphate battery, which is more stable, and more suited for how it’s used with the stoves. </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OqREmX"></div>                            </div>                            <script src="https://kwizly.com/embed/OqREmX.js" async=""></script><h3 class="article-body__section" id="section-now-we-re-cooking"><span>Now we're cooking</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Cv4aYBK8AB99GeMZm3MFmU" name="Copper Charlie scallops" alt="searing scallops on the Copper Charlie" src="https://cdn.mos.cms.futurecdn.net/Cv4aYBK8AB99GeMZm3MFmU-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>As I (well, mostly Lisa) were cooking, I was impressed with how fast the oven heated up. While I didn’t time it, the Copper Charlie seemed far shorter than my oven at home. Similarly, its cooktop element warmed up the pan in no time, and put a sear on the scallops as good as I’ve ever done on any range, gas or electric.</p><p>Booth said that his cooking game has improved since getting the Charlie. “I like to make a Spanish potato omelet,” he said. “I like it because you can get a really nice, low temperature, so it doesn't brown too quickly. With the gas, I could get a low flame, but then the heat doesn't distribute quite as well, and so it's like cooking more in one spot and less on the edges.” </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:57.65%;"><img id="7in93fN4mpP8rnadB7BmuY" name="Copper Charlie chicken" alt="Chicken baked in the Copper Charlie" src="https://cdn.mos.cms.futurecdn.net/7in93fN4mpP8rnadB7BmuY-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1153" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Booth said he could no longer do the <a href="https://bittmanproject.com/recipe/seared-steak/" target="_blank">Mark Bittman trick of cooking a steak</a> by placing a pan on the very bottom of the oven, but the Charlie proved its worth when the outlet behind the stove stopped working. </p><p>“At first, I was like, what are we gonna do?” he said. “It's gonna take a while to get an electrician to come, and then I was like, oh, no, wait, it's fine. We have an outlet behind that cluster of little appliances in the corner is a four-prong outlet with a GFCI. So I just plugged it into that.”</p><p>“That to me really proved to me how much power this draws, because we've got an Instapot, we've got a kettle, we've got an espresso machine.  And we never had an issue, it never popped the GFCI.”</p><h3 class="article-body__section" id="section-how-it-s-working-out"><span>How it's working out</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="js4rQ6VnrMbiGjMoaYsBZ4" name="Copper Charlie induction range" alt="Copper Charlie induction range" src="https://cdn.mos.cms.futurecdn.net/js4rQ6VnrMbiGjMoaYsBZ4-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Ultimately, eleven owners in Booth’s building ended up getting a Copper Charlie. It proved to be more expensive than those who merely opted to replace their gas line, but Booth said it was worth the expense.</p><p>“We're gonna spend all this money for these pipes in the wall, and all I get is to get a blue flame?” he asks. ”I want something better than that.”</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/I-tried-an-induction-cooktop-3-things-i-learned">I used an induction cooktop for the first time — here are 3 things I learned</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/mistakes-i-made-when-i-switched-to-an-induction-cooktop-and-how-to-avoid-them">5 mistakes I made when I switched to an induction cooktop</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/we-tested-3-portable-induction-cooktops-at-wildly-different-prices-heres-our-verdict">We tested 3 portable induction cooktops from $50 to $1,500 </a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/kitchen-dining/i-put-a-battery-powered-induction-stove-to-the-test-heres-what-surprised-me</link>
                                                                            <description>
                            <![CDATA[ I tested the Copper Charlie, an induction range with a built-in battery, which makes it far easier to install — and even works when the power is out. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">DdYjBJKiUFNpyXNePiyb4A</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/g8TQNn5XqY4EknpbYVuy3n-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 31 Jul 2026 09:45:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Kitchen & Dining]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                <author><![CDATA[ mike.prospero@futurenet.com (Mike Prospero) ]]></author>                    <dc:creator><![CDATA[ Mike Prospero ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/xeJFBrJwXQzCqXLZXBFBKQ-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Michael A. Prospero is the U.S. Editor-in-Chief for Tom’s Guide.  In his spare time, he also tests out the latest drones, electric scooters, and smart home gadgets, such as video doorbells. Before his tenure at Tom&#039;s Guide, he was the Reviews Editor for Laptop Magazine, a reporter at Fast Company, the Times of Trenton, and, many eons back, an intern at George magazine. He received his undergraduate degree from Boston College, where he worked on the campus newspaper The Heights, and then attended the Columbia University school of Journalism. When he’s not testing out the latest running watch, electric scooter, or skiing or training for a marathon, he’s probably using the latest sous vide machine, smoker, or pizza oven, to the delight — or chagrin — of his family.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/g8TQNn5XqY4EknpbYVuy3n-1920-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Copper Charlie induction range]]></media:description>                                                            <media:text><![CDATA[Copper Charlie induction range]]></media:text>
                                <media:title type="plain"><![CDATA[Copper Charlie induction range]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/g8TQNn5XqY4EknpbYVuy3n-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The oil sizzled as I placed the scallops in the pan. On the counter next to me sat a tray of just-baked chocolate chip cookies, their aroma wafting through the air. In the oven, a tray of chicken thighs was slowly baking atop a mixture of Chinese vegetables, their juices infusing with the cabbage and boy choy beneath.</p><p>I was cooking it all on the Copper Charlie, an innovative induction stove that doesn’t require any special installation, thanks to a massive battery. And while it's an early adopter in the world of early adopters, it could represent the future of home appliances. </p><h2 id="renovation-is-the-mother-of-necessity">Renovation is the mother of necessity</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5CZATxc8HsbQamB9K4HAUe" name="Copper Charlie cooktop" alt="Copper Charlie cooktop" src="https://cdn.mos.cms.futurecdn.net/5CZATxc8HsbQamB9K4HAUe-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I tested out the range in the Brooklyn apartment of Ted Booth, who switched from a traditional gas oven to the Copper about a year ago. At the time, his building was facing a million-dollar renovation bill to upgrade the ancient gas pipes leading into, and threading through, the entire 33-unit building.</p><p>Rather than forcing the entire building to front the cost of fixing each unit’s gas line, the condo board gave each owner an option to switch to an induction stove. However, most induction stoves require a 220-volt electric line — which would have meant an equally expensive bill. </p><p>But there was an alternative: the Copper induction stove. This range has a large battery in the bottom, where the warming tray would sit. Not only does this provide a steady source of energy, even when the power goes out, but it also allows the stove to use a regular 110-volt outlet, so you can plug it in almost anywhere. </p><p>“To me, it was an opportunity to get off gas,” Booth said. “And, you can call me a bit of an early adopter, so it appealed to me that way.”</p><h3 class="article-body__section" id="section-modern-but-retro"><span>Modern but retro</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="4NxvG2P32duYnS62Mc5dFJ" name="Copper Charlie knobs" alt="Copper Charlie knobs" src="https://cdn.mos.cms.futurecdn.net/4NxvG2P32duYnS62Mc5dFJ-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><div><blockquote><p>"It's the most analog experience I've had with a tech product"</p><p>— Ted Booth</p></blockquote></div><p>While the Charlie uses a very new type of technology, and has Wi-Fi and can be updated over the internet, it’s surprisingly low on connected features. </p><p>“I like how simple it is,” Booth said. “It's connected to the Wi-Fi, it has a battery, but it's the most analog experience I've had with a tech product. You have the little light indicator on the side, and the screen shows you what it's doing — it's 350 degrees. That's all you need to know. It's great.  And then the two little switches for the light and convection.”</p><h3 class="article-body__section" id="section-the-cost-of-upgrading"><span>The cost of upgrading</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4032px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="YtFxSHTSXqXwf62mnYZtBP" name="Copper Charlie oven open" alt="Copper Charlie oven open" src="https://cdn.mos.cms.futurecdn.net/YtFxSHTSXqXwf62mnYZtBP-1920-80.jpg" mos="" align="middle" fullscreen="" width="4032" height="2268" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The Copper Charlie isn’t cheap. The <a href="https://copperhome.com/products/charlie?variant=42413374079069" target="_blank">base model, with black plastic knobs, costs $6,000</a>, while the model with black walnut knobs is $6,300. That’s more than twice as expensive as some popular models from <a href="https://www.bestbuy.com/product/lg-30-in-wide-6-3-cu-ft-slide-in-electric-induction-true-convect-range-with-5-elements-instaview-and-flex-control-knobs-stainless-steel/J7G5658LSF"><u>LG</u></a> and GE — though it should be noted the GE Cafe series can get up to $5,000. </p><p>The Charlie is not Energy Star-certified, so you can’t get any government rebates from that program, but there are several other local clean energy tax credits that can help ease the cost.</p><p>However, it did get the seal of approval from the New York City Housing Authority, which is installing <a href="https://www.nytimes.com/2026/01/16/nyregion/induction-stoves-housing-authority.html"><u>100 Copper Charlie stoves in apartments</u></a> throughout the city as a pilot program for lower-income residents, as all city-owned apartment buildings get converted from gas to electric.</p><p>“There are so many families that haven't had the ability to cook for years because they had their utility to get the gas shut off,” said Lisa Pickney, a professional chef who created the Official Dessert of the 1996 Atlanta Olympics, served on the Obama White House culinary team, and now works for Copper. </p><p>“And so they just gave them a hot plate and a rice cooker and a teapot. And it's just not right. They can't make a Thanksgiving turkey. So that kind of broke my heart. And now they'll be able to have Thanksgiving and do proper cooking now.” </p><p>The Copper Charlie isn’t the only induction stove of its kind; a rival company, the <a href="https://www.tomsguide.com/home/home-appliances/i-tried-out-an-induction-stove-that-works-even-when-the-power-goes-out"><u>Electra Induction Stove</u></a>, works in much the same way. Rather than the lithium ion batteries you might find in your phone or electric scooter, these stoves use a lithium phosphate battery, which is more stable, and more suited for how it’s used with the stoves. </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OqREmX"></div>                            </div>                            <script src="https://kwizly.com/embed/OqREmX.js" async=""></script><h3 class="article-body__section" id="section-now-we-re-cooking"><span>Now we're cooking</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Cv4aYBK8AB99GeMZm3MFmU" name="Copper Charlie scallops" alt="searing scallops on the Copper Charlie" src="https://cdn.mos.cms.futurecdn.net/Cv4aYBK8AB99GeMZm3MFmU-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>As I (well, mostly Lisa) were cooking, I was impressed with how fast the oven heated up. While I didn’t time it, the Copper Charlie seemed far shorter than my oven at home. Similarly, its cooktop element warmed up the pan in no time, and put a sear on the scallops as good as I’ve ever done on any range, gas or electric.</p><p>Booth said that his cooking game has improved since getting the Charlie. “I like to make a Spanish potato omelet,” he said. “I like it because you can get a really nice, low temperature, so it doesn't brown too quickly. With the gas, I could get a low flame, but then the heat doesn't distribute quite as well, and so it's like cooking more in one spot and less on the edges.” </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:57.65%;"><img id="7in93fN4mpP8rnadB7BmuY" name="Copper Charlie chicken" alt="Chicken baked in the Copper Charlie" src="https://cdn.mos.cms.futurecdn.net/7in93fN4mpP8rnadB7BmuY-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1153" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Booth said he could no longer do the <a href="https://bittmanproject.com/recipe/seared-steak/" target="_blank">Mark Bittman trick of cooking a steak</a> by placing a pan on the very bottom of the oven, but the Charlie proved its worth when the outlet behind the stove stopped working. </p><p>“At first, I was like, what are we gonna do?” he said. “It's gonna take a while to get an electrician to come, and then I was like, oh, no, wait, it's fine. We have an outlet behind that cluster of little appliances in the corner is a four-prong outlet with a GFCI. So I just plugged it into that.”</p><p>“That to me really proved to me how much power this draws, because we've got an Instapot, we've got a kettle, we've got an espresso machine.  And we never had an issue, it never popped the GFCI.”</p><h3 class="article-body__section" id="section-how-it-s-working-out"><span>How it's working out</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="js4rQ6VnrMbiGjMoaYsBZ4" name="Copper Charlie induction range" alt="Copper Charlie induction range" src="https://cdn.mos.cms.futurecdn.net/js4rQ6VnrMbiGjMoaYsBZ4-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Ultimately, eleven owners in Booth’s building ended up getting a Copper Charlie. It proved to be more expensive than those who merely opted to replace their gas line, but Booth said it was worth the expense.</p><p>“We're gonna spend all this money for these pipes in the wall, and all I get is to get a blue flame?” he asks. ”I want something better than that.”</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/I-tried-an-induction-cooktop-3-things-i-learned">I used an induction cooktop for the first time — here are 3 things I learned</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/mistakes-i-made-when-i-switched-to-an-induction-cooktop-and-how-to-avoid-them">5 mistakes I made when I switched to an induction cooktop</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/we-tested-3-portable-induction-cooktops-at-wildly-different-prices-heres-our-verdict">We tested 3 portable induction cooktops from $50 to $1,500 </a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The US government just banned almost all robot vacuums — here's why (Update: companies respond) ]]></title>
                                                                                                <dc:content><![CDATA[ <p>If you've been watching the news, you may have seen the Trump administration's recent robotic ban. In a move by the Federal Communications Commission (FCC), the ban targets any new foreign-made <em>humanoid</em> robot imports to the U.S. The thinking is that these products may cause "unacceptable risks" to U.S. security.</p><p>But humanoid robots <strong>aren't the only robots at risk</strong>. It turns out the ban spreads much further than you might think. Far enough to spell trouble for the kind of 'bots you may be using in your own home.</p><p>Delve a little deeper into the <a href="https://www.fcc.gov/document/fcc-adds-foreign-produced-power-inverters-and-robots-covered-list-0" target="_blank">FCC's definition,</a> and you're looking at a <strong>much larger coverage of robots that fall under the term "advanced robotic devices"</strong>.  </p><p>If they're <strong>"capable of locomotion, obstacle avoidance, navigation, or movement on the ground"</strong> then they're targeted under the new ban. Sounds a lot like robotic lawnmowers, the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuums</a> or even your friendly neighborhood delivery robot, right? Exactly.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-exVMmO"></div>                            </div>                            <script src="https://kwizly.com/embed/exVMmO.js" async=""></script><h2 id="no-more-roombas">No more Roombas?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1393px;"><p class="vanilla-image-block" style="padding-top:56.07%;"><img id="pAsxEDhyFTzycwLvC2whue" name="Roomba S9+" alt="Roomba S9+" src="https://cdn.mos.cms.futurecdn.net/pAsxEDhyFTzycwLvC2whue-1920-80.jpg" mos="" align="middle" fullscreen="" width="1393" height="781" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: iRobot)</span></figcaption></figure><div><blockquote><p>Any new 'advanced robotic devices' being imported are banned, which essentially means any robots manufactured outside of the U.S.</p></blockquote></div><p>Now, it's worth delving into exactly what this means for home and delivery robots that fall under the FCC's definition. </p><p>Importantly, any existing robots previously authorised to be sold in the U.S. are safe. Equally, any robots that have already been imported from outside of the U.S., are currently being sold, or have been approved are also safe.</p><p>But any new "advanced robotic devices" being imported, which essentially means any robots being manufactured outside of the U.S., are banned.</p><p>This includes robots where "the combined weight of the device and, if applicable, ground station or docking station is over 4.4 lbs", as well as any with "software running either locally or remotely, including firmware and AI or machine-learning model weights" and "a sensor capable of perceiving its environment" or "a component that is capable of providing network connectivity (wired or wireless, including Bluetooth/Wi-Fi, cellular, or satellite)".</p><p>Why? Well, as the <a href="https://docs.fcc.gov/public/attachments/DA-26-786A1.pdf" target="_blank">FCC</a> has said, they consider these robots to pose a national security risk, stating: "foreign-produced advanced robotic devices could be weaponized to directly harm U.S. national security and U.S. persons". </p><p>But what's <em>really</em> interesting is what it's demanding companies do instead.</p><h2 id="safety-concerns">Safety concerns?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:11396px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="rUzUSbtwusZspBvdY3vZn7" name="Roborock-Hero" alt="The Roborock Saros Z70 picking up a shoe" src="https://cdn.mos.cms.futurecdn.net/rUzUSbtwusZspBvdY3vZn7-1920-80.jpg" mos="" align="middle" fullscreen="" width="11396" height="6410" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Roborock)</span></figcaption></figure><p>A lot of companies like Roomba, Ecovacs, Dreame, Roborock and more source manufacturing from China. Moving forward, they'll need to acquire waivers to continue to manufacture and sell these advanced robotic devices in the US. But, <a href="https://www.theverge.com/policy/972312/us-robot-ban-sweep-up-chinese-vacuums" target="_blank">The Verge</a> revealed the FCC doesn't want to ask any questions about actual security.</p><p>Instead, the site reports: "The FCC only wants to know <em>where </em>they're designed and made and assembled and tested and influenced, and get a specific commitment to start manufacturing them in the U.S. instead."</p><p>So, for now, existing robots in the U.S. are safe. You won't have to hand over your much-loved robot vacuum to security. But it's a <em>huge</em> deal for the companies making them. Any new models will need a waiver to be manufactured elsewhere, and if they can't get the waiver, then they won't be getting sold in the U.S. </p><p>If you were on the fence about picking up one of the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuums</a> or a robotic lawnmower, you might want to act sooner rather than later.</p><div class="product"><a data-dimension112="1f140922-8c09-11f1-a386-33dcaf7c427a" data-action="Deal Block" data-label="Q7 L5" data-dimension48="Q7 L5" data-dimension25="$139" href="https://www.amazon.com/roborock-Q7-Anti-Tangle-Multi-Level-Self-Charging/dp/B0F334DN9J" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="nTwuXCqZHGt7dBQq8jHrt4" name="Roborock Q7 M5 robot vacuum" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/nTwuXCqZHGt7dBQq8jHrt4-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Q7 L5 tackles everyday cleaning with ease, pulling out dust deep from carpets. Plus, its rugged wheels and bouncy suspension mean it's great at climbing over cables and handling uneven floors.<a class="view-deal button" href="https://www.amazon.com/roborock-Q7-Anti-Tangle-Multi-Level-Self-Charging/dp/B0F334DN9J" target="_blank" rel="nofollow" data-dimension112="1f140922-8c09-11f1-a386-33dcaf7c427a" data-action="Deal Block" data-label="Q7 L5" data-dimension48="Q7 L5" data-dimension25="$139">View Deal</a></p></div><h2 id="cta-responds">CTA responds</h2><p>The Consumer Technology Association, the organization behind CES, also issued a measured response on X in a series of posts. </p><div class="see-more see-more--clipped"><figure><blockquote class="twitter-tweet hawk-ignore" data-lang="en" cite="https://twitter.com/cantworkitout/status/2082853441462841735"><p lang="en" dir="ltr">At CES 2026, robotics took center stage. Innovation in this space is accelerating fast, and the U.S. must lead the world in developing and deploying these technologies. 🧵<a href="https://twitter.com/cantworkitout/status/2082853441462841735">July 30, 2026</a></p></blockquote></figure><div class="see-more__filter"></div></div><p>"At CES 2026, robotics took center stage. Innovation in this space is accelerating fast, and the U.S. must lead the world in developing and deploying these technologies."</p><p>"CTA supports efforts to protect our national security and strengthen technology supply chains. But those policies should be targeted, transparent and focused on genuine security risks, not unnecessary costs or supply chain disruption."</p><p>"The global race in robotics is on. CTA looks forward to working with the Administration to ensure America leads the world in robotics and the next generation of emerging technologies."</p><p>"We encourage continued engagement between industry and government to ensure policies advance trusted supply chains while preserving innovation, competition and consumer access to new technologies."</p><h2 id="companies-respond">Companies respond</h2><p>We reached out to a number of companies following the FCC's announcement. Here's what they had to say. </p><p><strong>Anker Innovations</strong></p><p>"We are aware of the FCC’s recent update. Based on our current understanding, the new rule does not affect the continued availability, use or support of products we currently sell in the United States. Those products remain available and will continue to receive updates and customer support.</p><p>"Like others across the industry, we are seeking further clarity on how the rule will be applied to future products, and we will keep our customers informed. We remain committed to complying with all regulatory requirements in every market where we operate."</p><p><strong>Dreame</strong></p><p>"We are currently reviewing and assessing the details of the recent announcement," a spokesperson said. "Dreame has always been committed to strict compliance with all local laws and regulatory requirements in every market where we operate globally."</p><p><strong>iRobot (makers of Roomba)</strong></p><p>"We are aware of the FCC's recent action and are working with them to better understand its implementation and potential impact. We remain committed to serving our customers and will share updates as more information becomes available."</p><p><strong>Segway Navimow</strong></p><p>"We are aware of the FCC’s announcement regarding restrictions to advanced robotic devices. There is no immediate impact to existing Navimow customers, as all Navimow models currently sold in the US have already received FCC equipment authorization. The ban does not affect the sales, service, or continued use of existing products. We are closely monitoring policy developments and evaluating compliance pathways for future products, including the Department of Defense's "Conditional Approval" process."</p><p><strong>SharkNinja</strong></p><p>“Our Shark robot vacuums currently sold in the U.S. will continue to be available for sale, use and support," a SharkNinja spokesperson said. "Regarding future models, we are evaluating our best options, but as a U.S.-based company we believe we are well positioned to navigate the process to continue to launch new models at competitive prices as we always have. We are closely monitoring developments and evaluating next steps as more information becomes available. We remain committed to serving our consumers and keeping them informed.”</p><p>What do you think of the ban? Let us know in the comments.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/home-appliances/dji-romo-p-the-one-robot-vacuum-i-wish-was-coming-to-the-states-but-what-to-buy-instead">Here’s the one robot vacuum I wish was coming to the US (and what to buy instead)</a></li><li><a href="https://www.tomsguide.com/best-picks/best-cheap-robot-vacuums">The 4 best cheap robot vacuums you can buy in 2026</a></li><li><a href="https://www.tomsguide.com/home/im-a-robot-vacuum-expert-and-after-seeing-this-vacuum-that-can-climb-over-obstacles-its-the-only-feature-i-care-about">I’m a robot vacuum expert, and after seeing this vacuum that can climb over obstacles, it’s the only feature I care about</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/smart-home/the-us-government-just-banned-almost-all-robot-vacuums-heres-why</link>
                                                                            <description>
                            <![CDATA[ The US government has announced a ban on "advanced robotic devices" entering the US. That means robot vacuums, robot lawnmowers and delivery robots on the ground are all under threat. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">yGyrPpxCVTbMkGtBiieWxT</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/WWbMLEt9LxVc2AR2drEipF-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 30 Jul 2026 11:24:15 +0000</pubDate>                                                                                                                                <updated>Wed, 05 Aug 2026 13:25:52 +0000</updated>
                                                                                                                                            <category><![CDATA[Smart Home]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/WWbMLEt9LxVc2AR2drEipF-1920-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[iRobot Roomba i3+ review]]></media:description>                                                            <media:text><![CDATA[iRobot Roomba i3+ review]]></media:text>
                                <media:title type="plain"><![CDATA[iRobot Roomba i3+ review]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/WWbMLEt9LxVc2AR2drEipF-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>If you've been watching the news, you may have seen the Trump administration's recent robotic ban. In a move by the Federal Communications Commission (FCC), the ban targets any new foreign-made <em>humanoid</em> robot imports to the U.S. The thinking is that these products may cause "unacceptable risks" to U.S. security.</p><p>But humanoid robots <strong>aren't the only robots at risk</strong>. It turns out the ban spreads much further than you might think. Far enough to spell trouble for the kind of 'bots you may be using in your own home.</p><p>Delve a little deeper into the <a href="https://www.fcc.gov/document/fcc-adds-foreign-produced-power-inverters-and-robots-covered-list-0" target="_blank">FCC's definition,</a> and you're looking at a <strong>much larger coverage of robots that fall under the term "advanced robotic devices"</strong>.  </p><p>If they're <strong>"capable of locomotion, obstacle avoidance, navigation, or movement on the ground"</strong> then they're targeted under the new ban. Sounds a lot like robotic lawnmowers, the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuums</a> or even your friendly neighborhood delivery robot, right? Exactly.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-exVMmO"></div>                            </div>                            <script src="https://kwizly.com/embed/exVMmO.js" async=""></script><h2 id="no-more-roombas">No more Roombas?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1393px;"><p class="vanilla-image-block" style="padding-top:56.07%;"><img id="pAsxEDhyFTzycwLvC2whue" name="Roomba S9+" alt="Roomba S9+" src="https://cdn.mos.cms.futurecdn.net/pAsxEDhyFTzycwLvC2whue-1920-80.jpg" mos="" align="middle" fullscreen="" width="1393" height="781" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: iRobot)</span></figcaption></figure><div><blockquote><p>Any new 'advanced robotic devices' being imported are banned, which essentially means any robots manufactured outside of the U.S.</p></blockquote></div><p>Now, it's worth delving into exactly what this means for home and delivery robots that fall under the FCC's definition. </p><p>Importantly, any existing robots previously authorised to be sold in the U.S. are safe. Equally, any robots that have already been imported from outside of the U.S., are currently being sold, or have been approved are also safe.</p><p>But any new "advanced robotic devices" being imported, which essentially means any robots being manufactured outside of the U.S., are banned.</p><p>This includes robots where "the combined weight of the device and, if applicable, ground station or docking station is over 4.4 lbs", as well as any with "software running either locally or remotely, including firmware and AI or machine-learning model weights" and "a sensor capable of perceiving its environment" or "a component that is capable of providing network connectivity (wired or wireless, including Bluetooth/Wi-Fi, cellular, or satellite)".</p><p>Why? Well, as the <a href="https://docs.fcc.gov/public/attachments/DA-26-786A1.pdf" target="_blank">FCC</a> has said, they consider these robots to pose a national security risk, stating: "foreign-produced advanced robotic devices could be weaponized to directly harm U.S. national security and U.S. persons". </p><p>But what's <em>really</em> interesting is what it's demanding companies do instead.</p><h2 id="safety-concerns">Safety concerns?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:11396px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="rUzUSbtwusZspBvdY3vZn7" name="Roborock-Hero" alt="The Roborock Saros Z70 picking up a shoe" src="https://cdn.mos.cms.futurecdn.net/rUzUSbtwusZspBvdY3vZn7-1920-80.jpg" mos="" align="middle" fullscreen="" width="11396" height="6410" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Roborock)</span></figcaption></figure><p>A lot of companies like Roomba, Ecovacs, Dreame, Roborock and more source manufacturing from China. Moving forward, they'll need to acquire waivers to continue to manufacture and sell these advanced robotic devices in the US. But, <a href="https://www.theverge.com/policy/972312/us-robot-ban-sweep-up-chinese-vacuums" target="_blank">The Verge</a> revealed the FCC doesn't want to ask any questions about actual security.</p><p>Instead, the site reports: "The FCC only wants to know <em>where </em>they're designed and made and assembled and tested and influenced, and get a specific commitment to start manufacturing them in the U.S. instead."</p><p>So, for now, existing robots in the U.S. are safe. You won't have to hand over your much-loved robot vacuum to security. But it's a <em>huge</em> deal for the companies making them. Any new models will need a waiver to be manufactured elsewhere, and if they can't get the waiver, then they won't be getting sold in the U.S. </p><p>If you were on the fence about picking up one of the <a href="https://www.tomsguide.com/us/best-robot-vacuums,review-2000.html">best robot vacuums</a> or a robotic lawnmower, you might want to act sooner rather than later.</p><div class="product"><a data-dimension112="1f140922-8c09-11f1-a386-33dcaf7c427a" data-action="Deal Block" data-label="Q7 L5" data-dimension48="Q7 L5" data-dimension25="$139" href="https://www.amazon.com/roborock-Q7-Anti-Tangle-Multi-Level-Self-Charging/dp/B0F334DN9J" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="nTwuXCqZHGt7dBQq8jHrt4" name="Roborock Q7 M5 robot vacuum" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/nTwuXCqZHGt7dBQq8jHrt4-1920-80.jpg" mos="" align="middle" fullscreen="" width="1500" height="1500" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Q7 L5 tackles everyday cleaning with ease, pulling out dust deep from carpets. Plus, its rugged wheels and bouncy suspension mean it's great at climbing over cables and handling uneven floors.<a class="view-deal button" href="https://www.amazon.com/roborock-Q7-Anti-Tangle-Multi-Level-Self-Charging/dp/B0F334DN9J" target="_blank" rel="nofollow" data-dimension112="1f140922-8c09-11f1-a386-33dcaf7c427a" data-action="Deal Block" data-label="Q7 L5" data-dimension48="Q7 L5" data-dimension25="$139">View Deal</a></p></div><h2 id="cta-responds">CTA responds</h2><p>The Consumer Technology Association, the organization behind CES, also issued a measured response on X in a series of posts. </p><div class="see-more see-more--clipped"><figure><blockquote class="twitter-tweet hawk-ignore" data-lang="en" cite="https://twitter.com/cantworkitout/status/2082853441462841735"><p lang="en" dir="ltr">At CES 2026, robotics took center stage. Innovation in this space is accelerating fast, and the U.S. must lead the world in developing and deploying these technologies. 🧵<a href="https://twitter.com/cantworkitout/status/2082853441462841735">July 30, 2026</a></p></blockquote></figure><div class="see-more__filter"></div></div><p>"At CES 2026, robotics took center stage. Innovation in this space is accelerating fast, and the U.S. must lead the world in developing and deploying these technologies."</p><p>"CTA supports efforts to protect our national security and strengthen technology supply chains. But those policies should be targeted, transparent and focused on genuine security risks, not unnecessary costs or supply chain disruption."</p><p>"The global race in robotics is on. CTA looks forward to working with the Administration to ensure America leads the world in robotics and the next generation of emerging technologies."</p><p>"We encourage continued engagement between industry and government to ensure policies advance trusted supply chains while preserving innovation, competition and consumer access to new technologies."</p><h2 id="companies-respond">Companies respond</h2><p>We reached out to a number of companies following the FCC's announcement. Here's what they had to say. </p><p><strong>Anker Innovations</strong></p><p>"We are aware of the FCC’s recent update. Based on our current understanding, the new rule does not affect the continued availability, use or support of products we currently sell in the United States. Those products remain available and will continue to receive updates and customer support.</p><p>"Like others across the industry, we are seeking further clarity on how the rule will be applied to future products, and we will keep our customers informed. We remain committed to complying with all regulatory requirements in every market where we operate."</p><p><strong>Dreame</strong></p><p>"We are currently reviewing and assessing the details of the recent announcement," a spokesperson said. "Dreame has always been committed to strict compliance with all local laws and regulatory requirements in every market where we operate globally."</p><p><strong>iRobot (makers of Roomba)</strong></p><p>"We are aware of the FCC's recent action and are working with them to better understand its implementation and potential impact. We remain committed to serving our customers and will share updates as more information becomes available."</p><p><strong>Segway Navimow</strong></p><p>"We are aware of the FCC’s announcement regarding restrictions to advanced robotic devices. There is no immediate impact to existing Navimow customers, as all Navimow models currently sold in the US have already received FCC equipment authorization. The ban does not affect the sales, service, or continued use of existing products. We are closely monitoring policy developments and evaluating compliance pathways for future products, including the Department of Defense's "Conditional Approval" process."</p><p><strong>SharkNinja</strong></p><p>“Our Shark robot vacuums currently sold in the U.S. will continue to be available for sale, use and support," a SharkNinja spokesperson said. "Regarding future models, we are evaluating our best options, but as a U.S.-based company we believe we are well positioned to navigate the process to continue to launch new models at competitive prices as we always have. We are closely monitoring developments and evaluating next steps as more information becomes available. We remain committed to serving our consumers and keeping them informed.”</p><p>What do you think of the ban? Let us know in the comments.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/home-appliances/dji-romo-p-the-one-robot-vacuum-i-wish-was-coming-to-the-states-but-what-to-buy-instead">Here’s the one robot vacuum I wish was coming to the US (and what to buy instead)</a></li><li><a href="https://www.tomsguide.com/best-picks/best-cheap-robot-vacuums">The 4 best cheap robot vacuums you can buy in 2026</a></li><li><a href="https://www.tomsguide.com/home/im-a-robot-vacuum-expert-and-after-seeing-this-vacuum-that-can-climb-over-obstacles-its-the-only-feature-i-care-about">I’m a robot vacuum expert, and after seeing this vacuum that can climb over obstacles, it’s the only feature I care about</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Furnishing a bedroom? I did the math on prices at IKEA, Lowe's and Home Depot to find out which is the winner — the result may surprise you ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Whether I'm planning a redesign or I've got a new room that needs fully furnishing, I always tend to shop in the same place – IKEA. </p><p>The blue and yellow allure and modular designs have continuously and cleverly been sold to me as the most budget-friendly option for an entire collection of furniture. But, is that <em>actually</em> the case?</p><p>Don't get me wrong, I know there's other options. In fact, the market has largely been dominated for decades by two juggernaut home retailers – Lowe's and Home Depot. </p><p>How do they hold up against IKEA though? I sometimes struggle to find clarity in which is the more affordable choice. </p><p>So, I thought I'd put it to the ultimate test. I mocked up a complete bedroom design and found similar items across IKEA, Lowes and Home Depot to compare the prices. </p><p><em>Spoiler alert</em>: you might be shocked by the results.</p><h3 class="article-body__section" id="section-different-stores-different-lures"><span>Different stores, different lures</span></h3><h2 id="pros-and-cons-of-ikea">Pros and cons of IKEA</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="qg5Z6rnAaTsHSyK9TWXmTN" name="IKEA-LEDE-1" alt="An closeup exterior shot of an IKEA store." src="https://cdn.mos.cms.futurecdn.net/qg5Z6rnAaTsHSyK9TWXmTN-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Pros:</p><ul><li>Competitively priced</li><li>Unique, space-friendly designs</li><li>Lots of stock</li><li>Ease of collection</li></ul><p>Cons:</p><ul><li>Build-it-yourself flat packs</li><li>Potentially expensive shipping costs</li><li>Less than 100 stores in the US</li></ul><h2 id="pros-and-cons-of-lowe-s">Pros and cons of Lowe's</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="S8S9NkUQkYzUcgFJrwWqZJ" name="Lowes Black Friday deals.jpg" alt="Lowe's Black Friday deals" src="https://cdn.mos.cms.futurecdn.net/S8S9NkUQkYzUcgFJrwWqZJ-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Pros:</p><ul><li>Price match guarantee</li><li>Stock diverse and exclusive range of brands</li><li>Over 1700 stores across US</li></ul><p>Cons:</p><ul><li>Less stock</li><li>Strict discounts</li><li>Less choice</li></ul><h2 id="pros-and-cons-of-home-depot">Pros and cons of Home Depot</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="6Lg2GZBcp9nKsL2dVWWfyY" name="Home Depot sales.jpg" alt="Home Depot Father's Day sales" src="https://cdn.mos.cms.futurecdn.net/6Lg2GZBcp9nKsL2dVWWfyY-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Pros:</p><ul><li>Extensive range of brands</li><li>Lots of stock</li><li>Over 2000 stores in the US</li></ul><p>Cons:</p><ul><li>Concerns over delivery</li><li>Not as affordable</li><li>Warehouses overwhelmingly large</li></ul><h3 class="article-body__section" id="section-cost-comparison"><span>Cost comparison</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3953px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="9cQxyWJdEMZynYWzhH8YrY" name="bedroom crop.jpg" alt="Bedroom" src="https://cdn.mos.cms.futurecdn.net/9cQxyWJdEMZynYWzhH8YrY-1920-80.jpg" mos="" align="middle" fullscreen="" width="3953" height="2224" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Bedroom </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>To carry out this cost comparison, I set out to find items from each store that looked incredibly similar. Of course, if you're planning a different aesthetic, you can shop around and compare all three. </p><p>But to fully furnish a bedroom with a bed, wardrobe, dresser, and nightstand, here's what the costs had to say.</p><div ><table><caption>IKEA vs Lowes vs Home Depot bedroom decor price comparison</caption><tbody><tr><td class="firstcol " ><p><strong>Retailer</strong></p></td><td  ><p><strong>IKEA</strong></p></td><td  ><p><strong>Lowes</strong></p></td><td  ><p><strong>Home Depot</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Bed</strong></p></td><td  ><p><a href="https://www.ikea.com/us/en/p/stjaernoe-bed-frame-anthracite-40570183/" target="_blank" rel="nofollow">STJÄRNÖ bed frame, Anthracite (Queen) </a></p><p>$229</p></td><td  ><p><a href="https://www.lowes.com/pd/Mondawe-Black-Queen-Metal-Bed-Frame/5015675731" target="_blank" rel="nofollow">Mondawe bed frame, Black metal (Queen)</a></p><p>$209</p></td><td  ><p><a href="https://www.homedepot.com/p/VECELO-Queen-Bed-Frame-with-Headboard-Heavy-Duty-Platform-Bed-Frame-No-Box-Spring-Needed-Under-Bed-Storage-Space-60-9-in-W-KHD-BTJ-MBQ08-BLK/321699841" target="_blank" rel="nofollow">VECELO bed frame, Black metal (Queen)</a></p><p>$232.20</p></td></tr><tr><td class="firstcol " ><p><strong>Wardrobe</strong></p></td><td  ><p><a href="https://www.ikea.com/us/en/p/brimnes-wardrobe-with-2-doors-white-30574799/" target="_blank" rel="nofollow">BRIMNES wardrobe, White</a></p><p>$199.99</p></td><td  ><p><a href="https://www.homedepot.com/p/FUFU-GAGA-White-Wood-31-5-in-Armoire-with-Metal-Hanging-Rod-and-6-Shelves-Modern-2-Door-Wardrobe-Closet-with-Storage-ZJ-JQ210085-01/340677403" target="_blank" rel="nofollow">FUFU&amp;GAGA wardrobe, White</a></p><p>$217.41</p></td><td  ><p><a href="https://www.homedepot.com/p/FUFU-GAGA-White-2-Doors-Armoire-Wardrobe-with-Hanging-Rod-and-Storage-Shelves-71-in-H-x-31-5-in-W-x-15-7-in-D-WFKF210085-01-xin/319500117" target="_blank" rel="nofollow">FUFU&amp;GAGA wardrobe, White</a></p><p>$235.10</p></td></tr><tr><td class="firstcol " ><p><strong>Dresser</strong></p></td><td  ><p><a href="https://www.ikea.com/us/en/p/storklinta-6-drawer-dresser-white-anchor-unlock-function-60561248/" target="_blank" rel="nofollow">STORKLINTA 6-drawer dresser, White</a></p><p>$249.99</p></td><td  ><p><a href="https://www.lowes.com/pd/FUFU-GAGA-6-drawer-dresser/5014112857" target="_blank" rel="nofollow">FUFU&amp;GAGA 6-drawer dresser, White</a></p><p>$229</p></td><td  ><p><a href="https://www.homedepot.com/p/FUFU-GAGA-15-7-in-D-x-32-3-in-H-6-Drawers-White-Wood-59-in-W-Dresser-Organizer-KF200151-01-c/325597761" target="_blank" rel="nofollow">FUFU&amp;GAGA 6-drawer dresser, White</a></p><p>$265.72</p></td></tr><tr><td class="firstcol " ><p><strong>Nightstand</strong></p></td><td  ><p><a href="https://www.ikea.com/us/en/p/hemnes-2-drawer-chest-white-stain-80242627/" target="_blank" rel="nofollow">HEMNES nightstand, White</a></p><p>$149.99</p></td><td  ><p><a href="https://www.lowes.com/pd/Signature-Design-by-Ashley-Fortman-White-Nightstand/7160884" target="_blank" rel="nofollow">Fortman nightstand, White</a></p><p>$209.99</p></td><td  ><p><a href="https://www.homedepot.com/p/Signature-DESIGN-BY-ASHLEY-Fortman-White-2-Drawer-25-in-W-Nightstands-B680-92/334069739" target="_blank" rel="nofollow">Fortman nightstand, White</a></p><p>$190.41</p></td></tr><tr><td class="firstcol " ><p><strong>Total cost</strong></p></td><td  ><p>$828.97</p></td><td  ><p><strong>$865.40</strong></p></td><td  ><p><strong>$923.43</strong></p></td></tr></tbody></table></div><p>It's also important to note that there can be additional costs when purchasing online, especially with delivery (varies dependent on location), but also including some potential extra costs for fittings, removal and storage fees.</p><h3 class="article-body__section" id="section-verdict"><span>Verdict</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="6uG29Mi4idZCcpWqKP8EF7" name="IKEA store.shutterstock_1942005295 (1)" alt="IKEA storefront sign" src="https://cdn.mos.cms.futurecdn.net/6uG29Mi4idZCcpWqKP8EF7-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>So, it turns out while IKEA is still the most affordable during this price comparison, it's not by as far as I would have thought. </p><p>For Lowe's, it's less than a $40 difference. Home Depot is considered widely to be the more premium priced of the three, but still only came in around $60 more than Lowe's. </p><p>What was surprising about Home Depot though, was that three of the items chosen were the same product as Lowe's, yet more expensive. </p><p>I did also notice that some of Lowe's and Home Depot's prices changed a little during my comparison, whereas IKEA tends to stick to their prices (unless during a sales event).</p><p>Yes, IKEA is still the most affordable, but there are other things to consider, like delivery costs to you and accessibility to stores. It wasn't the total washout that I was expecting from IKEA, especially as far as Lowe's is concerned. </p><p>I know that when I make up a mood board for my next redesign, I'll be creating the look across all three retailers rather than assuming that I know the answer.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-O92wpX"></div>                            </div>                            <script src="https://kwizly.com/embed/O92wpX.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/ikeas-new-collection-is-designed-for-frequent-movers-im-excited-about-how-portable-and-affordable-it-is">IKEA's new collection is designed for frequent movers — I'm excited about how portable and affordable it is</a></li><li><a href="https://www.tomsguide.com/home/5-ways-to-update-your-bedroom-without-a-complete-revamp">5 ways to update your bedroom without a complete revamp</a></li><li><a href="https://www.tomsguide.com/home/how-to-create-a-show-home-aesthetic-7-interior-tips-to-try">How to create a show home aesthetic — 7 interior tips to try</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/furnishing-a-bedroom-i-did-the-math-on-prices-at-ikea-lowes-and-home-depot-to-find-out-which-is-the-winner-the-result-may-surprise-you</link>
                                                                            <description>
                            <![CDATA[ Whenever I do a refurb, I turn to IKEA for its budget-friendly and easy-to-buy options. But, what if I shopped around at Lowe's and Home Depot? I put it to the test on a bedroom redesign. Here's what happened. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">eqeX4VbCinBEmE8m8mLhx4</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ra6FuG3hhbUqMCvjkBD444-1920-80.png" type="image/png" length="0"></enclosure>
                                                                        <pubDate>Thu, 30 Jul 2026 05:45:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/png" url="https://cdn.mos.cms.futurecdn.net/ra6FuG3hhbUqMCvjkBD444-1920-80.png">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Retail stores lead image]]></media:description>                                                            <media:text><![CDATA[Retail stores lead image]]></media:text>
                                <media:title type="plain"><![CDATA[Retail stores lead image]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ra6FuG3hhbUqMCvjkBD444-1920-80.png" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Whether I'm planning a redesign or I've got a new room that needs fully furnishing, I always tend to shop in the same place – IKEA. </p><p>The blue and yellow allure and modular designs have continuously and cleverly been sold to me as the most budget-friendly option for an entire collection of furniture. But, is that <em>actually</em> the case?</p><p>Don't get me wrong, I know there's other options. In fact, the market has largely been dominated for decades by two juggernaut home retailers – Lowe's and Home Depot. </p><p>How do they hold up against IKEA though? I sometimes struggle to find clarity in which is the more affordable choice. </p><p>So, I thought I'd put it to the ultimate test. I mocked up a complete bedroom design and found similar items across IKEA, Lowes and Home Depot to compare the prices. </p><p><em>Spoiler alert</em>: you might be shocked by the results.</p><h3 class="article-body__section" id="section-different-stores-different-lures"><span>Different stores, different lures</span></h3><h2 id="pros-and-cons-of-ikea">Pros and cons of IKEA</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="qg5Z6rnAaTsHSyK9TWXmTN" name="IKEA-LEDE-1" alt="An closeup exterior shot of an IKEA store." src="https://cdn.mos.cms.futurecdn.net/qg5Z6rnAaTsHSyK9TWXmTN-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Pros:</p><ul><li>Competitively priced</li><li>Unique, space-friendly designs</li><li>Lots of stock</li><li>Ease of collection</li></ul><p>Cons:</p><ul><li>Build-it-yourself flat packs</li><li>Potentially expensive shipping costs</li><li>Less than 100 stores in the US</li></ul><h2 id="pros-and-cons-of-lowe-s">Pros and cons of Lowe's</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="S8S9NkUQkYzUcgFJrwWqZJ" name="Lowes Black Friday deals.jpg" alt="Lowe's Black Friday deals" src="https://cdn.mos.cms.futurecdn.net/S8S9NkUQkYzUcgFJrwWqZJ-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Pros:</p><ul><li>Price match guarantee</li><li>Stock diverse and exclusive range of brands</li><li>Over 1700 stores across US</li></ul><p>Cons:</p><ul><li>Less stock</li><li>Strict discounts</li><li>Less choice</li></ul><h2 id="pros-and-cons-of-home-depot">Pros and cons of Home Depot</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="6Lg2GZBcp9nKsL2dVWWfyY" name="Home Depot sales.jpg" alt="Home Depot Father's Day sales" src="https://cdn.mos.cms.futurecdn.net/6Lg2GZBcp9nKsL2dVWWfyY-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>Pros:</p><ul><li>Extensive range of brands</li><li>Lots of stock</li><li>Over 2000 stores in the US</li></ul><p>Cons:</p><ul><li>Concerns over delivery</li><li>Not as affordable</li><li>Warehouses overwhelmingly large</li></ul><h3 class="article-body__section" id="section-cost-comparison"><span>Cost comparison</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3953px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="9cQxyWJdEMZynYWzhH8YrY" name="bedroom crop.jpg" alt="Bedroom" src="https://cdn.mos.cms.futurecdn.net/9cQxyWJdEMZynYWzhH8YrY-1920-80.jpg" mos="" align="middle" fullscreen="" width="3953" height="2224" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Bedroom </span><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>To carry out this cost comparison, I set out to find items from each store that looked incredibly similar. Of course, if you're planning a different aesthetic, you can shop around and compare all three. </p><p>But to fully furnish a bedroom with a bed, wardrobe, dresser, and nightstand, here's what the costs had to say.</p><div ><table><caption>IKEA vs Lowes vs Home Depot bedroom decor price comparison</caption><tbody><tr><td class="firstcol " ><p><strong>Retailer</strong></p></td><td  ><p><strong>IKEA</strong></p></td><td  ><p><strong>Lowes</strong></p></td><td  ><p><strong>Home Depot</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Bed</strong></p></td><td  ><p><a href="https://www.ikea.com/us/en/p/stjaernoe-bed-frame-anthracite-40570183/" target="_blank" rel="nofollow">STJÄRNÖ bed frame, Anthracite (Queen) </a></p><p>$229</p></td><td  ><p><a href="https://www.lowes.com/pd/Mondawe-Black-Queen-Metal-Bed-Frame/5015675731" target="_blank" rel="nofollow">Mondawe bed frame, Black metal (Queen)</a></p><p>$209</p></td><td  ><p><a href="https://www.homedepot.com/p/VECELO-Queen-Bed-Frame-with-Headboard-Heavy-Duty-Platform-Bed-Frame-No-Box-Spring-Needed-Under-Bed-Storage-Space-60-9-in-W-KHD-BTJ-MBQ08-BLK/321699841" target="_blank" rel="nofollow">VECELO bed frame, Black metal (Queen)</a></p><p>$232.20</p></td></tr><tr><td class="firstcol " ><p><strong>Wardrobe</strong></p></td><td  ><p><a href="https://www.ikea.com/us/en/p/brimnes-wardrobe-with-2-doors-white-30574799/" target="_blank" rel="nofollow">BRIMNES wardrobe, White</a></p><p>$199.99</p></td><td  ><p><a href="https://www.homedepot.com/p/FUFU-GAGA-White-Wood-31-5-in-Armoire-with-Metal-Hanging-Rod-and-6-Shelves-Modern-2-Door-Wardrobe-Closet-with-Storage-ZJ-JQ210085-01/340677403" target="_blank" rel="nofollow">FUFU&amp;GAGA wardrobe, White</a></p><p>$217.41</p></td><td  ><p><a href="https://www.homedepot.com/p/FUFU-GAGA-White-2-Doors-Armoire-Wardrobe-with-Hanging-Rod-and-Storage-Shelves-71-in-H-x-31-5-in-W-x-15-7-in-D-WFKF210085-01-xin/319500117" target="_blank" rel="nofollow">FUFU&amp;GAGA wardrobe, White</a></p><p>$235.10</p></td></tr><tr><td class="firstcol " ><p><strong>Dresser</strong></p></td><td  ><p><a href="https://www.ikea.com/us/en/p/storklinta-6-drawer-dresser-white-anchor-unlock-function-60561248/" target="_blank" rel="nofollow">STORKLINTA 6-drawer dresser, White</a></p><p>$249.99</p></td><td  ><p><a href="https://www.lowes.com/pd/FUFU-GAGA-6-drawer-dresser/5014112857" target="_blank" rel="nofollow">FUFU&amp;GAGA 6-drawer dresser, White</a></p><p>$229</p></td><td  ><p><a href="https://www.homedepot.com/p/FUFU-GAGA-15-7-in-D-x-32-3-in-H-6-Drawers-White-Wood-59-in-W-Dresser-Organizer-KF200151-01-c/325597761" target="_blank" rel="nofollow">FUFU&amp;GAGA 6-drawer dresser, White</a></p><p>$265.72</p></td></tr><tr><td class="firstcol " ><p><strong>Nightstand</strong></p></td><td  ><p><a href="https://www.ikea.com/us/en/p/hemnes-2-drawer-chest-white-stain-80242627/" target="_blank" rel="nofollow">HEMNES nightstand, White</a></p><p>$149.99</p></td><td  ><p><a href="https://www.lowes.com/pd/Signature-Design-by-Ashley-Fortman-White-Nightstand/7160884" target="_blank" rel="nofollow">Fortman nightstand, White</a></p><p>$209.99</p></td><td  ><p><a href="https://www.homedepot.com/p/Signature-DESIGN-BY-ASHLEY-Fortman-White-2-Drawer-25-in-W-Nightstands-B680-92/334069739" target="_blank" rel="nofollow">Fortman nightstand, White</a></p><p>$190.41</p></td></tr><tr><td class="firstcol " ><p><strong>Total cost</strong></p></td><td  ><p>$828.97</p></td><td  ><p><strong>$865.40</strong></p></td><td  ><p><strong>$923.43</strong></p></td></tr></tbody></table></div><p>It's also important to note that there can be additional costs when purchasing online, especially with delivery (varies dependent on location), but also including some potential extra costs for fittings, removal and storage fees.</p><h3 class="article-body__section" id="section-verdict"><span>Verdict</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="6uG29Mi4idZCcpWqKP8EF7" name="IKEA store.shutterstock_1942005295 (1)" alt="IKEA storefront sign" src="https://cdn.mos.cms.futurecdn.net/6uG29Mi4idZCcpWqKP8EF7-1920-80.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Shutterstock)</span></figcaption></figure><p>So, it turns out while IKEA is still the most affordable during this price comparison, it's not by as far as I would have thought. </p><p>For Lowe's, it's less than a $40 difference. Home Depot is considered widely to be the more premium priced of the three, but still only came in around $60 more than Lowe's. </p><p>What was surprising about Home Depot though, was that three of the items chosen were the same product as Lowe's, yet more expensive. </p><p>I did also notice that some of Lowe's and Home Depot's prices changed a little during my comparison, whereas IKEA tends to stick to their prices (unless during a sales event).</p><p>Yes, IKEA is still the most affordable, but there are other things to consider, like delivery costs to you and accessibility to stores. It wasn't the total washout that I was expecting from IKEA, especially as far as Lowe's is concerned. </p><p>I know that when I make up a mood board for my next redesign, I'll be creating the look across all three retailers rather than assuming that I know the answer.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-O92wpX"></div>                            </div>                            <script src="https://kwizly.com/embed/O92wpX.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/ikeas-new-collection-is-designed-for-frequent-movers-im-excited-about-how-portable-and-affordable-it-is">IKEA's new collection is designed for frequent movers — I'm excited about how portable and affordable it is</a></li><li><a href="https://www.tomsguide.com/home/5-ways-to-update-your-bedroom-without-a-complete-revamp">5 ways to update your bedroom without a complete revamp</a></li><li><a href="https://www.tomsguide.com/home/how-to-create-a-show-home-aesthetic-7-interior-tips-to-try">How to create a show home aesthetic — 7 interior tips to try</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I mixed the exact same smoothie in a $30 blender and a $129 one — here's my verdict ]]></title>
                                                                                                <dc:content><![CDATA[ <p>At the start of the year, I <a href="https://www.tomsguide.com/home/kitchen-dining/i-upgraded-my-usd30-budget-blender-to-a-nutribullet-and-its-made-smoothies-fun-again">upgraded our household blender</a> from a regular non-brand contraption we picked up at the local Aldi to a <a href="https://www.tomsguide.com/home/home-appliances/nutribullet-ultra-1200-personal-blender-review">Nutribullet Ultra 1200. </a>The benefits were that it was easier to clean, looked a lot nicer, and blends your ingredients straight into the shaker you can drink from.</p><p>Over six months later, I decided to return to the pair of them (we haven't got rid of the old one; it's good to have a spare) to put a little bit more testing on the table.</p><p>Part of this, I admit, is due to selfishly wanting to mix up my smoothie game. I'm guilty of going back to the same old recipe time and time again and, with summer here, I'm feeling the need for a change. </p><p>Secondly, although I swapped to the Nutribullet without a second thought — was I giving my old blender its due? What if I fed both machines the <em>exact same ingredients</em> and measured them directly in a head-to-head? Which would really come out on top?</p><p>There are a ton of things the Nutribullet does better: it's objectively smaller, lighter, simpler to use <em>and</em> comes with a better warranty. But I was surprised at a couple of outcomes from this experiment if I'm being totally honest. I'll spoil the big one for you now: <strong>I couldn't tell the difference when it came to tasting the final product</strong>.</p><p>But we're getting ahead of ourselves. Read on to discover just what I found out from my budget vs. premium experiment.</p>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@tomsguide/video/7667954816726895886" data-video-id="7667954816726895886" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@tomsguide" href="https://www.tiktok.com/@tomsguide">@tomsguide</a>                            <p></p><a target="_blank" title="♬ miffy cafe - sakuracloud" href="https://www.tiktok.com/music/miffy-cafe-7425305480727889936">♬ miffy cafe - sakuracloud</a></section>                    </blockquote></div>                <h3 class="article-body__section" id="section-the-recipe"><span>The recipe</span></h3><p>The wonderful thing about smoothies is they're uncomplicated. Pick stuff you like, throw it inside one of <a href="https://www.tomsguide.com/best-picks/best-blenders">the best blenders</a>, and chances are it'll come out alright. But this test had to be scientific, so here are the exact ingredients I used with both machines:</p><p><strong>100g strawberries </strong>(~1 cup, yields a thick texture and rich color)</p><p><strong>50g ripe banana</strong> (~1/2 medium banana, sliced)</p><p><strong>100g strawberry flavored Greek yogurt</strong> (~½ cup)</p><p><strong>180ml milk</strong> (~¾ cup)</p><p><strong>1 tbsp of honey</strong></p><p>Note that both of these machines are blenders and not bespoke juicers. Here's a <a href="https://www.tomsguide.com/news/juicer-vs-blender-what-is-the-differnce">complete rundown of the differences,</a> but in a nutshell, juicers squeeze and extract the juice from fruits and vegetables. A juicer breaks down the fruit by separating the pulp, peel/skin, and seeds from the fruit, as the juice flows out through a sieve. </p><p>Blenders, on the other hand, pulverize all of the ingredients together. Think of them as a sledgehammer rather than a scalpel.</p><h3 class="article-body__section" id="section-the-blend"><span>The blend</span></h3><p>Forget just throwing the above ingredients into the pot without a care. This is the process I followed with both blenders — just to make sure I did what I could to make the experiment fair.</p><ul><li><strong>Add liquids and soft ingredients first: </strong>Pour in the <strong>milk</strong> and spoon in the <strong>Greek yogurt</strong>. Placing liquid at the bottom helps the blender blades turn smoothly without getting stuck on the fruit.</li><li><strong>Layer in solids and the fruit: Next in went the</strong> <strong>banana slices</strong>, chopped <strong>strawberries</strong>, and finally I added the honey.</li><li><strong>Blend on high power for 30 seconds </strong>(I used my trusty Casio stopwatch to make sure they each got the same time)</li><li>Pour out and enjoy</li></ul><h3 class="article-body__section" id="section-the-result"><span>The result</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5712px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5rUCzNkPzywGJQtUU5KPJG" name="IMG_4627.JPG" alt="Two blenders with a glass each of smoothie" src="https://cdn.mos.cms.futurecdn.net/5rUCzNkPzywGJQtUU5KPJG-1920-80.jpg" mos="" align="middle" fullscreen="" width="5712" height="3213" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Not pictured: All the washing up that needed to be done after this experiment was complete </span><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide / Jeff Parsons)</span></figcaption></figure><p>I appreciate you can't <em>taste</em> the results of my experiment through the screen, but as I said at the outset. I didn't notice any difference in taste in the final product. If pressed, I would say the $129 result was a fractionally smoother than the cheaper alternative. Maybe my smoothie chops aren't what they used to be, but my takeaway is that if all you're interested in is the consistency and the taste of the final result, the cheap option will do you proud.</p><p>Also despite costing more and supposedly being quieter (Nutribullet says 87dB), the more expensive blender was louder than the budget one. It's more powerful 1,200W vs 600W and that showed when the noise level just crested 100dB for the Nutribullet compared to 99dB for the Blaupunkt. I know this is nitpicking, but I still wanted to mention it.</p><p>The Nutribullet uses a 6-point titanium-coated extractor blade rather than a 4-point one in the $30 Blaupunkt. But it's also got a lower capacity (32oz vs 52oz), so if you're mixing smoothies for a family or to batch, that may play a factor. Those two elements come in clutch because there were definitely some lumps left in the bottom of the jug on the cheaper blender when I poured out the drink.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4096px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ekPC5sugsCFx3xYSw2WPsF" name="Nutribullet Ultra 1200" alt="Nutribullet Ultra 1200 vs budget blender" src="https://cdn.mos.cms.futurecdn.net/ekPC5sugsCFx3xYSw2WPsF-1920-80.jpg" mos="" align="middle" fullscreen="" width="4096" height="2304" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Whereas I put the contents into a glass for the sake of this article, normally I would just cap off the Nutribullet shaker and be on my way. Similarly, I cranked the Blaupunkt all the way to five on its antiquated knob rather than the simple on/off capacitive touch of the Nutribullet. </p><p>And, last but by no means least, cleaning the Nutribullet was a simpler, quicker affair than my old budget blender.</p><p>So, both got the job done — one just did it with a little more style than the other.</p><h3 class="article-body__section" id="section-final-thoughts"><span>Final thoughts</span></h3><div class="product"><a data-dimension112="e59b75e6-8676-11f1-9acc-718a67d38a99" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="$124" href="https://www.amazon.com/gp/aw/d/B0CBWD3PN7" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1546px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="X2G4ud3wXRFEsYCZi8Hs9C" name="Nutribullet ultra" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/X2G4ud3wXRFEsYCZi8Hs9C-1920-80.jpg" mos="" align="middle" fullscreen="" width="1546" height="1546" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Nutribullet Ultra 1200 is a powerhouse of a blender boasting a 1200-watt motor, titanium-coated extractor blade and Tritan Renew cups (700ml and 900ml) that are both durable and sustainable. In Nutribullet's signature Gunmetal Grey, it's a sleek yet powerful combo that aims to deliver smoothies in just 30 seconds flat.<a class="view-deal button" href="https://www.amazon.com/gp/aw/d/B0CBWD3PN7" target="_blank" rel="nofollow" data-dimension112="e59b75e6-8676-11f1-9acc-718a67d38a99" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="$124">View Deal</a></p></div><div class="product"><a data-dimension112="e59b7640-8676-11f1-9b53-dd2c078d49e7" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="£129" href="https://www.amazon.co.uk/nutribullet-Ultra-1200W-Personal-Blender/dp/B0CSDWRT8N" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1546px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="X2G4ud3wXRFEsYCZi8Hs9C" name="Nutribullet ultra" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/X2G4ud3wXRFEsYCZi8Hs9C-1920-80.jpg" mos="" align="middle" fullscreen="" width="1546" height="1546" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.co.uk/nutribullet-Ultra-1200W-Personal-Blender/dp/B0CSDWRT8N" target="_blank" rel="nofollow" data-dimension112="e59b7640-8676-11f1-9b53-dd2c078d49e7" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="£129">Ultra: £129</a></strong><br />This product is also available in the U.K. where it's currently sitting at full price. During sales events, however, it can drop down to under £100 so it may be worth adding to your wishlist and keeping an eye on it.<a class="view-deal button" href="https://www.amazon.co.uk/nutribullet-Ultra-1200W-Personal-Blender/dp/B0CSDWRT8N" target="_blank" rel="nofollow" data-dimension112="e59b7640-8676-11f1-9b53-dd2c078d49e7" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="£129">View Deal</a></p></div><p>This little experiment has reinforced what I felt about leveling up blenders back at the start of the year. When it comes to the nuts and bolts of the taste of the final product, there's no difference — at least for someone with my unrefined palate.</p><p>Moreover, I can put up with a bit of noise for 30 seconds, so the fact my Nutribullet was louder than advertised is also something I can overlook.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4096px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WLz7mEum8qLNUquUQUJUrF" name="Nutribullet Ultra 1200" alt="Nutribullet Ultra 1200 vs budget blender" src="https://cdn.mos.cms.futurecdn.net/WLz7mEum8qLNUquUQUJUrF-1920-80.jpg" mos="" align="middle" fullscreen="" width="4096" height="2304" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>But, all the other aspects of using a blender were far superior with the more expensive model. I like that: <strong>a) it takes up less countertop space, b) it doesn't take as long to clean, c) it comes with a dedicated shaker for less fuss c) it genuinely just looks cooler and d) if it breaks, I can claim on the warranty for longer.</strong></p><p>Are those advantages worth $100 more? For my current lifestyle: yes. If you'd have asked me years ago when I was a student watching every dime I spent, then probably no.</p><p>The lesson I learned here was that despite our constant fixation on the end result, there's more to choosing a product than what it delivers. Less destination, more journey. </p><p>Of course, what works for me might not work for you. I happen to value how easy and quick the Nutribullet is to use so that makes the extra $100 worth it. Do you agree or not? Let me know in the comments below.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XZKP2e"></div>                            </div>                            <script src="https://kwizly.com/embed/XZKP2e.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/news/masticating-vs-centrifugal-juicer-which-is-best">Masticating vs centrifugal juicer: Which is best?</a></li><li><a href="https://www.tomsguide.com/best-picks/best-blenders">This is the best blender in the world, and two trusty, cheaper alternatives</a></li><li><a href="https://www.tomsguide.com/news/juicer-vs-blender-what-is-the-differnce">Juicer vs Blender: What's the difference?</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/kitchen-dining/i-mixed-the-exact-same-smoothie-in-a-usd30-blender-and-a-usd129-one-i-learned-a-valuable-lesson-in-the-process</link>
                                                                            <description>
                            <![CDATA[ After upgrading my blender at the start of the year, I felt it was time for a head-to-head test on which was better. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">iZB5DiXnxdDdR3sBqhSfri</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/bosNuKcBn37ynDukz8DqZm-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 29 Jul 2026 05:30:00 +0000</pubDate>                                                                                                                                <updated>Wed, 29 Jul 2026 14:23:23 +0000</updated>
                                                                                                                                            <category><![CDATA[Kitchen & Dining]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Home Appliances]]></category>
                                                                                                <author><![CDATA[ jeff.parsons@futurenet.com (Jeff Parsons) ]]></author>                    <dc:creator><![CDATA[ Jeff Parsons ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/7z3UTGGrmSokMKxTWHmhjX-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Jeff is U.K. Editor-in-Chief for Tom’s Guide looking after the day-to-day output of the site’s British contingent. &lt;/p&gt;&lt;p&gt;Rising early and heading straight for the coffee machine, Jeff loves nothing more than dialling into the zeitgeist of the day’s tech news. A journalist for over a decade, he&#039;s travelled around the world testing and reviewing any gadget he can get his hands on.&lt;/p&gt;&lt;p&gt;Before joining the team at Tom’s Guide, Jeff covered technology and science for two of the U.K.’s biggest national news sites: Metro.co.uk and the Daily Mirror. Memorable moments include getting lost in Vienna in an electric Audi, touring Lockheed Martin’s mile-long jet factory in Fort Worth and filming a Netflix documentary about Elon Musk in West London.&lt;/p&gt;&lt;p&gt;When not plugged into the current news agenda, editing or commissioning a series of articles or debating the merits of Apple vs Android, Jeff can usually be found out for a run trying to shave precious seconds off his PB. Or lifting weights in a vain attempt to offset the ageing process.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/bosNuKcBn37ynDukz8DqZm-1920-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[I mixed the exact same smoothie in a $30 blender and a $129 one]]></media:description>                                                            <media:text><![CDATA[I mixed the exact same smoothie in a $30 blender and a $129 one]]></media:text>
                                <media:title type="plain"><![CDATA[I mixed the exact same smoothie in a $30 blender and a $129 one]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/bosNuKcBn37ynDukz8DqZm-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>At the start of the year, I <a href="https://www.tomsguide.com/home/kitchen-dining/i-upgraded-my-usd30-budget-blender-to-a-nutribullet-and-its-made-smoothies-fun-again">upgraded our household blender</a> from a regular non-brand contraption we picked up at the local Aldi to a <a href="https://www.tomsguide.com/home/home-appliances/nutribullet-ultra-1200-personal-blender-review">Nutribullet Ultra 1200. </a>The benefits were that it was easier to clean, looked a lot nicer, and blends your ingredients straight into the shaker you can drink from.</p><p>Over six months later, I decided to return to the pair of them (we haven't got rid of the old one; it's good to have a spare) to put a little bit more testing on the table.</p><p>Part of this, I admit, is due to selfishly wanting to mix up my smoothie game. I'm guilty of going back to the same old recipe time and time again and, with summer here, I'm feeling the need for a change. </p><p>Secondly, although I swapped to the Nutribullet without a second thought — was I giving my old blender its due? What if I fed both machines the <em>exact same ingredients</em> and measured them directly in a head-to-head? Which would really come out on top?</p><p>There are a ton of things the Nutribullet does better: it's objectively smaller, lighter, simpler to use <em>and</em> comes with a better warranty. But I was surprised at a couple of outcomes from this experiment if I'm being totally honest. I'll spoil the big one for you now: <strong>I couldn't tell the difference when it came to tasting the final product</strong>.</p><p>But we're getting ahead of ourselves. Read on to discover just what I found out from my budget vs. premium experiment.</p>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@tomsguide/video/7667954816726895886" data-video-id="7667954816726895886" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@tomsguide" href="https://www.tiktok.com/@tomsguide">@tomsguide</a>                            <p></p><a target="_blank" title="♬ miffy cafe - sakuracloud" href="https://www.tiktok.com/music/miffy-cafe-7425305480727889936">♬ miffy cafe - sakuracloud</a></section>                    </blockquote></div>                <h3 class="article-body__section" id="section-the-recipe"><span>The recipe</span></h3><p>The wonderful thing about smoothies is they're uncomplicated. Pick stuff you like, throw it inside one of <a href="https://www.tomsguide.com/best-picks/best-blenders">the best blenders</a>, and chances are it'll come out alright. But this test had to be scientific, so here are the exact ingredients I used with both machines:</p><p><strong>100g strawberries </strong>(~1 cup, yields a thick texture and rich color)</p><p><strong>50g ripe banana</strong> (~1/2 medium banana, sliced)</p><p><strong>100g strawberry flavored Greek yogurt</strong> (~½ cup)</p><p><strong>180ml milk</strong> (~¾ cup)</p><p><strong>1 tbsp of honey</strong></p><p>Note that both of these machines are blenders and not bespoke juicers. Here's a <a href="https://www.tomsguide.com/news/juicer-vs-blender-what-is-the-differnce">complete rundown of the differences,</a> but in a nutshell, juicers squeeze and extract the juice from fruits and vegetables. A juicer breaks down the fruit by separating the pulp, peel/skin, and seeds from the fruit, as the juice flows out through a sieve. </p><p>Blenders, on the other hand, pulverize all of the ingredients together. Think of them as a sledgehammer rather than a scalpel.</p><h3 class="article-body__section" id="section-the-blend"><span>The blend</span></h3><p>Forget just throwing the above ingredients into the pot without a care. This is the process I followed with both blenders — just to make sure I did what I could to make the experiment fair.</p><ul><li><strong>Add liquids and soft ingredients first: </strong>Pour in the <strong>milk</strong> and spoon in the <strong>Greek yogurt</strong>. Placing liquid at the bottom helps the blender blades turn smoothly without getting stuck on the fruit.</li><li><strong>Layer in solids and the fruit: Next in went the</strong> <strong>banana slices</strong>, chopped <strong>strawberries</strong>, and finally I added the honey.</li><li><strong>Blend on high power for 30 seconds </strong>(I used my trusty Casio stopwatch to make sure they each got the same time)</li><li>Pour out and enjoy</li></ul><h3 class="article-body__section" id="section-the-result"><span>The result</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5712px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5rUCzNkPzywGJQtUU5KPJG" name="IMG_4627.JPG" alt="Two blenders with a glass each of smoothie" src="https://cdn.mos.cms.futurecdn.net/5rUCzNkPzywGJQtUU5KPJG-1920-80.jpg" mos="" align="middle" fullscreen="" width="5712" height="3213" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Not pictured: All the washing up that needed to be done after this experiment was complete </span><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide / Jeff Parsons)</span></figcaption></figure><p>I appreciate you can't <em>taste</em> the results of my experiment through the screen, but as I said at the outset. I didn't notice any difference in taste in the final product. If pressed, I would say the $129 result was a fractionally smoother than the cheaper alternative. Maybe my smoothie chops aren't what they used to be, but my takeaway is that if all you're interested in is the consistency and the taste of the final result, the cheap option will do you proud.</p><p>Also despite costing more and supposedly being quieter (Nutribullet says 87dB), the more expensive blender was louder than the budget one. It's more powerful 1,200W vs 600W and that showed when the noise level just crested 100dB for the Nutribullet compared to 99dB for the Blaupunkt. I know this is nitpicking, but I still wanted to mention it.</p><p>The Nutribullet uses a 6-point titanium-coated extractor blade rather than a 4-point one in the $30 Blaupunkt. But it's also got a lower capacity (32oz vs 52oz), so if you're mixing smoothies for a family or to batch, that may play a factor. Those two elements come in clutch because there were definitely some lumps left in the bottom of the jug on the cheaper blender when I poured out the drink.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4096px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ekPC5sugsCFx3xYSw2WPsF" name="Nutribullet Ultra 1200" alt="Nutribullet Ultra 1200 vs budget blender" src="https://cdn.mos.cms.futurecdn.net/ekPC5sugsCFx3xYSw2WPsF-1920-80.jpg" mos="" align="middle" fullscreen="" width="4096" height="2304" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Whereas I put the contents into a glass for the sake of this article, normally I would just cap off the Nutribullet shaker and be on my way. Similarly, I cranked the Blaupunkt all the way to five on its antiquated knob rather than the simple on/off capacitive touch of the Nutribullet. </p><p>And, last but by no means least, cleaning the Nutribullet was a simpler, quicker affair than my old budget blender.</p><p>So, both got the job done — one just did it with a little more style than the other.</p><h3 class="article-body__section" id="section-final-thoughts"><span>Final thoughts</span></h3><div class="product"><a data-dimension112="e59b75e6-8676-11f1-9acc-718a67d38a99" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="$124" href="https://www.amazon.com/gp/aw/d/B0CBWD3PN7" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1546px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="X2G4ud3wXRFEsYCZi8Hs9C" name="Nutribullet ultra" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/X2G4ud3wXRFEsYCZi8Hs9C-1920-80.jpg" mos="" align="middle" fullscreen="" width="1546" height="1546" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p>The Nutribullet Ultra 1200 is a powerhouse of a blender boasting a 1200-watt motor, titanium-coated extractor blade and Tritan Renew cups (700ml and 900ml) that are both durable and sustainable. In Nutribullet's signature Gunmetal Grey, it's a sleek yet powerful combo that aims to deliver smoothies in just 30 seconds flat.<a class="view-deal button" href="https://www.amazon.com/gp/aw/d/B0CBWD3PN7" target="_blank" rel="nofollow" data-dimension112="e59b75e6-8676-11f1-9acc-718a67d38a99" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="$124">View Deal</a></p></div><div class="product"><a data-dimension112="e59b7640-8676-11f1-9b53-dd2c078d49e7" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="£129" href="https://www.amazon.co.uk/nutribullet-Ultra-1200W-Personal-Blender/dp/B0CSDWRT8N" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1546px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="X2G4ud3wXRFEsYCZi8Hs9C" name="Nutribullet ultra" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/X2G4ud3wXRFEsYCZi8Hs9C-1920-80.jpg" mos="" align="middle" fullscreen="" width="1546" height="1546" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.co.uk/nutribullet-Ultra-1200W-Personal-Blender/dp/B0CSDWRT8N" target="_blank" rel="nofollow" data-dimension112="e59b7640-8676-11f1-9b53-dd2c078d49e7" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="£129">Ultra: £129</a></strong><br />This product is also available in the U.K. where it's currently sitting at full price. During sales events, however, it can drop down to under £100 so it may be worth adding to your wishlist and keeping an eye on it.<a class="view-deal button" href="https://www.amazon.co.uk/nutribullet-Ultra-1200W-Personal-Blender/dp/B0CSDWRT8N" target="_blank" rel="nofollow" data-dimension112="e59b7640-8676-11f1-9b53-dd2c078d49e7" data-action="Deal Block" data-label="Ultra" data-dimension48="Ultra" data-dimension25="£129">View Deal</a></p></div><p>This little experiment has reinforced what I felt about leveling up blenders back at the start of the year. When it comes to the nuts and bolts of the taste of the final product, there's no difference — at least for someone with my unrefined palate.</p><p>Moreover, I can put up with a bit of noise for 30 seconds, so the fact my Nutribullet was louder than advertised is also something I can overlook.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4096px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WLz7mEum8qLNUquUQUJUrF" name="Nutribullet Ultra 1200" alt="Nutribullet Ultra 1200 vs budget blender" src="https://cdn.mos.cms.futurecdn.net/WLz7mEum8qLNUquUQUJUrF-1920-80.jpg" mos="" align="middle" fullscreen="" width="4096" height="2304" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>But, all the other aspects of using a blender were far superior with the more expensive model. I like that: <strong>a) it takes up less countertop space, b) it doesn't take as long to clean, c) it comes with a dedicated shaker for less fuss c) it genuinely just looks cooler and d) if it breaks, I can claim on the warranty for longer.</strong></p><p>Are those advantages worth $100 more? For my current lifestyle: yes. If you'd have asked me years ago when I was a student watching every dime I spent, then probably no.</p><p>The lesson I learned here was that despite our constant fixation on the end result, there's more to choosing a product than what it delivers. Less destination, more journey. </p><p>Of course, what works for me might not work for you. I happen to value how easy and quick the Nutribullet is to use so that makes the extra $100 worth it. Do you agree or not? Let me know in the comments below.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XZKP2e"></div>                            </div>                            <script src="https://kwizly.com/embed/XZKP2e.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/news/masticating-vs-centrifugal-juicer-which-is-best">Masticating vs centrifugal juicer: Which is best?</a></li><li><a href="https://www.tomsguide.com/best-picks/best-blenders">This is the best blender in the world, and two trusty, cheaper alternatives</a></li><li><a href="https://www.tomsguide.com/news/juicer-vs-blender-what-is-the-differnce">Juicer vs Blender: What's the difference?</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I'm married to a plumber — here are 3 costly mistakes you could be making right now ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Whenever I tell people my husband is a plumber, they usually say: "That must be so handy!" And I always agree, yes, it absolutely is. </p><p>Whenever there's a plumbing (or heating) problem in my house, he knows how to solve it, and we don't have to spend extra money doing it or calling an emergency plumber late at night. </p><p>But instead of gatekeeping his secrets, I thought I'd ask him to share three of his favorite expert-approved tips that he thinks will help anyone in their home, so you can avoid making common plumbing mistakes.</p><p>Trust me, I should know if they work, because I literally use all three of them whenever needed. Here's some expert advice (free of charge) that'll hopefully even save you money in the future. </p><p>Just be sure to stick around for all three; I've saved my favorite until last.</p><h2 id="1-don-t-pour-hot-oil-down-your-sink">1. Don't pour hot oil down your sink</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="P8jFdp6K88rhckcBhSQ7Ac" name="hot_oil_hack" alt="Foil in a bowl for hot oil disposal" src="https://cdn.mos.cms.futurecdn.net/P8jFdp6K88rhckcBhSQ7Ac-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Foil in a bowl for hot oil disposal </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Excess oil that you've been cooking with seems like a pretty reasonable thing to pour down your sink when you've finished with it. After all, it's greasy, runny, and edible. But <em>don't do it</em>. </p><p>As my plumber husband explains: "While hot oil is liquid when it's been heated up, once it cools down it sets hard. If you have an incorrect fall on your waste pipe, this oil can sit stationary inside it, leading to blockages. </p><p>"The best solution is to pour your hot oil into a foil-lined bowl, leave it to set, and then throw the foil directly into the trash once it has [congealed]."</p><h2 id="2-don-t-put-bleach-tablets-in-toilet-tanks">2. Don't put bleach tablets in toilet tanks</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="RuuL9W3k2nub5ZnWyrMH6c" name="cistern_hack_2" alt="Checking the tank on a toilet" src="https://cdn.mos.cms.futurecdn.net/RuuL9W3k2nub5ZnWyrMH6c-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Checking the cistern on a toilet </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Bleach tablets are my go-to for tackling limescale and germs in my toilets at home, but my husband always tells me that I shouldn't use them regularly and I certainly shouldn't be putting them into the tank of the toilet. </p><p>The thought hadn't crossed my mind, but he says it's quite a common mistake that people tend to make: "A bleach tablet has high concentrations of chlorine. This can cause internal parts of the [tank] to fail, leading to leaks and damage to your toilet's components."</p><p>So, while you think you may be cleaning your toilet thoroughly, you could actually be doing more harm than good, which can become quite a costly mistake. Just stick to popping them into the bowl.</p><div class="product"><a data-dimension112="69bd9a08-88ec-11f1-a376-1b13d887de96" data-action="Deal Block" data-label="30-Pack Toilet Bowl Cleaning Tablets" data-dimension48="30-Pack Toilet Bowl Cleaning Tablets" data-dimension25="$19.99" href="https://www.amazon.com/Vacplus-Toilet-Bowl-Cleaners-Automatical-Cleaning/dp/B09SZ7F5FY" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="ukgP3AyXvqKNWwJYKs825E" name="bleach_tablets_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ukgP3AyXvqKNWwJYKs825E-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Vacplus-Toilet-Bowl-Cleaners-Automatical-Cleaning/dp/B09SZ7F5FY" target="_blank" rel="nofollow" data-dimension112="69bd9a08-88ec-11f1-a376-1b13d887de96" data-action="Deal Block" data-label="30-Pack Toilet Bowl Cleaning Tablets" data-dimension48="30-Pack Toilet Bowl Cleaning Tablets" data-dimension25="$19.99">30-Pack Toilet Bowl Cleaning Tablets: was $22.99 now $19.99</a></strong><br />In order for bleach cleaning tablets to work, they contain powerful bleaching ingredients which are great for tackling stubborn stains, but not great if you put them in your cistern. The sustained release will work wonders on your toilet, as long as you follow my husband plumber's helpful tip.<a class="view-deal button" href="https://www.amazon.com/Vacplus-Toilet-Bowl-Cleaners-Automatical-Cleaning/dp/B09SZ7F5FY" target="_blank" rel="nofollow" data-dimension112="69bd9a08-88ec-11f1-a376-1b13d887de96" data-action="Deal Block" data-label="30-Pack Toilet Bowl Cleaning Tablets" data-dimension48="30-Pack Toilet Bowl Cleaning Tablets" data-dimension25="$19.99">View Deal</a></p></div><h2 id="3-draw-a-pencil-line-around-damp-spots">3. Draw a pencil line around damp spots</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="MNmqKrgC9eakdpxzvgrFAc" name="pencil_hack" alt="Drawing a pencil line around a damp patch on the ceiling" src="https://cdn.mos.cms.futurecdn.net/MNmqKrgC9eakdpxzvgrFAc-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Drawing a pencil line around a damp patch on the ceiling </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Now, this one's my favorite, and it's one of those hacks you wonder why you didn't think of it yourself. </p><p>Whenever you spot a damp patch or stain in your home, here's what my plumber husband recommends: "I advise customers that if they notice a mark on their ceiling (most commonly), they should trace the outline with a pencil."</p><p>Why? Well, he adds: "If you leave it for 12 hours and come back, you'll see if the leak has gone past the pencil line. If it has, then you know you have an active leak." </p><p>And since a pencil is harmless to your ceiling, you can leave it a little longer to be extra sure or rub it away when you're fully satisfied that the leak has stopped.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XponGO"></div>                            </div>                            <script src="https://kwizly.com/embed/XponGO.js" async=""></script><p>Do you have any tips for saving money when it comes to plumbing? Let us know in the comments.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/this-tiktok-hack-claims-vinegar-will-clean-your-shower-head-i-asked-my-plumber-husband-if-it-actually-works">This TikTok hack claims vinegar will clean your shower head — I asked my plumber husband if it actually works</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/people-are-using-dish-soap-to-break-down-drain-blockages-i-asked-a-plumber-if-its-a-good-idea">You asked: Can dish soap fix your clogged drain? A plumber explains the facts</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/households-urged-not-to-pour-boiling-water-down-drains-this-winter-i-asked-a-plumber-what-to-do-instead">Households urged not to pour boiling water down drains this winter — I asked a plumber what to do instead</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/my-husbands-a-plumber-and-these-are-the-3-expert-approved-tips-he-says-every-homeowner-should-know</link>
                                                                            <description>
                            <![CDATA[ Having a plumber for a husband is super handy, and to share the wealth. I asked him for his top expert-approved tips to help avoid common household mistakes. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">5eZgfGpidynCjv68Hb4KQY</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/KRHRWF4jQrrQc2GWgtvNGj-1920-80.png" type="image/png" length="0"></enclosure>
                                                                        <pubDate>Tue, 28 Jul 2026 05:00:00 +0000</pubDate>                                                                                                                                <updated>Tue, 28 Jul 2026 11:11:09 +0000</updated>
                                                                                                                                            <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/png" url="https://cdn.mos.cms.futurecdn.net/KRHRWF4jQrrQc2GWgtvNGj-1920-80.png">
                                                            <media:credit><![CDATA[Shutterstock and Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Plumber at work under a sink]]></media:description>                                                            <media:text><![CDATA[Plumber at work under a sink]]></media:text>
                                <media:title type="plain"><![CDATA[Plumber at work under a sink]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/KRHRWF4jQrrQc2GWgtvNGj-1920-80.png" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Whenever I tell people my husband is a plumber, they usually say: "That must be so handy!" And I always agree, yes, it absolutely is. </p><p>Whenever there's a plumbing (or heating) problem in my house, he knows how to solve it, and we don't have to spend extra money doing it or calling an emergency plumber late at night. </p><p>But instead of gatekeeping his secrets, I thought I'd ask him to share three of his favorite expert-approved tips that he thinks will help anyone in their home, so you can avoid making common plumbing mistakes.</p><p>Trust me, I should know if they work, because I literally use all three of them whenever needed. Here's some expert advice (free of charge) that'll hopefully even save you money in the future. </p><p>Just be sure to stick around for all three; I've saved my favorite until last.</p><h2 id="1-don-t-pour-hot-oil-down-your-sink">1. Don't pour hot oil down your sink</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="P8jFdp6K88rhckcBhSQ7Ac" name="hot_oil_hack" alt="Foil in a bowl for hot oil disposal" src="https://cdn.mos.cms.futurecdn.net/P8jFdp6K88rhckcBhSQ7Ac-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Foil in a bowl for hot oil disposal </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Excess oil that you've been cooking with seems like a pretty reasonable thing to pour down your sink when you've finished with it. After all, it's greasy, runny, and edible. But <em>don't do it</em>. </p><p>As my plumber husband explains: "While hot oil is liquid when it's been heated up, once it cools down it sets hard. If you have an incorrect fall on your waste pipe, this oil can sit stationary inside it, leading to blockages. </p><p>"The best solution is to pour your hot oil into a foil-lined bowl, leave it to set, and then throw the foil directly into the trash once it has [congealed]."</p><h2 id="2-don-t-put-bleach-tablets-in-toilet-tanks">2. Don't put bleach tablets in toilet tanks</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="RuuL9W3k2nub5ZnWyrMH6c" name="cistern_hack_2" alt="Checking the tank on a toilet" src="https://cdn.mos.cms.futurecdn.net/RuuL9W3k2nub5ZnWyrMH6c-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Checking the cistern on a toilet </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Bleach tablets are my go-to for tackling limescale and germs in my toilets at home, but my husband always tells me that I shouldn't use them regularly and I certainly shouldn't be putting them into the tank of the toilet. </p><p>The thought hadn't crossed my mind, but he says it's quite a common mistake that people tend to make: "A bleach tablet has high concentrations of chlorine. This can cause internal parts of the [tank] to fail, leading to leaks and damage to your toilet's components."</p><p>So, while you think you may be cleaning your toilet thoroughly, you could actually be doing more harm than good, which can become quite a costly mistake. Just stick to popping them into the bowl.</p><div class="product"><a data-dimension112="69bd9a08-88ec-11f1-a376-1b13d887de96" data-action="Deal Block" data-label="30-Pack Toilet Bowl Cleaning Tablets" data-dimension48="30-Pack Toilet Bowl Cleaning Tablets" data-dimension25="$19.99" href="https://www.amazon.com/Vacplus-Toilet-Bowl-Cleaners-Automatical-Cleaning/dp/B09SZ7F5FY" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="ukgP3AyXvqKNWwJYKs825E" name="bleach_tablets_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ukgP3AyXvqKNWwJYKs825E-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Vacplus-Toilet-Bowl-Cleaners-Automatical-Cleaning/dp/B09SZ7F5FY" target="_blank" rel="nofollow" data-dimension112="69bd9a08-88ec-11f1-a376-1b13d887de96" data-action="Deal Block" data-label="30-Pack Toilet Bowl Cleaning Tablets" data-dimension48="30-Pack Toilet Bowl Cleaning Tablets" data-dimension25="$19.99">30-Pack Toilet Bowl Cleaning Tablets: was $22.99 now $19.99</a></strong><br />In order for bleach cleaning tablets to work, they contain powerful bleaching ingredients which are great for tackling stubborn stains, but not great if you put them in your cistern. The sustained release will work wonders on your toilet, as long as you follow my husband plumber's helpful tip.<a class="view-deal button" href="https://www.amazon.com/Vacplus-Toilet-Bowl-Cleaners-Automatical-Cleaning/dp/B09SZ7F5FY" target="_blank" rel="nofollow" data-dimension112="69bd9a08-88ec-11f1-a376-1b13d887de96" data-action="Deal Block" data-label="30-Pack Toilet Bowl Cleaning Tablets" data-dimension48="30-Pack Toilet Bowl Cleaning Tablets" data-dimension25="$19.99">View Deal</a></p></div><h2 id="3-draw-a-pencil-line-around-damp-spots">3. Draw a pencil line around damp spots</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="MNmqKrgC9eakdpxzvgrFAc" name="pencil_hack" alt="Drawing a pencil line around a damp patch on the ceiling" src="https://cdn.mos.cms.futurecdn.net/MNmqKrgC9eakdpxzvgrFAc-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">Drawing a pencil line around a damp patch on the ceiling </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Now, this one's my favorite, and it's one of those hacks you wonder why you didn't think of it yourself. </p><p>Whenever you spot a damp patch or stain in your home, here's what my plumber husband recommends: "I advise customers that if they notice a mark on their ceiling (most commonly), they should trace the outline with a pencil."</p><p>Why? Well, he adds: "If you leave it for 12 hours and come back, you'll see if the leak has gone past the pencil line. If it has, then you know you have an active leak." </p><p>And since a pencil is harmless to your ceiling, you can leave it a little longer to be extra sure or rub it away when you're fully satisfied that the leak has stopped.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XponGO"></div>                            </div>                            <script src="https://kwizly.com/embed/XponGO.js" async=""></script><p>Do you have any tips for saving money when it comes to plumbing? Let us know in the comments.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/this-tiktok-hack-claims-vinegar-will-clean-your-shower-head-i-asked-my-plumber-husband-if-it-actually-works">This TikTok hack claims vinegar will clean your shower head — I asked my plumber husband if it actually works</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/people-are-using-dish-soap-to-break-down-drain-blockages-i-asked-a-plumber-if-its-a-good-idea">You asked: Can dish soap fix your clogged drain? A plumber explains the facts</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/households-urged-not-to-pour-boiling-water-down-drains-this-winter-i-asked-a-plumber-what-to-do-instead">Households urged not to pour boiling water down drains this winter — I asked a plumber what to do instead</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ This ultimate garden hack reveals why you should be planting your tomatoes horizontally ]]></title>
                                                                                                <dc:content><![CDATA[ <p>I've always found growing tomatoes tricky. Every year, I make a new attempt, but the results are inconsistent. One year, I'll get a few worthy of a salad, the next it'll be a total fail. </p><p>And as I sat out in my yard recently, I stared at this year's yield – tomato plants that had stopped growing entirely. So, I did what I love to do and headed online to social media to see if I could find an answer.</p><p>Fortunately, tomato growing hacks are never hard to find, from <a href="https://www.tomsguide.com/home/gardening/i-tried-this-zero-waste-gardening-hack-to-help-my-tomato-plants-thrive-and-all-i-needed-was-a-common-kitchen-scrap">using this common kitchen scrap for zero-waste gardening</a> to <a href="https://www.tomsguide.com/home/gardening-pros-swear-by-this-ingenious-tomato-watering-trick-try-it-for-juicier-plumper-tomatoes">trying out an ingenious tomato-watering trick</a>, but this time I was looking for something that would switch up my tomato growing game altogether.</p><p>Then, I found a TikTok that told me I've actually been doing it all wrong. It turns out we should all be planting our tomato plants horizontally. It might sound crazy, but it's actually a stroke of genius. Here's how it works.</p><h2 id="how-does-it-work-5">How does it work?</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@creative_explained/video/7654664045248744718" data-video-id="7654664045248744718" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@creative_explained" href="https://www.tiktok.com/@creative_explained">@creative_explained</a>                            <p></p><a target="_blank" title="♬ original sound - creative explained" href="https://www.tiktok.com/music/original-sound-7654664106951052045">♬ original sound - creative explained</a></section>                    </blockquote></div>                <p>I'm a sucker for TikTok creator, <a href="https://www.tiktok.com/@creative_explained" target="_blank" rel="nofollow">@creative_explained</a>'s videos and I'm not the only one. With over 7.5m followers, he's known for consistently sharing quick home and garden hacks with an enthusiasm that's infectious. I should know; I've been using his <a href="https://www.tomsguide.com/home/gardening/i-tried-this-genius-money-saving-hack-to-give-my-plants-a-boost-all-you-need-is-a-box-of-matches">money-saving hack for giving my plants a boost</a> this year, and I've been shocked by the results.  </p><p>But it's this tomato planting hack that caught my attention this time. As he demonstrates, you take a tomato plant and strip all the leaves off the stalk, leaving just the top shoot with one leaf. </p><p>Then, you dig a trench in your garden bed. After exposing the roots of your tomato plant and breaking apart the soil at the base, lay the entire plant horizontally into the trench.</p><p>Bury the entire stalk with soil, leaving just the top shoot and leaf exposed. Raise just this part and hold it vertically with soil. </p><p>He explains: "What's going to happen now underneath the soil is that the tomato will grow roots all along its stem. </p><p>It'll start to grow new shoots. The stem pretty much transforms into an entire root system." Genius.</p><h2 id="here-s-what-happened-when-i-tried-it">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ybpqyfqtMJj82jKWwxVz94" name="tomato_plant_hack" alt="Soil for planting" src="https://cdn.mos.cms.futurecdn.net/ybpqyfqtMJj82jKWwxVz94-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I fear I may have found this hack a little late for the tomato growing season, but with hot weather in my area, I figured I could still transplant outside with a totally new tomato plant to hand. </p><p>Planting it horizontally was simple enough, even if it did feel like a strange process. I've had success with @creative_explained's hacks before like <a href="https://www.tomsguide.com/home/gardening/this-cheap-gardening-hack-uses-a-common-household-ingredient-youre-probably-throwing-away">using potato peel water in my soil</a>, so I'm looking forward to seeing the results. In terms of process, it was easy to do, though I needed to find a space in my garden bed that was long enough to accommodate.</p><p>Fortunately, I recently dug up some old rhubarb that was suffering in the heat, so I had the space to try out this horizontal planting trick. Now, I just need to wait until fall to see the results, but it feels good to try out something entirely new for a change. Growing tomatoes is a tricky business, but this might well be the solution I've been desperately searching for.</p><div class="product"><a data-dimension112="a3df4f40-84c5-11f1-8c30-c777546c4971" data-action="Deal Block" data-label="2lb Compressed Organic Potting Soil" data-dimension48="2lb Compressed Organic Potting Soil" data-dimension25="$39.97" href="https://www.amazon.com/Compressed-Organic-Potting-Soil-Garden-Plants/dp/B07DF9LN96" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="nw2fuEKy7r6FfmJQ7GNecm" name="potting_soil_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/nw2fuEKy7r6FfmJQ7GNecm-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Compressed-Organic-Potting-Soil-Garden-Plants/dp/B07DF9LN96" target="_blank" rel="nofollow" data-dimension112="a3df4f40-84c5-11f1-8c30-c777546c4971" data-action="Deal Block" data-label="2lb Compressed Organic Potting Soil" data-dimension48="2lb Compressed Organic Potting Soil" data-dimension25="$39.97">2lb Compressed Organic Potting Soil: $39.97</a></strong><br />For indoor and outdoor use, this potting and planting soil expands with water up to 4x and can make up to 3 gallons worth of soil. Kept compact in this small bag, it's easy to store and bring out when you've got a planting mission in mind.<a class="view-deal button" href="https://www.amazon.com/Compressed-Organic-Potting-Soil-Garden-Plants/dp/B07DF9LN96" target="_blank" rel="nofollow" data-dimension112="a3df4f40-84c5-11f1-8c30-c777546c4971" data-action="Deal Block" data-label="2lb Compressed Organic Potting Soil" data-dimension48="2lb Compressed Organic Potting Soil" data-dimension25="$39.97">View Deal</a></p></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XZQZ5O"></div>                            </div>                            <script src="https://kwizly.com/embed/XZQZ5O.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/gardening/this-cheap-garden-hack-will-help-your-roses-grow-and-all-you-need-is-a-few-old-tea-bags">This cheap garden hack will help your roses grow — and all you need is a few old tea bags</a></li><li><a href="https://www.tomsguide.com/home/stop-wasting-money-on-tomato-feed-heres-how-i-made-my-own-free-fertilizer">Stop wasting money on tomato feed — here’s how I made my own free fertilizer</a></li><li><a href="https://www.tomsguide.com/home/gardening/the-3-kitchen-scraps-i-never-throw-away-if-i-want-sweet-ripe-tomatoes">The 3 kitchen scraps I never throw away if I want sweet, ripe tomatoes</a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/gardening/this-ultimate-garden-hack-reveals-why-you-should-be-planting-your-tomatoes-horizontally</link>
                                                                            <description>
                            <![CDATA[ Growing tomato plants can be a tricky garden task. I should know, I've failed on numerous attempts. Now, I've found out I should be planting my tomato plants horizontally, here's why. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">unWs6N7aH3Ps65BsVhA2BX</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/UPyx4JVFD9VPZ6gEZRzfoe-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 24 Jul 2026 08:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gardening]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                    <category><![CDATA[Outdoors]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/UPyx4JVFD9VPZ6gEZRzfoe-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tomato plant]]></media:description>                                                            <media:text><![CDATA[Tomato plant]]></media:text>
                                <media:title type="plain"><![CDATA[Tomato plant]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/UPyx4JVFD9VPZ6gEZRzfoe-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I've always found growing tomatoes tricky. Every year, I make a new attempt, but the results are inconsistent. One year, I'll get a few worthy of a salad, the next it'll be a total fail. </p><p>And as I sat out in my yard recently, I stared at this year's yield – tomato plants that had stopped growing entirely. So, I did what I love to do and headed online to social media to see if I could find an answer.</p><p>Fortunately, tomato growing hacks are never hard to find, from <a href="https://www.tomsguide.com/home/gardening/i-tried-this-zero-waste-gardening-hack-to-help-my-tomato-plants-thrive-and-all-i-needed-was-a-common-kitchen-scrap">using this common kitchen scrap for zero-waste gardening</a> to <a href="https://www.tomsguide.com/home/gardening-pros-swear-by-this-ingenious-tomato-watering-trick-try-it-for-juicier-plumper-tomatoes">trying out an ingenious tomato-watering trick</a>, but this time I was looking for something that would switch up my tomato growing game altogether.</p><p>Then, I found a TikTok that told me I've actually been doing it all wrong. It turns out we should all be planting our tomato plants horizontally. It might sound crazy, but it's actually a stroke of genius. Here's how it works.</p><h2 id="how-does-it-work-5">How does it work?</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@creative_explained/video/7654664045248744718" data-video-id="7654664045248744718" style="max-width: 605px; min-width: 325px;">                        <section>                            <a target="_blank" title="@creative_explained" href="https://www.tiktok.com/@creative_explained">@creative_explained</a>                            <p></p><a target="_blank" title="♬ original sound - creative explained" href="https://www.tiktok.com/music/original-sound-7654664106951052045">♬ original sound - creative explained</a></section>                    </blockquote></div>                <p>I'm a sucker for TikTok creator, <a href="https://www.tiktok.com/@creative_explained" target="_blank" rel="nofollow">@creative_explained</a>'s videos and I'm not the only one. With over 7.5m followers, he's known for consistently sharing quick home and garden hacks with an enthusiasm that's infectious. I should know; I've been using his <a href="https://www.tomsguide.com/home/gardening/i-tried-this-genius-money-saving-hack-to-give-my-plants-a-boost-all-you-need-is-a-box-of-matches">money-saving hack for giving my plants a boost</a> this year, and I've been shocked by the results.  </p><p>But it's this tomato planting hack that caught my attention this time. As he demonstrates, you take a tomato plant and strip all the leaves off the stalk, leaving just the top shoot with one leaf. </p><p>Then, you dig a trench in your garden bed. After exposing the roots of your tomato plant and breaking apart the soil at the base, lay the entire plant horizontally into the trench.</p><p>Bury the entire stalk with soil, leaving just the top shoot and leaf exposed. Raise just this part and hold it vertically with soil. </p><p>He explains: "What's going to happen now underneath the soil is that the tomato will grow roots all along its stem. </p><p>It'll start to grow new shoots. The stem pretty much transforms into an entire root system." Genius.</p><h2 id="here-s-what-happened-when-i-tried-it">Here's what happened when I tried it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check="" ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ybpqyfqtMJj82jKWwxVz94" name="tomato_plant_hack" alt="Soil for planting" src="https://cdn.mos.cms.futurecdn.net/ybpqyfqtMJj82jKWwxVz94-1920-80.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="" /></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I fear I may have found this hack a little late for the tomato growing season, but with hot weather in my area, I figured I could still transplant outside with a totally new tomato plant to hand. </p><p>Planting it horizontally was simple enough, even if it did feel like a strange process. I've had success with @creative_explained's hacks before like <a href="https://www.tomsguide.com/home/gardening/this-cheap-gardening-hack-uses-a-common-household-ingredient-youre-probably-throwing-away">using potato peel water in my soil</a>, so I'm looking forward to seeing the results. In terms of process, it was easy to do, though I needed to find a space in my garden bed that was long enough to accommodate.</p><p>Fortunately, I recently dug up some old rhubarb that was suffering in the heat, so I had the space to try out this horizontal planting trick. Now, I just need to wait until fall to see the results, but it feels good to try out something entirely new for a change. Growing tomatoes is a tricky business, but this might well be the solution I've been desperately searching for.</p><div class="product"><a data-dimension112="a3df4f40-84c5-11f1-8c30-c777546c4971" data-action="Deal Block" data-label="2lb Compressed Organic Potting Soil" data-dimension48="2lb Compressed Organic Potting Soil" data-dimension25="$39.97" href="https://www.amazon.com/Compressed-Organic-Potting-Soil-Garden-Plants/dp/B07DF9LN96" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:535px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="nw2fuEKy7r6FfmJQ7GNecm" name="potting_soil_deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/nw2fuEKy7r6FfmJQ7GNecm-1920-80.jpg" mos="" align="middle" fullscreen="" width="535" height="535" attribution="" endorsement="" credit="" class="" /></p></div></div></figure></a><p><strong><a href="https://www.amazon.com/Compressed-Organic-Potting-Soil-Garden-Plants/dp/B07DF9LN96" target="_blank" rel="nofollow" data-dimension112="a3df4f40-84c5-11f1-8c30-c777546c4971" data-action="Deal Block" data-label="2lb Compressed Organic Potting Soil" data-dimension48="2lb Compressed Organic Potting Soil" data-dimension25="$39.97">2lb Compressed Organic Potting Soil: $39.97</a></strong><br />For indoor and outdoor use, this potting and planting soil expands with water up to 4x and can make up to 3 gallons worth of soil. Kept compact in this small bag, it's easy to store and bring out when you've got a planting mission in mind.<a class="view-deal button" href="https://www.amazon.com/Compressed-Organic-Potting-Soil-Garden-Plants/dp/B07DF9LN96" target="_blank" rel="nofollow" data-dimension112="a3df4f40-84c5-11f1-8c30-c777546c4971" data-action="Deal Block" data-label="2lb Compressed Organic Potting Soil" data-dimension48="2lb Compressed Organic Potting Soil" data-dimension25="$39.97">View Deal</a></p></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XZQZ5O"></div>                            </div>                            <script src="https://kwizly.com/embed/XZQZ5O.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/gardening/this-cheap-garden-hack-will-help-your-roses-grow-and-all-you-need-is-a-few-old-tea-bags">This cheap garden hack will help your roses grow — and all you need is a few old tea bags</a></li><li><a href="https://www.tomsguide.com/home/stop-wasting-money-on-tomato-feed-heres-how-i-made-my-own-free-fertilizer">Stop wasting money on tomato feed — here’s how I made my own free fertilizer</a></li><li><a href="https://www.tomsguide.com/home/gardening/the-3-kitchen-scraps-i-never-throw-away-if-i-want-sweet-ripe-tomatoes">The 3 kitchen scraps I never throw away if I want sweet, ripe tomatoes</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Yellow Monstera leaves signal stress — here’s how to save your plant and bring back the green ]]></title>
                                                                                                <dc:content><![CDATA[ <p>Monsteras are usually the drama-free roommates of the houseplant world, until the morning you walk past yours and spot an undeniably yellow leaf.</p><p>Trust me, I know that sudden flash of panic. But after years of keeping these tropical giants happy, I’ve learned a yellow leaf isn't an instant death sentence. It’s just your plant’s version of a check-engine light. </p><p>Whether you're dealing with a simple watering mistake or a tricky lighting spot, I’ll help you translate what your Monstera is begging for and get it thriving again.</p><section class="howto-block">                    <h3>1. Assess your watering habits </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/kJDpXGLQ9dA8bjps3rY9VR.jpg"                                        alt="Yellowing monstera leaf caused by overwatering"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/kJDpXGLQ9dA8bjps3rY9VR.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Overwatering is the single most common cause of yellowing Monstera leaves. Monsteras need oxygen at their roots to survive. When potting soil stays waterlogged, roots suffocate, develop root rot, and lose the ability to transport nutrients to the foliage.</p><p>If overwatering is the issue, lower leaves will turn a solid, pale yellow, often accompanied by dark brown soft spots or a wet, musty smell coming from the soil. </p><p><strong>Stick your finger two to three inches into the soil. If it feels soggy, stop watering immediately</strong>. Allow the top half of the soil mix to dry completely before watering again, and <strong>always ensure your pot has functional drainage holes paired with a well-draining soil mix</strong>.</p><p>Underwatering causes a different pattern altogether. Leaves turn yellow with dry, crispy brown edges, and the entire plant feels droopy or papery to the touch.</p><p><strong>If the soil is bone-dry and pulling away from the inside edges of the pot, bottom-water or thoroughly soak the root ball</strong> until water drains freely from the bottom holes.</p></p>                </section><section class="howto-block">                    <h3>2. Adjust your lighting conditions </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/hB455b3MG4oG4U7RAzBhBL.jpg"                                        alt="Sun burned monstera"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/hB455b3MG4oG4U7RAzBhBL.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Monstera plants require medium to bright, indirect sunlight to photosynthesize effectively. Without enough light, the plant cannot process moisture in the soil, leading to both energy starvation and lingering wet roots.</p><p>When light is too low, leaves gradually fade from dark green to a dull, muted yellow, and new leaves grow unusually small without fenestrations. </p><p><strong>Move your plant closer to an east- or south-facing window behind a sheer curtain, or install a full-spectrum LED grow light </strong>positioned a few feet away. </p><p>Even though they're tropical plants, they dislike direct sunlight. If you notice yellow patches with bleached or crispy brown centers, this is likely the culprit. <strong>Move your plant away from where it'll be scorched by harsh sun</strong>. </p></p>                </section><section class="howto-block">                    <h3>3. Check for houseplant pests</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/ACatoM5cZHUtgdSVxbwVzn.jpg"                                        alt="Monstera leaf infested with pests"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/ACatoM5cZHUtgdSVxbwVzn.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Systematic pest attacks drain vital sap from plant tissue, causing yellow stippling, discoloration, and eventual leaf drop. </p><p>Thrips are particularly common on Monsteras and leave behind tiny, slender dark insects, black specks of excrement, and silvery patches on the leaves. Spider mites and mealybugs also target Monsteras, leaving behind delicate webbing or white, cottony residues.</p><p>If you spot pests,<strong> isolate the plant</strong> from your other houseplants immediately. <strong>Rinse or wipe down the leaves thoroughly with a mild soap solution</strong>, then <strong>spray all foliage with neem oil or insecticidal soap once a week</strong> until the infestation is completely cleared.</p></p>                </section><section class="howto-block">                    <h3>4. Address nutrient deficiencies or natural aging</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/vc3hXWS8N7viB59aDnVxff.jpg"                                        alt="Monstera plant with old, yellowed leaves "                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/vc3hXWS8N7viB59aDnVxff.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>If older, bottom leaves show general pale yellowing while the leaf veins stay slightly green, your Monstera may be lacking key nutrients like nitrogen. </p><p>Monstera plants grow rapidly during spring and summer and exhaust soil nutrients over time. <strong>Feed your plant every two to four weeks during the growing season with a balanced liquid houseplant fertilizer diluted to half strength</strong>, cutting back completely during winter dormancy.</p><p>Keep in mind that not all yellowing is a crisis. If a single, lowermost small leaf turns yellow and drops every once in a while while the rest of the plant flourishes, this is simply natural leaf turnover as the plant directs its energy to new growth.</p></p>                </section><h3 class="article-body__section" id="section-frequently-asked-questions"><span>Frequently asked questions</span></h3><h2 id="should-i-cut-off-yellow-monstera-leaves">Should I cut off yellow monstera leaves?</h2><p>Yes, you should prune them. Once a Monstera leaf has turned <em>fully </em>yellow, it cannot regain its green color because the chlorophyll has broken down. Use sterilized shears to cut the yellow leaf stem near the base so the plant stops wasting valuable energy trying to sustain damaged tissue.</p><h2 id="how-long-does-it-take-for-a-monstera-to-recover">How long does it take for a monstera to recover?</h2><p>Once you fix the underlying issue, such as adjusting your watering schedule or moving the pot to better lighting, you should expect to see fresh, healthy green growth within two to four weeks during the growing season.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-egKKpe"></div>                            </div>                            <script src="https://kwizly.com/embed/egKKpe.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide </span></h3><ul><li><a href="https://www.tomsguide.com/home/monstera-leaves-curling-heres-what-your-plant-is-trying-to-tell-you">Monstera leaves curling? Here's what your plant is trying to tell you</a></li><li><a href="https://www.tomsguide.com/home/gardening/this-tiny-pest-causes-the-biggest-damage-to-your-plants-heres-how-to-stop-thrips">This tiny pest causes the biggest damage to your plants — here's how to stop thrips</a></li><li><a href="https://www.tomsguide.com/home/houseplants-taking-over-heres-how-to-repot-a-swiss-cheese-plant">Houseplants taking over? Here's how to repot a monstera </a></li></ul> ]]></dc:content>
                                                                                                                                            <link>https://www.tomsguide.com/home/yellow-monstera-leaves-signal-stress-heres-how-to-save-your-plant-and-bring-back-the-green</link>
                                                                            <description>
                            <![CDATA[ I'll help you decode what your Monstera is trying to tell you — plus the simple tweaks you need to bring back healthy, green growth. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">UHaZSfmbNxp6iyQ3g2JHsQ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/M85ZY6VENL6vnYuCFF3YHC-1920-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 23 Jul 2026 08:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                <author><![CDATA[ kaycee.hill@futurenet.com (Kaycee Hill) ]]></author>                    <dc:creator><![CDATA[ Kaycee Hill ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/xHn6RmpEqg87cvtLwrBu9G-320-70.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                                                                    <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/M85ZY6VENL6vnYuCFF3YHC-1920-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Yellowing potted monstera plants]]></media:description>                                                            <media:text><![CDATA[Yellowing potted monstera plants]]></media:text>
                                <media:title type="plain"><![CDATA[Yellowing potted monstera plants]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/M85ZY6VENL6vnYuCFF3YHC-1920-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Monsteras are usually the drama-free roommates of the houseplant world, until the morning you walk past yours and spot an undeniably yellow leaf.</p><p>Trust me, I know that sudden flash of panic. But after years of keeping these tropical giants happy, I’ve learned a yellow leaf isn't an instant death sentence. It’s just your plant’s version of a check-engine light. </p><p>Whether you're dealing with a simple watering mistake or a tricky lighting spot, I’ll help you translate what your Monstera is begging for and get it thriving again.</p><section class="howto-block">                    <h3>1. Assess your watering habits </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/kJDpXGLQ9dA8bjps3rY9VR.jpg"                                        alt="Yellowing monstera leaf caused by overwatering"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/kJDpXGLQ9dA8bjps3rY9VR.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Overwatering is the single most common cause of yellowing Monstera leaves. Monsteras need oxygen at their roots to survive. When potting soil stays waterlogged, roots suffocate, develop root rot, and lose the ability to transport nutrients to the foliage.</p><p>If overwatering is the issue, lower leaves will turn a solid, pale yellow, often accompanied by dark brown soft spots or a wet, musty smell coming from the soil. </p><p><strong>Stick your finger two to three inches into the soil. If it feels soggy, stop watering immediately</strong>. Allow the top half of the soil mix to dry completely before watering again, and <strong>always ensure your pot has functional drainage holes paired with a well-draining soil mix</strong>.</p><p>Underwatering causes a different pattern altogether. Leaves turn yellow with dry, crispy brown edges, and the entire plant feels droopy or papery to the touch.</p><p><strong>If the soil is bone-dry and pulling away from the inside edges of the pot, bottom-water or thoroughly soak the root ball</strong> until water drains freely from the bottom holes.</p></p>                </section><section class="howto-block">                    <h3>2. Adjust your lighting conditions </h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/hB455b3MG4oG4U7RAzBhBL.jpg"                                        alt="Sun burned monstera"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/hB455b3MG4oG4U7RAzBhBL.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Monstera plants require medium to bright, indirect sunlight to photosynthesize effectively. Without enough light, the plant cannot process moisture in the soil, leading to both energy starvation and lingering wet roots.</p><p>When light is too low, leaves gradually fade from dark green to a dull, muted yellow, and new leaves grow unusually small without fenestrations. </p><p><strong>Move your plant closer to an east- or south-facing window behind a sheer curtain, or install a full-spectrum LED grow light </strong>positioned a few feet away. </p><p>Even though they're tropical plants, they dislike direct sunlight. If you notice yellow patches with bleached or crispy brown centers, this is likely the culprit. <strong>Move your plant away from where it'll be scorched by harsh sun</strong>. </p></p>                </section><section class="howto-block">                    <h3>3. Check for houseplant pests</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/ACatoM5cZHUtgdSVxbwVzn.jpg"                                        alt="Monstera leaf infested with pests"                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/ACatoM5cZHUtgdSVxbwVzn.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>Systematic pest attacks drain vital sap from plant tissue, causing yellow stippling, discoloration, and eventual leaf drop. </p><p>Thrips are particularly common on Monsteras and leave behind tiny, slender dark insects, black specks of excrement, and silvery patches on the leaves. Spider mites and mealybugs also target Monsteras, leaving behind delicate webbing or white, cottony residues.</p><p>If you spot pests,<strong> isolate the plant</strong> from your other houseplants immediately. <strong>Rinse or wipe down the leaves thoroughly with a mild soap solution</strong>, then <strong>spray all foliage with neem oil or insecticidal soap once a week</strong> until the infestation is completely cleared.</p></p>                </section><section class="howto-block">                    <h3>4. Address nutrient deficiencies or natural aging</h3>                    <figure>                            <p class="bordeaux-image-check">                                <img    src="https://cdn.mos.cms.futurecdn.net/vc3hXWS8N7viB59aDnVxff.jpg"                                        alt="Monstera plant with old, yellowed leaves "                                        onerror="this.parentNode.replaceChild(window.missingImage(),this)"                                        data-pin-media="https://cdn.mos.cms.futurecdn.net/vc3hXWS8N7viB59aDnVxff.jpg"                                        class="expandable van-old-layout-image" />                            </p><div class="credit">(Image: © Shutterstock)</div></figure>                    <p><p>If older, bottom leaves show general pale yellowing while the leaf veins stay slightly green, your Monstera may be lacking key nutrients like nitrogen. </p><p>Monstera plants grow rapidly during spring and summer and exhaust soil nutrients over time. <strong>Feed your plant every two to four weeks during the growing season with a balanced liquid houseplant fertilizer diluted to half strength</strong>, cutting back completely during winter dormancy.</p><p>Keep in mind that not all yellowing is a crisis. If a single, lowermost small leaf turns yellow and drops every once in a while while the rest of the plant flourishes, this is simply natural leaf turnover as the plant directs its energy to new growth.</p></p>                </section><h3 class="article-body__section" id="section-frequently-asked-questions"><span>Frequently asked questions</span></h3><h2 id="should-i-cut-off-yellow-monstera-leaves">Should I cut off yellow monstera leaves?</h2><p>Yes, you should prune them. Once a Monstera leaf has turned <em>fully </em>yellow, it cannot regain its green color because the chlorophyll has broken down. Use sterilized shears to cut the yellow leaf stem near the base so the plant stops wasting valuable energy trying to sustain damaged tissue.</p><h2 id="how-long-does-it-take-for-a-monstera-to-recover">How long does it take for a monstera to recover?</h2><p>Once you fix the underlying issue, such as adjusting your watering schedule or moving the pot to better lighting, you should expect to see fresh, healthy green growth within two to four weeks during the growing season.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-egKKpe"></div>                            </div>                            <script src="https://kwizly.com/embed/egKKpe.js" async=""></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide </span></h3><ul><li><a href="https://www.tomsguide.com/home/monstera-leaves-curling-heres-what-your-plant-is-trying-to-tell-you">Monstera leaves curling? Here's what your plant is trying to tell you</a></li><li><a href="https://www.tomsguide.com/home/gardening/this-tiny-pest-causes-the-biggest-damage-to-your-plants-heres-how-to-stop-thrips">This tiny pest causes the biggest damage to your plants — here's how to stop thrips</a></li><li><a href="https://www.tomsguide.com/home/houseplants-taking-over-heres-how-to-repot-a-swiss-cheese-plant">Houseplants taking over? Here's how to repot a monstera </a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
            </channel>
</rss>