<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="https://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/pc-gaming" rel="self" type="application/rss+xml" />
                            <title><![CDATA[ Latest from Tom's Guide in Pc-gaming ]]></title>
                <link>https://www.tomsguide.com/gaming/pc-gaming</link>
        <description><![CDATA[ All the latest pc-gaming content from the Tom's Guide team ]]></description>
                                    <lastBuildDate>Wed, 29 Jul 2026 05:45:00 +0000</lastBuildDate>
                            <language>en</language>
                                <item>
                                                            <title><![CDATA[ I test gaming laptops and this is how I get better performance without plugging them in ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/gaming-laptops/i-test-gaming-laptops-and-this-is-how-i-get-better-performance-without-plugging-them-in</link>
                                                                            <description>
                            <![CDATA[ While you'll always get better performance from a gaming laptop that's plugged in, you can get a better experience on battery with the right adjustments. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">WnYAazuE82tR9ZiMqkg56A</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/qvTTEwYDZVcqGf3ZswazMP-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 29 Jul 2026 05:45:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gaming Laptops]]></category>
                                                    <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Laptops]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/qvTTEwYDZVcqGf3ZswazMP-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Alienware Area-51 gaming laptop]]></media:description>                                                            <media:text><![CDATA[Alienware Area-51 gaming laptop]]></media:text>
                                <media:title type="plain"><![CDATA[Alienware Area-51 gaming laptop]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/qvTTEwYDZVcqGf3ZswazMP-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>A core reason you’d want one of the <a href="https://www.tomsguide.com/best-picks/best-gaming-laptops">best gaming laptops</a> is to play your favorite PC games on the go. However, your experience with AAA games won’t be great on battery power. Not only will you generally get less than two hours of gameplay, but you'll suffer severe drops in frames per second (FPS). This is why most users keep their gaming laptops plugged in during use.</p><p>But what if you’re itching to play a game and there’s no wall outlet in sight? Are you stuck playing for just a couple of hours at 30 frames per second or lower? Not necessarily, so long as you make various adjustments to the laptop and game. Though the results won't always match what you'd get when plugged in, you’ll have a smoother gaming experience.</p><p>If you want to squeeze as much performance as possible from a gaming laptop running on battery, I’ll show you how!</p><h2 id="on-battery-vs-plugged-in">On battery vs plugged in</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="DoMP5mBnSytRfb3gvzY7k3" name="Alienware Area-51 gaming laptop-05" alt="Alienware Area-51 gaming laptop" src="https://cdn.mos.cms.futurecdn.net/DoMP5mBnSytRfb3gvzY7k3.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>Generally, a battery provides around 40 to 90 watts of power, whereas a wall charger can provide 100 to 200+ watts. That extra power allows laptop components like the GPU and CPU to run more efficiently, delivering smoother gaming performance. However, on battery power, operating systems automatically switch to low-power or balanced profiles, which lowers frame rates and screen refresh rates.</p><p>There are also safety reasons. Drawing too much power too quickly from a battery can generate excessive heat and damage the cells. Laptops also slow the CPU and GPU on battery power to prevent overheating. When you connect a laptop to a wall outlet, your computer knows it has an endless energy supply and removes all the speed caps.</p><p>I ran <a href="https://www.tomsguide.com/reviews/cyberpunk-2077-phantom-liberty">Cyberpunk 2077</a> on the Alienware 16 (2026) on both battery power and while plugged in to show you the difference. At default graphical settings and native 2560x1600 resolution, the game ran at around 110-120 fps while I was on foot and around 90-100 fps when I drove through the city center. Unplugged, Cyberpunk 2077’s frame rate dropped to the 70s on foot and to around 55 on the highway.</p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Plugged in</strong></p></td><td  ><p><strong>On battery</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Cyberpunk 2077</strong></p></td><td  ><p>90-120 fps</p></td><td  ><p>55-70 fps</p></td></tr></tbody></table></div><p>To be clear, the Alienware 16 is an extremely powerful gaming laptop, which accounts for its high fps even when unplugged. Still, a 30 frames-per-second drop isn’t small and illustrates the difference between playing plugged in and unplugged.</p><h2 id="how-to-get-better-performance-on-battery">How to get better performance on battery</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="SEKyVaGak7BDw83yseU2CP" name="cyberpunk-2077-phantom-liberty-screenshot-01.jpg" alt="Cyberpunk 2077 Phantom Liberty screenshot" src="https://cdn.mos.cms.futurecdn.net/SEKyVaGak7BDw83yseU2CP.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: CD Projekt Red)</span></figcaption></figure><p>I’ll now detail how to get battery gaming laptop performance while on battery. Keep in mind that the battery can’t output enough wattage for full gaming speeds, so performance will always be limited compared to when you’re plugged in. With that out of the way, let’s get into it.</p><p>On your laptop, <strong>click the battery icon on the taskbar and set the power mode to Best Performance</strong>. If your laptop has an Nvidia RTX GPU, <strong>you can disable BatteryBoost or raise the frame rate cap in the GeForce Experience app</strong> (or the Nvidia app). </p><p>Similarly, open your laptop manufacturer’s custom app (such as Asus Armoury Crate, Razer Synapse, or Lenovo Vantage) <strong>and switch the operating mode from Eco/Silent to a manual or performance profile</strong>. You can also <strong>set a custom frame limiter in the Nvidia Control Panel to limit CPU and GPU usage as needed</strong>. </p><p>To improve battery life, <strong>you can lower the refresh rate from a high rate like 144Hz to 60Hz</strong>. You can also <strong>reduce the display’s brightness to around 50% or lower and turn off RGB lighting</strong> if your laptop uses it. <strong>Unplugging unnecessary peripherals also helps improve battery life</strong>. And of course, <strong>shut down any apps you’re not currently using</strong>.</p><p>On the game side, you can do things like<strong> lower the game’s resolution, shadow quality, and graphical settings to reduce the workload on your laptop</strong>. Similarly, <strong>you can cap your maximum FPS in the game settings</strong> to keep stable performance.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OKBpRW"></div>                            </div>                            <script src="https://kwizly.com/embed/OKBpRW.js" async></script><h2 id="bottom-line">Bottom line</h2><p>I will always advise folks to keep their gaming laptops plugged in while playing for the best possible performance. However, if there’s nowhere to connect, the tips above should help you get better performance on battery life. It’s not as optimal as when you’re plugged in, but you’ll have a smoother overall experience.</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/computing/im-a-pc-hardware-reviewer-here-are-the-3-best-ways-to-get-into-pc-gaming-in-2026-without-spending-a-fortune">I’m a PC hardware reviewer — here are the 3 best ways to get into PC gaming in 2026 without spending a fortune</a></li><li><a href="https://www.tomsguide.com/computing/laptops/dell-xps-13-2026-review">I just tested the new Dell XPS 13 — here’s why it’s the best budget Windows laptop right now</a></li><li><a href="https://www.tomsguide.com/computing/while-pc-gamers-fight-for-16gb-of-vram-amd-just-unveiled-a-rack-with-31-000-gigabytes">While PC gamers fight for 16GB of VRAM, AMD just unveiled a rack with 31,000 Gigabytes</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I’m a PC hardware reviewer — here are the 3 best ways to get into PC gaming in 2026 without spending a fortune ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/im-a-pc-hardware-reviewer-here-are-the-3-best-ways-to-get-into-pc-gaming-in-2026-without-spending-a-fortune</link>
                                                                            <description>
                            <![CDATA[ PC gaming is more expensive in 2026, but these 3 realistic paths make it possible to start without overspending. Here's what they are. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">EqA76HsXzMfFGjkoit6BAZ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/NZVGFGtR5xgjTMoDWwYjQP-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 28 Jul 2026 11:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Handheld Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/NZVGFGtR5xgjTMoDWwYjQP-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Maingear MG-1 gaming PC review unit in action]]></media:description>                                                            <media:text><![CDATA[Maingear MG-1 gaming PC review unit in action]]></media:text>
                                <media:title type="plain"><![CDATA[Maingear MG-1 gaming PC review unit in action]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/NZVGFGtR5xgjTMoDWwYjQP-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As a computing writer for Tom’s Guide, part of my job is helping readers save money on PCs and components. That has become much harder thanks to <a href="https://www.tomsguide.com/computing/ram-price-crisis-2026-everything-you-need-to-know">RAMageddon</a>, which has driven up the cost of memory and, by extension, most electronics. PC gaming has been hit especially hard. It was already a relatively expensive hobby, and price increases have made the barrier to entry even higher.</p><p>That doesn’t mean it’s impossible to get into PC gaming in 2026. You’ll almost certainly pay more for machines and components than you would have a year ago. But if you know what to look for (and what to avoid), you can still find a capable setup that fits your needs and lasts for years.</p><p>In this guide, I’ll walk through the three main ways people start PC gaming right now: a gaming handheld, a pre-built desktop, and building your own PC. I’ll break down the pros and cons of each, then explain which path makes the most sense depending on your budget, space, and priorities.</p><h2 id="gaming-handhelds">Gaming handhelds</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="NeG4gtJxwVkhZ9FyNv9FmT" name="ROG Xbox Ally" alt="ROG Xbox Ally" src="https://cdn.mos.cms.futurecdn.net/NeG4gtJxwVkhZ9FyNv9FmT.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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 price of the <a href="https://www.tomsguide.com/round-up/best-handheld-gaming-consoles">best handheld gaming consoles</a> has climbed sharply this year. Where the <a href="https://www.tomsguide.com/opinion/steam-deck-oled-is-the-must-buy-handheld-of-2023-and-the-perfect-holiday-gift-for-gamers">Steam Deck OLED</a> once topped out at $649, the 512GB model now starts at $789. Other notable handhelds have seen similar increases, though entry-level options like the <a href="https://www.tomsguide.com/gaming/handheld-gaming/rog-xbox-ally-review">Asus ROG Xbox Ally</a> (around $600) remain relatively more accessible than the higher-end <a href="https://www.tomsguide.com/gaming/handheld-gaming/lenovo-legion-go-2-review">Legion Go 2</a>.</p><p>Even with the higher prices, gaming handhelds are still one of the strongest low-friction ways to start PC gaming right now — especially while discrete GPUs, RAM, and other components stay expensive. These self-contained systems run the <a href="https://www.tomsguide.com/best-picks/best-PC-games">best PC games</a> from Steam (and other libraries), either on SteamOS or Windows.</p><p>The advantages are clear. Portability means you can play almost anywhere. Setup is relatively simple, particularly on <a href="https://www.tomsguide.com/us/steamos-faq-machines,news-17614.html">SteamOS</a> devices, where you can get into games with less tinkering than a full <a href="https://www.tomsguide.com/reviews/windows-11">Windows 11</a> machine. Most models also support docking to a TV or monitor, which often improves performance once the handheld is powered and no longer thermally limited. While they’re no longer the bargains they once were, several capable options still sit under $1,000.</p><p>They do come with real trade-offs, though. The biggest is the performance ceiling: most current AAA titles run at 720p–1080p on low-to-medium settings, typically in the 30–60 fps range. Battery life often drops to one or two hours during demanding games (longer on lighter titles), and Windows handhelds can introduce additional UI friction and software overhead. Storage also fills up quickly on 512GB models.</p><p>Despite those compromises, the combination of portability, access to a PC library, and a relatively contained total cost still makes handhelds a solid option for many newcomers—especially anyone who wants to start playing without committing to a full desktop setup.</p><div class="product"><a data-dimension112="0a158874-89f8-11f1-bf64-e18de257f925" data-action="Deal Block" data-label="Price Check: $499 (refurbished) @ Woot" data-dimension48="Price Check: $499 (refurbished) @ Woot" data-dimension25="$599" href="https://www.bestbuy.com/product/rog-xbox-ally-7-fhd-120hz-gaming-handheld-3-month-xbox-game-pass-premium-amd-ryzen-z2-a-16gb-ram-512gb-ssd/JJGHGPGFL4" 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="EoKxmvvEgJ4fHxbcrhCRo9" name="Asus ROG Xbox Ally deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/EoKxmvvEgJ4fHxbcrhCRo9.jpg" mos="" align="middle" fullscreen="" width="1500" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Asus ROG Xbox Ally is an Xbox-inspired gaming handheld that features a comfortable design and a leaner version of Windows. While this model isn't as powerful as the ROG Xbox Asus X, it's a more compelling purchase at this lower price.<br><br><strong>Price Check: </strong><a href="https://computers.woot.com/offers/asus-rog-xbox-ally-7-gaming-handheld-1" target="_blank" rel="nofollow" data-dimension112="0a158874-89f8-11f1-bf64-e18de257f925" data-action="Deal Block" data-label="Price Check: $499 (refurbished) @ Woot" data-dimension48="Price Check: $499 (refurbished) @ Woot" data-dimension25="$599"><strong>$499 (refurbished) @ Woot</strong></a><a class="view-deal button" href="https://www.bestbuy.com/product/rog-xbox-ally-7-fhd-120hz-gaming-handheld-3-month-xbox-game-pass-premium-amd-ryzen-z2-a-16gb-ram-512gb-ssd/JJGHGPGFL4" target="_blank" rel="nofollow" data-dimension112="0a158874-89f8-11f1-bf64-e18de257f925" data-action="Deal Block" data-label="Price Check: $499 (refurbished) @ Woot" data-dimension48="Price Check: $499 (refurbished) @ Woot" data-dimension25="$599">View Deal</a></p></div><h2 id="pre-built-gaming-pcs">Pre-built gaming PCs</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="saYVqx7hF7MHyTk3MU2Qt3" name="Gaming PC build" alt="Gaming PC build images" src="https://cdn.mos.cms.futurecdn.net/saYVqx7hF7MHyTk3MU2Qt3.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’d rather own one of the <a href="https://www.tomsguide.com/us/best-gaming-pc,review-2219.html">best gaming PCs</a> but don’t want to build one from scratch, a pre-built PC is your best bet. Some gamers still look down on them, but after reviewing dozens of these machines, I can tell you this route is often a smart choice right now. Because manufacturers buy components in bulk, pre-builts can match or even beat the cost of a comparable DIY build in the current market.</p><p>The advantages are straightforward. There’s virtually no assembly required, and you only have to deal with one company if something goes wrong. You also get professional cable management and properly seated components out of the box. Thanks to that bulk purchasing power, solid 1080p systems with an RTX 5060-class GPU and 32GB of RAM currently sit in the $1,000–$1,200 range and often deliver stronger immediate value than piecing the same parts together yourself.</p><p>As Techsponential’s Avi Greengart told me via email, in this environment “buying pre-built is usually less expensive than building your own.” Looking for systems with last-generation CPUs that were priced before the worst of RAMageddon can stretch the budget even further.</p><p>There are real trade-offs, though. You won’t always get to choose every part, which can leave you with a louder cooler or a lower-tier power supply. Some cases use proprietary front panels, offer limited GPU clearance, or have tight PSU spacing that restricts future upgrades. And even when the overall price is competitive, you’re still paying something for the convenience.</p><p>If you go this route, prioritize GPU performance and RAM capacity (32GB is pretty valuable right now) over chasing a particular CPU brand. Read recent reviews of the specific model you’re considering (including ours!) to get a real sense of thermals, noise, and build quality. Stick with more established names such as Lenovo, iBuyPower, ABS, or CyberPower when possible. Factor in the full cost of a monitor, keyboard, and mouse if you don’t already own them, and move quickly when you find a good configuration — popular models can sell out fast.</p><p>Pre-builts shine when you value convenience, want a working system quickly, or feel intimidated by the current component market. They’re a legitimate entry point into PC gaming during RAMageddon, even if they offer less long-term flexibility and control than building your own system.</p><div class="product"><a data-dimension112="0a15890a-89f8-11f1-a897-29a9cd335b0b" data-action="Deal Block" data-label="The HP Omen 35L is a beautiful and powerful mid-tower gaming PC that’s highly upgradeable. Though it comes with a lot of bloatware and its CPU/GPU combination is strange, this rig’s superb gaming performance, gorgeous design, and small footprint are hard to argue against." data-dimension48="The HP Omen 35L is a beautiful and powerful mid-tower gaming PC that’s highly upgradeable. Though it comes with a lot of bloatware and its CPU/GPU combination is strange, this rig’s superb gaming performance, gorgeous design, and small footprint are hard to argue against." data-dimension25="$1454" href="https://www.bestbuy.com/product/hp-omen-35l-gaming-desktop-amd-ryzen-5-8400f-16gb-ddr5-memory-nvidia-geforce-rtx-5060-1tb-ssd-panda-metal/JJGWKY9LLY/sku/6667947" 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="qQ4BPvoamdjz2djhQF5ykn" name="Omen 35L" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/qQ4BPvoamdjz2djhQF5ykn.jpg" mos="" align="middle" fullscreen="" width="1500" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The HP Omen 35L is a beautiful and powerful mid-tower gaming PC that’s highly upgradeable. Though it comes with a lot of bloatware and its CPU/GPU combination is strange, this rig’s superb gaming performance, gorgeous design, and small footprint are hard to argue against.<a class="view-deal button" href="https://www.bestbuy.com/product/hp-omen-35l-gaming-desktop-amd-ryzen-5-8400f-16gb-ddr5-memory-nvidia-geforce-rtx-5060-1tb-ssd-panda-metal/JJGWKY9LLY/sku/6667947" target="_blank" rel="nofollow" data-dimension112="0a15890a-89f8-11f1-a897-29a9cd335b0b" data-action="Deal Block" data-label="The HP Omen 35L is a beautiful and powerful mid-tower gaming PC that’s highly upgradeable. Though it comes with a lot of bloatware and its CPU/GPU combination is strange, this rig’s superb gaming performance, gorgeous design, and small footprint are hard to argue against." data-dimension48="The HP Omen 35L is a beautiful and powerful mid-tower gaming PC that’s highly upgradeable. Though it comes with a lot of bloatware and its CPU/GPU combination is strange, this rig’s superb gaming performance, gorgeous design, and small footprint are hard to argue against." data-dimension25="$1454">View Deal</a></p></div><h2 id="custom-built-pcs">Custom-built PCs</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="6r5AqgigcXDevmKMjjTEdE" name="gaming rig.jpg" alt="PC gaming rig" src="https://cdn.mos.cms.futurecdn.net/6r5AqgigcXDevmKMjjTEdE.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>Even with elevated component prices, building your own PC remains the strongest long-term option for many people getting into PC gaming. The current memory shortage has made it less of an automatic money-saver than it was a couple of years ago, but the advantages in quality, knowledge, and future flexibility still hold for those willing to put in the work.</p><p>The biggest advantage is full control over every part. You choose the exact GPU, cooler, power supply, and case you want. And when the time comes to upgrade, you can swap individual components instead of replacing the whole system. Building also teaches you how everything fits together, which makes future upgrades and troubleshooting much easier. You can optimize the machine for your specific needs — whether that’s a quiet system, maximum airflow, or a particular mix of CPU, GPU, and RAM suited to the games you actually play.</p><p>Securing solid last-generation components (especially AM4 and DDR4) or taking advantage of motherboard/CPU/memory bundles from places like Micro Center can still deliver meaningful savings, particularly on RAM.</p><p>Of course, the DIY route requires more research, compatibility checks, assembly, and initial troubleshooting. Pricing remains a hurdle. A decent 32GB DDR5 kit can cost $350–$470, and GPUs and SSDs are similarly priced. You’ll also face multiple individual warranties instead of a single system-wide warranty, plus the small but real risk of assembly mistakes or dead-on-arrival parts. And unless you already own them, you’ll still need to buy a monitor, keyboard, mouse, and other peripherals.</p><p>Building your own PC is still the path that delivers the most ownership, flexibility, and long-term satisfaction. It demands more effort and research than a pre-built or handheld, especially with today’s component pricing. However, the reward is a system that better matches what you actually want and can grow with you for years.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Wwq5oX"></div>                            </div>                            <script src="https://kwizly.com/embed/Wwq5oX.js" async></script><h2 id="bottom-line-2">Bottom line</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:3632px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="TFv3c7xBzm337tLujZ4pRE" name="Alienware 34 QD-OLED 2026-1" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/TFv3c7xBzm337tLujZ4pRE.jpg" mos="" align="middle" fullscreen="" width="3632" height="2043" 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>So which of these three paths is the best way to get into PC gaming in 2026? It depends on your needs.</p><p>If you just want to start playing games with as little hassle as possible, a solid pre-built is a smart move. If space is tight or you’re not yet sure how deep you want to go into PC gaming, a handheld is a strong starting point. And if you care about control, upgradeability, or simply enjoying the process of putting a machine together, building your own PC is still a fantastic option.</p><p>You’re almost certainly going to spend more than you would have a year ago. But with a clearer sense of the trade-offs, you can make a smarter choice and still get into PC gaming without overspending or ending up with a setup that doesn’t fit your lifestyle.</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/computing/laptops/dell-xps-13-2026-review">Here’s why the Dell XPS 13 is the best budget Windows laptop right now</a></li><li><a href="https://www.tomsguide.com/computing/laptops/dell-xps-13-vs-macbook-neo-which-usd699-laptop-is-right-for-you">Dell XPS 13 vs. MacBook Neo: Which $699 laptop is right for you?</a></li><li><a href="https://www.tomsguide.com/computing/while-pc-gamers-fight-for-16gb-of-vram-amd-just-unveiled-a-rack-with-31-000-gigabytes">AMD just unveiled a rack with 31,000 Gigabytes</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Xbox is testing out Backward Compatibility for older games on PCs with four classic titles ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/xbox/xbox-is-testing-out-backward-compatibility-for-older-games-on-pcs-with-four-classic-titles</link>
                                                                            <description>
                            <![CDATA[ Xbox is bringing backward compatibility for some older games to PC and handhelds. Here's what the games are and when they'll be available. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">ri3s7vyHsPqfnfeN8Gnhj4</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/CBRgpGNSoTrkkwFE6i9CUF-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 22 Jul 2026 18:59:03 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Xbox]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ scott.younker@futurenet.com (Scott Younker) ]]></author>                    <dc:creator><![CDATA[ Scott Younker ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/RZsUpqcJ6Uj2q83oCUwNhQ.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Scott Younker is the West Coast Reporter at Tom’s Guide. He covers all the latest tech news, including phones, computing and more. He’s been involved in tech since 2011 covering everything from cameras and swimming pool equipment to the latest gaming consoles and smart TVs. He is on a seemingly never ending hunt to build the easiest to use home media system. &lt;/p&gt;&lt;p&gt;Before Tom’s Guide, Scott worked for publications like &lt;em&gt;Digital Trends, Outdoor Photographer, Dead Beats Panel&lt;/em&gt;, and in a brief detour, &lt;em&gt;America’s Funniest Home Videos&lt;/em&gt;. Yes, he has seen more pratfalls, silly pets and ridiculous home movie fails than is reasonably healthy. &lt;/p&gt;&lt;p&gt;When not writing about the latest devices or advances in chipsets, be sure to ask about Scott about disc golf and sustainability, or just if you’re being cheeky, ask about his noodle arm. If you truly want to get nerdy, bring up board games and his ongoing losing streak. &lt;/p&gt;&lt;p&gt;Scott joined Tom&#039;s Guide in 2024 as the West Coast Reporter. He graduated from the School of Journalism at the University of Oregon with a degree in magazine journalism and a minor in communications. While there he blogged or wrote for several magazines including the Fluxx, Ethos and the Oregon Commentator. He briefly wrote and managed a moderately successful blog focused on web comics. &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/CBRgpGNSoTrkkwFE6i9CUF-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Xbox and Samsung]]></media:description>                                                            <media:text><![CDATA[Xbox and Samsung]]></media:text>
                                <media:title type="plain"><![CDATA[Xbox and Samsung]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/CBRgpGNSoTrkkwFE6i9CUF-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Today (7/22), Xbox introduced a new early release program it's calling Xbox Compatibility on PC. It's an interesting move as rival <a href="https://www.tomsguide.com/gaming/a-playstation-6-without-a-disc-drive-im-done-with-sony">Sony faces an ongoing backlash</a> for ditching discs.</p><p>In the <a href="https://news.xbox.com/en-us/2026/07/22/xbox-backward-compatibility-on-pc/" target="_blank">announcement post</a>, Xbox said that the program will let you play classic Xbox games on either your PC or gaming handheld consoles like the <a href="https://www.tomsguide.com/gaming/handheld-gaming/rog-xbox-ally-x-review">ROG Xbox Ally X</a>.</p><p>"We don’t want to leave our gaming legacy behind even as technology continues to evolve and advance. We expect our library of games to move forward with us and to be able to play them in entirely new ways."</p><p>The program is starting with four original Xbox games coming to PC for the first time. Xbox says that new features are also being added, like customizable graphic settings, up to 4x resolution upscaling, VSync support, Fullscreen and Windowed display modes, and anti-aliasing.</p><p>Here are the four starting games:</p><ul><li><em><strong>BLiNX: The Time Sweeper </strong></em></li><li><em><strong>Conker: Live and Reloaded </strong></em></li><li><em><strong>Crimson Skies: High Road to Revenge </strong></em></li><li><em><strong>Fuzion Frenzy</strong></em></li></ul><p>Each game costs $9.99, though at the time of writing, Fuzion Frenzy is on sale for $7.50. They're available for purchase now and are included in all Xbox Game Pass plans.</p><p>Of the four, I'd personally recommend Fuzion Frenzy or Crimson Skies. If you're unfamiliar, Crimson Skies is an arcade flier while Fuzion Frenzy is a more sci-fi Mario Party from the original Xbox. </p><p>If you already have licenses for these games, they'll carry over to your PC or handheld console.</p><p>Here are the minimum requirements to run these games per Xbox:</p><ul><li><strong>GPU: </strong>Nvidia GTX 950 or AMD Radeon RX 550 or Intel UHD 770 or Intel Arc A310</li><li><strong>CPU</strong>: Min 4 cores: Intel Core i3-8100 or AMD Ryzen 3 1200 or AMD Ryzen Z2 A Processor</li><li><strong>RAM: </strong>8GB</li><li><strong>OS: </strong>Windows 11</li><li><strong>Drivers and versions: </strong>Latest version as of January 2026</li></ul><p>Xbox is starting with those four titles, but it's not clear when any more games will be added. Achievements will arrive in the coming months.</p><p>But these four are a decent start.</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/computing/dlss-5-is-fully-controllable-from-the-developer-nvidias-upscaler-might-be-better-than-expected">"DLSS 5 is fully controllable from the developer": Nvidia’s upscaler might be better than expected</a></li><li><a href="https://www.tomsguide.com/gaming/nintendo/splatoon-raiders-review">Splatoon Raiders review: An ink-soaked looter shooter</a></li><li><a href="https://www.tomsguide.com/gaming/playstation/if-playstation-wants-to-succeed-with-all-digital-it-needs-to-follow-the-steam-model-5-ways-it-can-win-over-gamers-like-me">If PlayStation wants to succeed with all-digital, it needs to follow the Steam model — 5 ways it can win over gamers like me</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ "DLSS 5 is fully controllable from the developer": Nvidia’s upscaler might be better than expected ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/dlss-5-is-fully-controllable-from-the-developer-nvidias-upscaler-might-be-better-than-expected</link>
                                                                            <description>
                            <![CDATA[ The original DLSS 5 announcement was controversial, but Nvidia has now addressed many of the key concerns. Here’s how DLSS 5 will maintain artistic intent for games. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">PGEiQUbugQ2LRUsFgAYq5j</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/PJS2JJLoZ3qWusm2ZFjrAW-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 22 Jul 2026 16:11:40 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/PJS2JJLoZ3qWusm2ZFjrAW-1280-80.jpg">
                                                            <media:credit><![CDATA[Nvidia]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Nvidia DLSS 5]]></media:description>                                                            <media:text><![CDATA[Nvidia DLSS 5]]></media:text>
                                <media:title type="plain"><![CDATA[Nvidia DLSS 5]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/PJS2JJLoZ3qWusm2ZFjrAW-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>To say that people weren’t impressed when <a href="https://www.tomsguide.com/computing/gpus/deciphering-dlss-5-pc-gaming-breakthrough-or-nvidias-ai-slop-era">Nvidia DLSS 5</a> was announced would be an understatement. Gamers and critics alike expressed concerns over heavy-handed “beauty filters” smoothing out character faces and AI overwriting developer art direction. The initial requirement of a second GPU for rendering also didn’t go over well.</p><p>At SIGGRAPH, Nvidia held a follow-up keynote that was practically built to address the concerns folks have with DLSS 5. Instead of focusing on how photo-realistic DLSS 5 could make graphics appear, the keynote centered around the amount of control artists will have over the technology.</p><p>Here’s a breakdown of what Nvidia discussed at SIGGRAPH and how DLSS 5 might not be as bad as we feared.</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/vXDetI2TUWw" allowfullscreen></iframe></div></div><h2 id="granular-control">Granular control</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="YxnzjvFDDGGrmrSjc9iYRU" name="Nvidia DLSS 5 three models 2" alt="Nvidia DLSS 5" src="https://cdn.mos.cms.futurecdn.net/YxnzjvFDDGGrmrSjc9iYRU.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: Nvidia)</span></figcaption></figure><p>As you might recall, the biggest complaint with DLSS 5 is how the graphics appeared to have an Instagram/TikTok filter slapped over them. A less charitable description would be an “AI slop” filter. Nvidia addressed this concern directly, saying that game artists would have full control over a game’s graphics.</p><p>Developers won’t be forced into all-or-nothing with AI. They’ll be able to mask out individual characters, faces, props, or background elements so DLSS 5 either ignores them or processes them with tailored settings. Structural and Tone Intensity sliders will give devs fine control over how things appear. There will also be three distinct AI models for developers to assign. </p><h2 id="no-ai-overwrites">No AI overwrites</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="mnvD4pGZ6ePcqrKZBC2UR5" name="Nvidia DLSS 5 granular controls" alt="DLSS 5" src="https://cdn.mos.cms.futurecdn.net/mnvD4pGZ6ePcqrKZBC2UR5.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: Nvidia)</span></figcaption></figure><p>Another concern is that the AI would hallucinate on low-poly geometry or rewrite hand-crafted visuals. DLSS 5 isn’t generating a game scene from scratch but relies strictly on internal game engine buffers to preserve the artist’s original intent.</p><p>Nvidia emphasized that traditional rasterization and ray tracing still build the entire frame first, defining geometry, lighting anchors, motion vectors, and surface normals. Nvidia framed DLSS 5 as a third category of AI rendering alongside upscaling reconstruction and frame generation. The engine creates the world while the model enriches complex lighting elements.</p><h2 id="latency">Latency</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="q7R5wTB9YVYfCsA6htPPrd" name="Nvidia DLSS 5 frames" alt="Nvidia DLSS 5" src="https://cdn.mos.cms.futurecdn.net/q7R5wTB9YVYfCsA6htPPrd.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: Nvidia)</span></figcaption></figure><p>Generative video models usually process frames in batches, which can introduce input lag. That’s obviously a non-starter for fast-paced games like CSGO 2.</p><p>Nvidia says that DLSS 5 processes the current frame using the game’s engine’s native motion vectors without looking ahead to future frames. By avoiding multi-frame batch processing, Nvidia’s goal is to eliminate both generative latency and temporal shimmering artifacts.</p><h2 id="one-gpu-needed-not-two">One GPU needed, not two</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:2002px;"><p class="vanilla-image-block" style="padding-top:56.19%;"><img id="m5EFY2WowRnf9kJ5ELvfGg" name="Nvidia DLSS 5 one GPU" alt="DLSS 5" src="https://cdn.mos.cms.futurecdn.net/m5EFY2WowRnf9kJ5ELvfGg.jpg" mos="" align="middle" fullscreen="" width="2002" height="1125" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Nvidia)</span></figcaption></figure><p>When Nvidia first demoed DLSS 5, the computational overhead was so heavy that it reportedly required dual high-end GPUs just to run smoothly. Naturally, this isn’t feasible for most players, but Nvidia says you’ll be able to run DLSS 5 on a single GPU.</p><p>To that end, Nvidia revealed that they have distilled the massive generative model into a much smaller, single-step diffusion model. The updated implementation has been engineered to run on a single RTX GPU with efficient VRAM allocation instead of requiring multi-GPU rigs that only hardcore users own.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OdR22e"></div>                            </div>                            <script src="https://kwizly.com/embed/OdR22e.js" async></script><h2 id="outlook">Outlook</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:5712px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="xWV7Xvua8aPb7TaLHKQ5Jj" name="Nvidia RTX 50 series GPU" alt="Nvidia RTX 50-series GPU held in hand with Nvidia logo on green background" src="https://cdn.mos.cms.futurecdn.net/xWV7Xvua8aPb7TaLHKQ5Jj.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="credit" itemprop="copyrightHolder">(Image credit: Future / Tom's Guide)</span></figcaption></figure><p>I’ve championed Nvidia DLSS for years, but I was one of the folks who wasn’t enamored with that initial DLSS 5 reveal. Now, after SIGGRAPH, I'm less worried about this fall's upcoming update.</p><p>We’ll have to wait to see how the final version functions, but I’m glad that Nvidia has addressed all the major concerns. If we can get richer game graphics without the infamous AI look, then we’ll all be winners.</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/computing/gpus/what-is-nvidia-dlss-explaining-the-ai-tech-transforming-pc-gaming-and-why-its-getting-controversial">What is Nvidia DLSS? Explaining the AI tech transforming PC gaming — and why it’s getting controversial</a></li><li><a href="https://www.tomsguide.com/gaming/theyre-completely-wrong-nvidia-ceo-jensen-huang-responds-to-dlss-5-criticism">Nvidia's 'GPT moment' for graphics rejected by gamers; CEO Jensen Huang rushes to defend DLSS 5</a></li><li><a href="https://www.tomsguide.com/gaming/pc-gaming/deciphering-dlss-4-5-i-tested-nvidias-new-upscaler-and-figured-out-when-to-use-model-l-or-m">DLSS 4.5 is now live — I tested Nvidia’s upscaler to see which model you should actually use</a></li></ul><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=laptops&min_discount_ratio=0.95&widget_title=Top+Deals+Handpicked+by+Our+Editors&widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&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 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%;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      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 {      display: flex;      gap: 12px;      justify-content: center;      flex-wrap: wrap;    }    .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;    }        .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 {      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;    }        .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);      display: -webkit-box;      -webkit-line-clamp: 2;      -webkit-box-orient: vertical;      overflow: hidden;    }    .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;    }    .tg-df-container .tg-df-card-cta.tg-df-cta-savings-squad {      background-color: #3c8d0d;    }    .tg-df-card:hover .tg-df-card-cta.tg-df-cta-savings-squad,    .tg-df-card-cta.tg-df-cta-savings-squad:hover {      background-color: #2b6509;    }    /*       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: 0;      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: 0 16px;      }            .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-filters {        width: calc(100% + 32px);        margin: 0 -16px;        padding: 0 16px 4px 16px;        display: flex;        justify-content: flex-start;        gap: 8px;        flex-wrap: nowrap;        overflow-x: auto;        -webkit-overflow-scrolling: touch;        scrollbar-width: none;      }      .tg-df-filters::after {        content: "";        display: block;        flex: 0 0 8px;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }            .tg-df-sort-wrapper {        flex: 0 0 max(42%, 130px);        min-width: 0;      }      .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;      }            .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;        -webkit-line-clamp: 3;      }      /* 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;        -webkit-line-clamp: 3;        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;    }    .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: 16px;      text-align: center;      width: 100%;      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; }    @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: #f8fafc;      border-color: #cbd5e1;    }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right {      background-color: rgba(255, 255, 255, 0.4);      border: none;      box-shadow: none;      backdrop-filter: blur(4px);      -webkit-backdrop-filter: blur(4px);    }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right { right: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-right { right: 0; }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left:hover,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);      border: none;    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-carousel-roundels::after {      content: "";      flex: 0 0 32px;    }    .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;      transition: font-weight 0.2s;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-label {      font-weight: 700;    }    .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;      display: inline-flex;      align-items: center;      justify-content: center;      min-height: 36px;      box-sizing: border-box;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .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::after {      content: "";      flex: 0 0 32px;    }    .tg-df-grid-wrapper {      position: relative;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card {      flex: 0 0 auto;      width: 100px;      border-radius: 15px;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      border: 2px solid #1e293b;      background: white;      color: #1e293b;      display: flex;      flex-direction: column;      justify-content: center;      align-items: center;      font-weight: 600;      font-size: 14px;      cursor: pointer;      padding: 16px;      text-align: center;      transition: all 0.2s;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card:hover {      background: #1e293b;      color: white;    }    .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;      -webkit-line-clamp: 2;      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 {      -webkit-line-clamp: 3;    }    .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.45);        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: #5aaf0b; 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: #4a9109; 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; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \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-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\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>        \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-controls" id="tg-df-controls" style="display:flex;">      \x3Cdiv class="tg-df-top-bar">        \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>                \x3Cdiv class="tg-df-settings-wrapper">          \x3Cbutton type="button" class="tg-df-settings-btn" aria-label="Settings" id="tg-df-settings-toggle">            \x3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20">                \x3Cpath d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.73 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .43-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.49-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>            \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-settings-dropdown-backdrop" id="tg-df-settings-backdrop">\x3C/div>          \x3Cdiv class="tg-df-settings-dropdown" id="tg-df-settings-panel">            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Search Region\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-region-select">                \x3Coption value="auto">🌍 Auto-detect\x3C/option>                \x3Coption value="US">🇺🇸 United States (US)\x3C/option>                \x3Coption value="GB">🇬🇧 United Kingdom (UK)\x3C/option>                \x3Coption value="CA">🇨🇦 Canada (CA)\x3C/option>                \x3Coption value="AU">🇦🇺 Australia (AU)\x3C/option>                \x3Coption value="DE">🇩🇪 Germany (DE)\x3C/option>                \x3Coption value="FR">🇫🇷 France (FR)\x3C/option>                \x3Coption value="IT">🇮🇹 Italy (IT)\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Retailer\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-retailer-select">                \x3Coption value="">All Retailers\x3C/option>                \x3Coption value="Amazon">Amazon\x3C/option>                \x3Coption value="Walmart">Walmart\x3C/option>                \x3Coption value="Best Buy">Best Buy\x3C/option>                \x3Coption value="Target">Target\x3C/option>                \x3Coption value="John Lewis">John Lewis\x3C/option>                \x3Coption value="Currys">Currys\x3C/option>                \x3Coption value="Argos">Argos\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Offer Type\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-offer-type-select">                \x3Coption value="">All Offers\x3C/option>                \x3Coption value="amazon_prime">Amazon Prime\x3C/option>                \x3Coption value="recommended_promo">Recommended Promo\x3C/option>                \x3Coption value="amazon_lightning">Amazon Lightning Deal\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Result Count\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-rows-select">                \x3Coption value="3">3 Items\x3C/option>                \x3Coption value="4">4 Items\x3C/option>                \x3Coption value="6">6 Items\x3C/option>                \x3Coption value="12" selected>12 Items\x3C/option>                \x3Coption value="24">24 Items\x3C/option>                \x3Coption value="48">48 Items\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Deal Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Only show products with active offers or previous prices (was_price)\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-deal-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Editor Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Enable multi-select to copy deals to CMS\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-editor-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">View Mode\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-view-mode-select">                \x3Coption value="auto">Auto Collection\x3C/option>                \x3Coption value="carousel">Carousel\x3C/option>                \x3Coption value="savings_squad">Savings Squad\x3C/option>                \x3Coption value="grid">Grid (Columns)\x3C/option>                \x3Coption value="row">Row (List)\x3C/option>              \x3C/select>            \x3C/div>          \x3C/div>        \x3C/div>      \x3C/div>      \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">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/>          \x3C/svg>          \x3Cselect class="tg-df-sort-select" aria-label="Sort Deals">            \x3Coption value="date_desc">Newest First\x3C/option>            \x3Coption value="best_match">Sort by: Match\x3C/option>            \x3Coption value="price_asc">Price Low to High\x3C/option>            \x3Coption value="price_desc">Price High to Low\x3C/option>            \x3Coption value="discount_desc">Biggest Discount\x3C/option>          \x3C/select>        \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!-- 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();            if (['carousel', 'carousel-compact', 'auto', 'grid', 'row'].includes(this.getViewMode())) { this.loadCarouselSpreadsheet(); }        }        getViewMode() {          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();          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          if (mode === 'carousel' || mode === 'auto' || mode === 'grid' || mode === 'row') {             if (mode === 'carousel') this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container') && mode === 'carousel') {               this.root.classList.add('is-carousel');             } else if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             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 (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Everything';             if (this.discountFilter && !params.has('min_discount_ratio')) {               this.discountFilter.value = '5';             }          }          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 (params.has('bg_color')) {            const bg = params.get('bg_color');            if (bg === 'white') {              this.root.style.setProperty('background-color', '#ffffff', 'important');            } else if (bg === 'transparent') {              this.root.style.setProperty('background-color', 'transparent', 'important');            } else if (bg === 'light_blue') {              this.root.style.setProperty('background-color', '#E7F0FF', 'important');            }          } else {             this.root.style.removeProperty('background-color');          }                    if (params.has('view_mode')) {            if (this.viewModeSelect) {              this.viewModeSelect.value = params.get('view_mode');            } else {              this.viewModeOverride = 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') || 'discount_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }                    // 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) {            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 !== 'discount_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 roundels = this.root.querySelectorAll('.tg-df-carousel-cat.original-hardcoded');          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');              }            });          }          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              if (this.getViewMode() === 'savings_squad' && this.autocompleteDropdown && this.airedaleTags && query.length > 0) {                 const matches = this.airedaleTags.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase()).slice(0, 5);                 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');                 }              } else if (this.autocompleteDropdown) {                 this.autocompleteDropdown.classList.remove('active');              }              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  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;                this.activeDealTag = null;                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   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;                   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 });              this.activeDealTag = null;              this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.fetchDeals(query);              }            });          }          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;               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 = this.viewModeSelect.value === 'savings_squad' ? 'date_desc' : 'discount_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 loadCarouselSpreadsheet() {          try {              const parseCSVRow = (str) => {                  let result = [], cur = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (inQuotes) {                          if (char === '"') {                              if (str[i + 1] === '"') { cur += '"'; i++; }                              else { inQuotes = false; }                          } else { cur += char; }                      } else {                          if (char === '"') { inQuotes = true; }                          else if (char === ',') { result.push(cur); cur = ''; }                          else { cur += char; }                      }                  }                  result.push(cur); return result;              };              const parseCSV = (str) => {                  const rows = []; let curRow = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (char === '"') inQuotes = !inQuotes;                      if ((char === '\n' || char === '\r') && !inQuotes) {                          if (char === '\r' && str[i+1] === '\n') i++;                          if (curRow) rows.push(parseCSVRow(curRow));                          curRow = '';                      } else { curRow += char; }                  }                  if (curRow) rows.push(parseCSVRow(curRow));                  return rows;              };              const preloadedCSV = decodeURIComponent(escape(atob("LCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNQ0KUm91bmRlbCB0ZXh0LEFsbCxUVnMsRm9vdHdlYXIsQXBwYXJlbCxNYXR0cmVzZXMsQXBwbGlhbmNlcyxXZWFyYWJsZSB0ZWNoLEhlYWRwaG9uZXMsU21hcnQgSG9tZSxTcGVha2VycyxMYXB0b3BzLFRhYmxldHMsQ29tcHV0aW5nLFBob25lcyxHYW1pbmcsTGVnbw0KUm91bmRlbCBpbWFnZSxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2FpLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3R2cy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvN2IzYTIyNGIwNzk2M2M2MjdiNmI5MDliZDc4MzM4MzZlMDJmZjgxOS5qcGcud2VicCxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy84NGRhYzVkNDhlZDJkNDQ4NTU5ZWJhNjdhY2U4MzE0Y2M2N2NjZDk0LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvbWF0dHJlc3Nlcy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvNzY4ZTk3Y2ViMDcxODAxZmFlMjA5MTBkMDgyMGIxNmY3NDdhZjkzOS5qcGcud2VicCxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3dlbGxuZXNzLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2hlYWRwaG9uZXMuanBnLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzg5NTM1YmVlYmUyMGRiYmQ0YTM0NmQ2ZDZiZGZlOTFkOGE4ODRhMjEuanBnLndlYnAsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9hdWRpby5qcGcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9sYXB0b3BzLmpwZyxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy8yMzk3NTY0ZWQ3YTVmZjk0N2U5YjZiMzBlNTRmNDc0OTRiODQxZjg5LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvY29tcHV0aW5nLmpwZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3Bob25lcy5wbmcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9nYW1pbmcucG5nLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzRmNmM2MjFjYWMwYmMxYTg1ZDU5M2UzNTk0YmE1YjM0OWVmZmQyOTIuanBnLndlYnANClNlYXJjaCBRdWVyeSxFdmVyeXRoaW5nLFRlbGV2aXNpb25zLCJTbmVha2VycywgcnVubmluZyBzaG9lcywgc2FuZGFscyIsQ2xvdGhpbmcsTWF0dHJlc3NlcyxIb21lIEFwcGxpYW5jZXMsV2VhcmFibGVzICYgRml0bmVzcyBUZWNoLEhlYWRwaG9uZXMsSG9tZSBUZWNoLFNwZWFrZXJzLExhcHRvcHMsVGFibGV0cyxDb21wdXRpbmcsUGhvbmVzLEdhbWluZyxDb25zdHJ1Y3Rpb24gVG95cw0KRGlzY291bnQgQW1vdW50LG1pbiA1JSxtaW4gMTAlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUNClByaWNlIFJhbmdlLCwsLCxtaW4gJDQwMCwsLCxtaW4gJDI1LCxtaW4gJDMwMCwsLG1pbiAkMTAwLCwNCkJyYW5kIFNlbGVjdGlvbiwsLCwsLCwsLCwsLCwsLCwNCkZpbHRlciBidXR0b25zLCwsLCwsLCwsLCwsLCwsLA0KMSxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMNCjIsQW1hem9uIGRlYWxzLFVuZGVyICQxMDAwLDUwJSBvZmYsQWRpZGFzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsNTAlIG9mZixBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscw0KMyxPdmVyICQ0MDAsVW5kZXIgJDUwMCxIb2thLE5pa2UsU2FhdHZhLE5pbmphLDQwJSBvZmYsSkxhYiwsSkJMLERlbGwsLEFzdXMsQXBwbGUsQ29uc29sZXMsU3RhciBXYXJzDQo0LFVuZGVyICQxMDAwLDUwJSBvZmYsU2tlY2hlcnMsVW5kZXIgQXJtb3VyLEhlbGl4LFNoYXJrLEdhcm1pbixBbmtlciBTb3VuZGNvcmUsUmluZyxTb25vcyxBcHBsZSxBcHBsZSxUUC1saW5rLFNhbXN1bmcsQWNjZXNzb3JpZXMsVW5kZXIgJDI1DQo1LFVuZGVyICQ1MDAsTEcsQXNpY3MsQ29sdW1iaWEsRHJlYW1DbG91ZCxLZXVyaWcsQXBwbGUsU29ueSxHb3ZlZSxUcmliaXQsTGVub3ZvLFNhbXN1bmcsRWVybyxHb29nbGUsR2FtZXMsVW5kZXIgJDUwDQo2LDUwJSBvZmYsU2Ftc3VuZyxOaWtlLFBhdGFnb25pYSxOZWN0YXIsRGUnTG9uZ2hpLEFtYXpmaXQsQXBwbGUsS2FzYSBzbWFydCxTb255LEFsaWVud2FyZSxUQ0wsTmV0Z2VhcixNb3Rvcm9sYSxOaW50ZW5kbyxCb3RhbmljYWxzDQo3LEFtYXpvbixIaXNlbnNlLE5ldyBCYWxhbmNlLEFyYyd0ZXJ5eCxUZW1wdXItcGVkaWMsRHlzb24sRml0Yml0LEJlYXRzLFBoaWxpcHMgSHVlLEFua2VyLEFjZXIsT25lUGx1cyxEZWxsLE9uZVBsdXMsU29ueSxEaXNuZXkNCjgsQXBwbGUsVENMLEFkaWRhcyxDYXJoYXJ0dCxCZWFyLEJpc3NlbGwsU2Ftc3VuZyxFYXJmdW4sQmxpbmssQmVhdHMsTVNJLE1pY3Jvc29mdCxBY2VyLE5vdGhpbmcsWGJveCxNYXJ2ZWwNCjksLFNvbnksU2F1Y29ueSxUaGUgTm9ydGggRmFjZSxTaWVuYSxOdXRyaWJ1bGxldCxPdXJhLFNhbXN1bmcsR29vZ2xlIE5lc3QgLE1hcnNoYWxsLFNhbXN1bmcsTGVub3ZvLExlbm92bywsLFBva2Vtb24NCjEwLCxSb2t1LEJpcmtlbnN0b2NrLENSWiBZb2dhLFdpbmtCZWRzLEJsYWNrIGFuZCBEZWNrZXIsUmluZ2Nvbm4sQ01GLEV1ZnksU2Ftc3VuZyxNaWNyb3NvZnQsUmVNYXJrYWJsZSxBbGllbndhcmUsLCwNCjExLCwsQnJvb2tzLFRoZSBHeW0gUGVvcGxlLEJyb29rbHluIGJlZGRpbmcsTmVzcHJlc3NvLCwxTW9yZSxBcmxvLCxSYXplciwsQ29yc2FpciwsLA0KMTIsLCxDcm9jcywsRWlnaHQgU2xlZXAsQ3Vpc2luYXJ0LCxKQkwsLCwsLEhQLCwsDQpOb3RlcywsLCwsLCwsLCwsLCwsLCwNCiwsIlByaW9yaXRpc2UgYmlnZ2VzdCAlLyQgZGlzY291bnQsIFR2cyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiB0aGUgbW9zdCBwb3B1bGFyIGV2ZW4gaWYgdGhleSBhcmUgc3RpbGwgZXhwZW5zaXZlIiwiTm8gcGF0dGVybiB0byBwcmljaW5nL2Rpc2NvdW50LCByZWFkZXJzIG1haW5seSBzaG9wIGJ5IGJyYW5kL3JlY29nbmlzYWJsZSBzaG9lcyIsIk5vIHBhdHRlcm4gdG8gcHJpY2luZy9kaXNjb3VudCwgcmVhZGVycyBtYWlubHkgc2hvcCBieSBicmFuZCIsIkEgbGFiZWwgd2lsbCBkZWZpbml0ZWx5IGhlbHAgaGVyZSBlLmcuIGJlc3QgZm9yIHNpZGUgc2xlZXBlciwgYmVzdCBtZW1vcnkgZm9hbSIsIkFwcGxpYW5jZXMgaXMgYSBiaWcgY2F0ZWdvcnksIGlzIGl0IHBvc3NpYmxlIHRvIHNwbGl0IGludG8ga2l0Y2hlbiBhcHBsaWFuY2VzLCBmbG9vcmNhcmUsIGFpciBoZWFsdGgvY29vbGluZz8gT3Igc2ltaWxhciIsIkZvY3VzIG9uIHZhbHVlIGZvciBtb25leSwgR2FybWlucyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiBwb3B1bGFyIGV2ZW4gdGhvdWdoIHRoZXkgYXJlIHN0aWxsICQ1MDAiLCwsLCxJbmNsdWRlIEtpbmRsZXMsSSB3b3VsZCBpbmNsdWRlIHdpZmkgcm91dGVycyBoZXJlIGluc3RlYWQgb2Ygc21hcnQgaG9tZSxDYW4gd2Ugc3VyZmFjZSBwaG9uZSBwcm92aWRlciBkZWFscz8gVC1tb2JpbGUgYW5kIHZlcml6b24gd291bGQgbWFrZSBhIGxvdCBtb3JlIG1vbmV5IHRoYW4gQW1hem9uLCwNCiwsaGF2aW5nIGEgJ2Jlc3QgZm9yJyBsYWJlbCB3b3VsZCBiZSBoZWxwZnVsIGUuZy4gYmVzdCBmb3IgYnJpZ2h0IHJvb20sQ2FuIHdlIHN0b3Aga2lkcyBzaG9lcyBmcm9tIHB1bGxpbmcgdGhyb3VnaD8sIldpbGwgdGhpcyBpbmNsdWRlIGFjY2Vzc29yaWVzIGUuZy4gY2FwcywgYmFncywgaWYgc28gbWFrZSBzdXJlIHRoZXNlIGFyZSBtaXhlZCB0aHJvdWdob3V0IGNsb3RoaW5nIGRlYWxzIixXaWxsIHRoaXMgaW5jbHVkZSB0b3BwZXJzIGFuZCBwaWxsb3dzPyBTZWVpbmcgbW9yZSBtb21lbnR1bSB3aXRoIHRoaXMgY2F0ZWdvcnkgcmVjZW50bHkgc28gYSBiZWRkaW5nIHRhYiBtaWdodCB3b3JrLCwiTmVlZCB0byBtYWtlIHN1cmUgYmFuZHMsIHNjcmVlbiBwcm90ZWN0b3JzIGV0Yy4gZG9uJ3QgcHVsbCBpbnRvIGhlcmUiLCwsLCwsLCwsDQosLCJQcmlvcml0aXNlIDY1JycgYW5kIDU1JyBpbmNoIFRWcywgdGhlbiBiaWdnZXIgc2NyZWVucyBiZWZvcmUgdGhlIHNtYWxsZXIgc2l6ZXMiLCwsUXVlZW4gaXMgdGhlIG1vc3QgcG9wdWxhciBzaXplIGluIHRoZSBVUyAtIHByaW9yaXRpc2UgZGVhbHMgZm9yIHRoaXMgc2l6ZSwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpDYXRlZ29yaWVzIHRvIGNvbnNpZGVyLCxQcm9kdWN0cyBpbmNsdWRlZCwsLCwsLCwsLCwsLCwsDQpVbmRlciAkNTA/LCxBaXIgdGFncywsLCwsLCwsLCwsLCwsDQosLFBvcnRhYmxlIGNoYXJnZXJzL3dpcmVsZXNzIGNoYXJnZXJzLCwsLCwsLCwsLCwsLCwNCiwsIldhdGVyIGJvdHRsZXMgKHN0YW5sZXlzLCBPd2FsYSwgSHlkcm8gZmxhc2ssIFlldGkpIiwsLCwsLCwsLCwsLCwsDQosLEhhbmQgaGVsZCBmYW5zLCwsLCwsLCwsLCwsLCwNCiwsLCwsLCwsLCwsLCwsLCwNCmhvbWUgb2ZmaWNlLCxvZmZpY2UgY2hhaXJzLCwsLCwsLCwsLCwsLCwNCiwsc3RhbmRpbmcgZGVza3MsLCwsLCwsLCwsLCwsLA0KLCxtb25pdG9ycywsLCwsLCwsLCwsLCwsDQosLEtleWJvYXJkcywsLCwsLCwsLCwsLCwsDQosLGRvY2tpbmcgc3RhdGlvbiwsLCwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpHYW1pbmcsLENvbnNvbGVzLCwsLCwsLCwsLCwsLCwNCiwsQWNjZXNzb3JpZXMsLCwsLCwsLCwsLCwsLA0KLCxHYW1lcywsLCwsLCwsLCwsLCwsDQosLENvdWxkIGluY2x1ZGUgTGVnbz8sLCwsLCwsLCwsLCwsLA==")));              const text = preloadedCSV;              const parsed = parseCSV(text);                            const rowsByName = {};              let filterStart = -1;              parsed.forEach((rc, i) => {                 if (rc && rc.length > 0 && rc[0]) rowsByName[rc[0]] = rc;                 if (rc && rc.length > 0 && rc[0] === 'Filter buttons') filterStart = i;              });                            const cols = [];              if(rowsByName['Roundel text']) {                const headerRow = rowsByName['Roundel text'];                for(let col = 1; col < headerRow.length; col++) {                   let label = headerRow[col];                   if (!label) continue;                                      let q = rowsByName['Search Query'] && rowsByName['Search Query'][col] ? rowsByName['Search Query'][col] : '';                   let img = rowsByName['Roundel image'] && rowsByName['Roundel image'][col] ? rowsByName['Roundel image'][col] : '';                   let ds = rowsByName['Discount Amount'] && rowsByName['Discount Amount'][col] ? rowsByName['Discount Amount'][col] : '';                   let pr = rowsByName['Price Range'] && rowsByName['Price Range'][col] ? rowsByName['Price Range'][col] : '';                   let rt = rowsByName['Retailer'] && rowsByName['Retailer'][col] ? rowsByName['Retailer'][col] : '';                   let ot = rowsByName['Offer Type'] && rowsByName['Offer Type'][col] ? rowsByName['Offer Type'][col] : '';                                      let filters = [];                   if(filterStart > 0) {                     for(let r = filterStart + 1; r < parsed.length; r++) {                         if(!parsed[r] || parsed[r][0] === 'Notes' || parsed[r][0] === 'Categories to consider') break;                         let f = parsed[r][col];                         if(f) filters.push(f);                     }                   }                   cols.push({ label, img, q, ds, pr, rt, ot, filters });                }              }              this.carouselData = cols;              if (this.carouselData && this.carouselData.length > 0) {                 const isMatched = this.carouselData.some(c => c.q === this.currentQuery || c.label === this.currentQuery);                 if (!isMatched) {                    const first = this.carouselData[0];                    this.currentQuery = first.q || first.label;                    if (this.priceFilter) this.priceFilter.value = 'all';                    if (this.customPriceMin) this.customPriceMin.value = '';                    if (this.customPriceMax) this.customPriceMax.value = '';                    let dPr = first.pr || 'all';                    if (typeof dPr === 'string' && dPr !== 'all') {                       let prLower = dPr.toLowerCase();                       if (prLower.includes('min') || prLower.includes('over')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else if (prLower.includes('max') || prLower.includes('under')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       }                    }                    let dAm = '0';                    if(first.ds && typeof first.ds === 'string') {                       let m = first.ds.match(/(\d+)/);                       if(m) dAm = m[1];                    }                    if (this.discountFilter) this.discountFilter.value = dAm;                    if (this.offerTypeSelect) this.offerTypeSelect.value = first.ot || '';                    if (this.retailerSelect) this.retailerSelect.value = first.rt || '';                    this.selectedBrands = [];                    if (this.brandDropdown) {                        const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                        chks.forEach(chk => chk.checked = false);                    }                    if (this.searchInput) this.searchInput.value = this.currentQuery;                 }              }              this.renderCarouselUI();          } catch(e){ console.warn(e); }        }                renderCarouselUI() {           const roundelWrapper = this.root.querySelector('.tg-df-carousel-roundels');           if(!roundelWrapper || !this.carouselData) return;                      let html = '';           this.carouselData.forEach(r => {              const q = r.q || r.label;              const isActive = (this.currentQuery === q || this.currentQuery === r.label) ? 'active' : '';              const imgHtml = r.img ? `\x3Cimg src="${r.img}" alt="${r.label}" />` : `\x3Csvg width="32" height="32" fill="#1F69FF" viewBox="0 0 24 24">\x3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>\x3C/svg>`;              html += `                \x3Cdiv class="tg-df-roundel tg-df-carousel-cat ${isActive}" data-label="${this.escapeHTML(r.label)}">                  \x3Cdiv class="tg-df-roundel-img-box">${imgHtml}\x3C/div>                  \x3Cspan class="tg-df-roundel-label">${this.escapeHTML(r.label)}\x3C/span>                \x3C/div>              `;           });           roundelWrapper.innerHTML = html;                      // Rebind clicks           const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');           roundels.forEach(rNode => {             rNode.addEventListener('click', () => {                const r = this.carouselData.find(c => c.label === rNode.getAttribute('data-label'));                 if(!r) return;                                  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: r.label,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = r.q || r.label;                const labelTitle = this.root.querySelector('#tg-df-carousel-title-label');                if (labelTitle) labelTitle.textContent = 'Best ' + this.currentQuery;                if (this.priceFilter) this.priceFilter.value = 'all';                if (this.customPriceMin) this.customPriceMin.value = '';                if (this.customPriceMax) this.customPriceMax.value = '';                let dPr = r.pr || 'all';                if (typeof dPr === 'string' && dPr !== 'all') {                   let prLower = dPr.toLowerCase();                   if (prLower.includes('min') || prLower.includes('over')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMin) this.customPriceMin.value = m[1];                   } else if (prLower.includes('max') || prLower.includes('under')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMax) this.customPriceMax.value = m[1];                   }                }                                let discountAmount = '0';                if(r.ds && typeof r.ds === 'string') {                   let m = r.ds.match(/(\d+)/);                   if(m) discountAmount = m[1];                }                if (this.discountFilter) this.discountFilter.value = discountAmount;                if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                                // Clear brands                    this.selectedBrands = [];                    if (this.brandDropdown) {                    const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                    chks.forEach(chk => chk.checked = false);                }                                if (this.searchInput) this.searchInput.value = this.currentQuery;                                roundels.forEach(ro => ro.classList.remove('active'));                if (rNode) rNode.classList.add('active');                                this.renderCarouselFilters(r);                this.fetchDeals(this.currentQuery);             });           });                      // Auto-highlight active           const activeR = this.carouselData.find(c => c.q === this.currentQuery || c.label === this.currentQuery);           if(activeR) this.renderCarouselFilters(activeR);        }                renderCarouselFilters(r) {           const filtersWrap = this.root.querySelector('.tg-df-carousel-filters-wrap');           if(!filtersWrap) return;                      let html = `\x3Cbutton class="tg-df-carousel-filter-btn" data-type="all">All\x3C/button>`;                      r.filters.forEach(f => {              let fL = f.toLowerCase();              let icon = '';              let logic = `data-type="custom" data-v="${this.escapeHTML(f)}"`;              if (fL === 'amazon deals' || fL === 'prime deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\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>`;              } else if (fL === 'lightning deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\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>`;              } else {                 if (fL.includes('lightning')) {                    icon = `\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-zap">\x3Cpolygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2">\x3C/polygon>\x3C/svg>`;                 } else if (fL.includes('% off')) {                    icon = `\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>`;                 } else if (fL.includes('under') || fL.includes('min ')) {                    icon = `\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>`;                 }                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>${icon} ${this.escapeHTML(f)}\x3C/button>`;              }           });                      filtersWrap.innerHTML = html;                      const btns = filtersWrap.querySelectorAll('button');           btns.forEach(b => {             b.addEventListener('click', () => {                const type = b.getAttribute('data-type');                if (type === 'custom') {                   const v = b.getAttribute('data-v');                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-custom-${(v||'').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, name: 'Custom Filter', label: v });                }                if (type === 'all') {                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: 'filter-clear-all', name: 'Clear all', label: 'Clear all filters' });                   // reset everything                   btns.forEach(btn => btn.classList.remove('active'));                   b.classList.add('active');                                      // Reset prices                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   if (this.brandDropdown) {                     const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                     chks.forEach(chk => chk.checked = false);                   }                } else {                   const v = b.getAttribute('data-v');                   const fL = v.toLowerCase();                                      let mapRet = ['amazon', 'walmart', 'best buy', 'target', 'john lewis', 'currys', 'argos'];                   const getCategory = (s) => {                      if (s === 'lightning deals' || s === 'amazon deals' || s === 'prime deals') return 'offer';                      if (s.includes('% off')) return 'discount';                      if (s.includes('under') || s.includes('over') || s.includes('min') || s.includes('max')) return 'price';                      if (mapRet.includes(s)) return 'retailer';                      return 'brand';                   };                   const cat = getCategory(fL);                   const wasActive = b.classList.contains('active');                   if (cat !== 'brand') {                      btns.forEach(btn => {                          if (btn === b) return;                          if (btn.getAttribute('data-type') === 'all') return;                          const bV = btn.getAttribute('data-v');                          if (!bV) return;                          if (getCategory(bV.toLowerCase()) === cat) btn.classList.remove('active');                      });                   }                   if (wasActive) b.classList.remove('active');                   else b.classList.add('active');                   let anyActive = Array.from(btns).some(btn => btn !== btns[0] && btn.classList.contains('active'));                   if (!anyActive) {                       btns[0].click();                       return;                   } else {                       btns[0].classList.remove('active');                   }                                      if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   btns.forEach(btn => {                       if (!btn.classList.contains('active') || btn.getAttribute('data-type') === 'all') return;                       const vv = btn.getAttribute('data-v');                       const vl = vv.toLowerCase();                                              if (vl === 'lightning deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_lightning';                       } else if (vl === 'amazon deals' || vl === 'prime deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_prime';                       } else if (vl.includes('% off')) {                          let m = vl.match(/(\d+)%/);                          if (m && this.discountFilter) this.discountFilter.value = m[1];                       } else if (vl.includes('under') || vl.includes('max')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       } else if (vl.includes('min') || vl.includes('over')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else {                          let foundR = mapRet.find(x => x === vl);                          if (foundR) {                             let realR = ['Amazon', 'Walmart', 'Best Buy', 'Target', 'John Lewis', 'Currys', 'Argos'].find(x => x.toLowerCase() === vl);                             if (this.retailerSelect) this.retailerSelect.value = realR;                          } else {                             this.selectedBrands.push(vv);                          }                       }                   });                                      if (this.brandDropdown) {                       const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                       chks.forEach(c => c.checked = this.selectedBrands.includes(c.value));                   }                                      if (r.pr && typeof r.pr === 'string') {                       let prL = r.pr.toLowerCase();                       if (prL.includes('under $')) {                           let m = prL.match(/under \$(\d+)/i);                           if (m && this.customPriceMax && !this.customPriceMax.value) this.customPriceMax.value = m[1];                       }                   }                }                                this.fetchDeals(this.currentQuery);             });           });                      // default to highlighting first           btns[0].classList.add('active');        }async fetchDeals(query, append = false) {          if (!append) {             this.showLoading();             this.deals = [];             this.displayLimit = this.getRowsLimit();          } else {             this.displayLimit += this.getRowsLimit();          }                    try {            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad(append);            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query, append);               } else {                 await this.fetchHawkDeals(query, append);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query, append);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&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=tomsguide&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) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const url = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&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 dynamicBrandsCounts = {};                    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();                   dynamicBrandsCounts[data.brand] = (dynamicBrandsCounts[data.brand] || 0) + 1;                }                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;                   }                }                                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 || ''                });             });          });                    const airedaleBrandsList = Object.keys(dynamicBrandsCounts).map(b => ({              formatted_value: b,              count: dynamicBrandsCounts[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, append = false) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (append && this.deals.length > 0) {            url.searchParams.append('offset', this.deals.length.toString());          }                    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 : (this.getViewMode() === 'savings_squad' ? 'date_desc' : 'discount_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}                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin-top:8px;">${_div}                ${_div}              ${_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)} (${this.airedaleTagCounts[tag] || 0})${_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 = isSavingsSquadMode ? 'View Deal' : 'Check Price';              if (isSavingsSquadMode) {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                  ${_div}                `;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \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 = `                \x3Cdiv class="tg-df-card-merchant-wrapper">                  \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                ${_div}                \x3Cdiv class="tg-df-card-price-group">                  ${isSavingsSquadMode ? '' : `                  \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">\x3Cp>${this.escapeHTML(deal.description)}${_p}${_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>${deal.isCheckPrice ? 'Check Price' : '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}                ${_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 ? `\x3Cp style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 12px; line-height: 1.4;">${this.escapeHTML(deal.description)}${_p}` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${priceGroupHtml}                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta ${isSavingsSquadMode ? 'tg-df-cta-savings-squad' : ''}" style="text-decoration: none;">${ctaText}${_a}                  ${_div}                ${_div}              ${_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 || ((this.getViewMode() === 'carousel' || this.getViewMode() === 'auto') && displayDeals.length > 0 && displayDeals.length % ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12) === 0)) {            if (this.getViewMode() === 'carousel') {               dealsHtml += `                 \x3Cbutton type="button" class="tg-df-load-more-card tg-df-load-more">                   \x3Csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-bottom: 8px;">\x3Cpath d="M5 12h14">\x3C/path>\x3Cpath d="m12 5 7 7-7 7">\x3C/path>\x3C/svg>                   Load More                 ${_button}               `;            } else {               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; display: flex; align-items: center;">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); }                    let gridWrapper = this.grid.parentElement;          if (gridWrapper && gridWrapper.classList.contains('tg-df-grid-wrapper')) {             let rightChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-right');             let leftChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-left');             if (this.getViewMode() === 'carousel') {                 // The observer set up in setupScrollListeners handles visibility.                 if (rightChevron) rightChevron.style.display = 'flex';                 if (leftChevron) leftChevron.style.display = 'none'; // reset correctly             } else {                 if (rightChevron) rightChevron.style.display = 'none';                 if (leftChevron) leftChevron.style.display = 'none';             }          }                    const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', async () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              if (displayDeals.length <= this.displayLimit) {                 loadMoreBtn.innerHTML = `                  <svg class="tg-df-spinner" style="width: 16px; height: 16px; display: inline-block; vertical-align: middle; margin-right: 8px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/></svg>                  Loading...                 `;                 loadMoreBtn.disabled = true;                 await this.fetchDeals(this.currentQuery, true);              } else {                 this.displayLimit += this.getRowsLimit();                 this.render();              }            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();                        // 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');            }            setTimeout(() => {               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);          } 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[ If PlayStation wants to succeed with all-digital, it needs to follow the Steam model — 5 ways it can win over gamers like me ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/playstation/if-playstation-wants-to-succeed-with-all-digital-it-needs-to-follow-the-steam-model-5-ways-it-can-win-over-gamers-like-me</link>
                                                                            <description>
                            <![CDATA[ PlayStation appears to be going all-in on digital games. To make this easier on gamers, it should implement some of Steam's policies. Here's what Sony can do. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">RZxxLUXKiNi3NuokYLVCbf</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/y5T6EzpDkzjkm8NbGVewWW-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 18 Jul 2026 15:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Playstation]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/y5T6EzpDkzjkm8NbGVewWW-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The PlayStation logo on a PS5 Pro]]></media:description>                                                            <media:text><![CDATA[The PlayStation logo on a PS5 Pro]]></media:text>
                                <media:title type="plain"><![CDATA[The PlayStation logo on a PS5 Pro]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/y5T6EzpDkzjkm8NbGVewWW-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p><a href="https://www.tomsguide.com/gaming/playstation/playstation-is-officially-killing-physical-discs-heres-when-they-disappear-and-what-that-means-for-you">PlayStation is officially killing physical discs</a>, and gamers aren’t happy. The company’s social media accounts can’t post anything without being slammed with negative comments, and even websites and influencers who are usually fans of PlayStation are taking them to task. Sony has yet to respond to any of this, which is likely making the situation worse. In short, this whole no-disc situation is a mess.</p><p>Sony says that digital now accounts for the vast majority of PlayStation game sales — hitting 85% in the most recent quarter — and it also nets a greater profit from digital purchases than physical, so it’s unlikely the company will reverse this controversial decision. However, if Sony wants to start (re)building trust with its fanbase, there are ways to make an all-digital future more palatable, namely by copying some of what has made Steam successful.</p><p>Steam has been a rousing success on PC for many years. Though Valve doesn’t offer physical games, it provides users with plenty of incentives to remain satisfied with their digital purchases and with the platform overall. I don’t expect Sony to completely copy Steam, but it can adopt similar policies if it ends disc production in January 2028.</p><p>Here are five practical, realistic adaptations Sony can take to make PSN more player-friendly.</p><h2 id="more-frequent-and-enticing-sales">More frequent (and enticing) sales</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="ykRy32GfJmDiDjqymNueJf" name="shutterstock_703264159.jpg" alt="Steam storefront on laptop screen." src="https://cdn.mos.cms.futurecdn.net/ykRy32GfJmDiDjqymNueJf.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>While PC gaming has higher upfront costs than consoles, it has become more affordable over time thanks to frequent Steam sales. Steam keeps its online store thriving with major seasonal sales and near-constant publisher promotions. Games also drop in price faster and more aggressively. This is why Steam users (like me) end up with libraries of hundreds of games. It’s hard to pass up a title when it’s just a few bucks!</p><p>The PlayStation Store has its own sales events, such as Days of Play, Black Friday, and other holiday sales, along with weekly deals. However, full-price windows for new games are longer, and we usually only see extreme deep discounts when a game is all but forgotten. I’ve taken advantage of PSN sales and snatched some good titles, but the sales and discounts still don’t match those of Steam.</p><p>In an all-digital world, Sony would have complete control over pricing. Using Steam-style volume-driven discounting on the back catalog (and even earlier on mid-tier titles) would encourage more impulse and library-building purchases, rather than people either waiting for huge discounts or skipping entirely.</p><h2 id="a-true-try-before-you-fully-commit-refund-policy">A true “try before you fully commit” refund policy</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:957px;"><p class="vanilla-image-block" style="padding-top:67.71%;"><img id="sEEJ2czKyykbmZiNdbohSe" name="Screenshot 2025-09-04 100754" alt="Hollow Knight: Silksong store page on Steam" src="https://cdn.mos.cms.futurecdn.net/sEEJ2czKyykbmZiNdbohSe.png" mos="" align="middle" fullscreen="" width="957" height="648" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Steam)</span></figcaption></figure><p>Right now, Steam arguably has the best refund policy in gaming. So long as you play a game for less than two hours total, you have 14 days to receive a full refund. This is a fantastic way to avoid purchasing a game that doesn’t click for you. While not technically a game demo, it pretty much serves the same “try before you buy” ethos.</p><p>PlayStation also has a 14-day refund policy, but it only applies if you haven’t downloaded a game. Once you start downloading, you no longer qualify for a refund unless the file is corrupt or you make a strong case to customer support that you purchased a game in error. This is frustrating enough now, but it will feel even worse if you can’t refund a digital title priced at $70–$80.</p><p>A playtime-based refund window, similar to Steam’s, would go a long way toward increasing purchase confidence without requiring Sony to change its curated store model. It’s actually wild that Sony doesn’t already have a similar policy, but the company should try it now if it plans to go all-in on an all-digital console.</p><h2 id="stronger-household-family-sharing">Stronger household/family sharing</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="kq426XFE2gzifzQdVzDYDU" name="steam-home-page.jpg" alt="The home page for Steam" src="https://cdn.mos.cms.futurecdn.net/kq426XFE2gzifzQdVzDYDU.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: Steam)</span></figcaption></figure><p>Sharing games is one of the main reasons gamers love physical media. While sharing digital content isn’t the same as handing a copy to someone else, Steam has a digital sharing policy that could work well for Sony.</p><p>On Steam, up to six family members can share a unified game library. Multiple members can play different games at the same time (you need multiple owned copies of the same game for concurrent play). </p><p>PlayStation has sharing features, but they’re more limited.</p><p>Console Sharing lets you log in to your account on a friend’s PS5 so they can play your games. Share Play lets you share your screen with a friend online and virtually hand them your controller. Though both of these methods work as advertised, a person cannot simply play games from another account on their own console in a straightforward way.</p><p>Expanding sharing options on PlayStation so a household can more easily share a digital library (with reasonable restrictions against abuse) wouldn’t be as seamless as lending someone a physical game, but it would at least offer gamers something comparable.</p><h2 id="better-discovery-tools">Better discovery tools</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="qvJ6bN35U3ezruK5peaaZk" name="20211213092912.jpg" alt="The Matrix Awakens product listing on the PlayStation Store on PS5" src="https://cdn.mos.cms.futurecdn.net/qvJ6bN35U3ezruK5peaaZk.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Sony)</span></figcaption></figure><p>Steam does a fantastic job with its wishlists, price-drop notifications, “players also like,” and other recommendations driven by player data. PlayStation has its own versions of these, but they could be updated to be more useful.</p><p>The store’s recent lowest-price-in-30-days indicator is a good step, but Sony can go further with smarter recommendations, clearer sale calendars, and stronger wishlist alerts. That last one really needs work — I feel like wishlist alerts are random at best, if I get them at all.</p><p>Improving discovery is an easy way to help players find and buy more games within Sony’s closed ecosystem. If you want people to buy digital games, you need to make it easier for them to find games they would actually like.</p><h2 id="clearer-long-term-library-guarantees-and-library-management">Clearer long-term library guarantees and library management</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="6jGE4qfxVjSEbbRvJ77xYf" name="Steam collection library" alt="Steam collection library" src="https://cdn.mos.cms.futurecdn.net/6jGE4qfxVjSEbbRvJ77xYf.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>One of the biggest reasons Sony is facing so much heat right now is the lack of clear guarantees about long-term access to the games players buy. Without physical discs, players worry more about access, storage, and account longevity. This is something that <a href="https://www.tomsguide.com/gaming/playstation/customers-need-assurances-their-games-wont-be-taken-from-them-after-purchase-stop-killing-games-on-playstations-decision-to-kill-physical-discs">Stop Killing Games founder Ross Scott</a> detailed when we interviewed him about Sony's decision to stop manufacturing discs.</p><p>Sony can learn from Steam’s emphasis on transparent licensing, robust cloud saves, and better tools for managing large digital libraries. Explicit, public commitments to offline play and long-term download availability would go a long way toward easing the anxiety surrounding digital-only ownership.</p><p>This is arguably the most important issue Sony has to address. People (rightly) want some form of ownership of the games they buy, especially when those games are digital. I’m not saying this will please everyone — some folks are certainly ride-or-die physical gamers — but clearer guarantees would ease much of the current anxiety.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eMVm7W"></div>                            </div>                            <script src="https://kwizly.com/embed/eMVm7W.js" async></script><h2 id="bottom-line-3">Bottom line</h2><p>I want to be clear that I am not dunking on Sony or PlayStation. The <a href="https://www.tomsguide.com/gaming/playstation/ps5-pro-review">PS5 Pro</a> is my primary gaming platform, after all. But as a PlayStation gamer since the early 2000s (thanks to the Gran Turismo 3 PS2 bundle!), I want to see the company do right by loyal customers like me.</p><p>PSN is not inherently broken. Sony already runs a polished, high-production store. However, things need to change when discs disappear. Adopting some of Steam’s more player-friendly policies would not only benefit gamers but also Sony, which would benefit from a more committed user base.</p><p>Sony will ultimately do what it believes is in its best interest. That said, prioritizing what customers want, genuinely listening, and addressing concerns would go a long way. Hopefully, Sony does right by its user base and makes an all-digital future on its consoles as acceptable as it is on Steam.</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/gaming/pc-gaming/my-wallet-gonna-cry-valve-gives-official-update-on-steam-machine-and-steam-frame-launch-but-still-wont-tell-us-the-price">Valve gives official update on Steam Machine and Steam Frame launch</a></li><li><a href="https://www.tomsguide.com/gaming/pc-gaming/steam-machine-reviews-are-here-even-valve-is-disappointed">Steam Machine reviews are here: 'Even Valve is disappointed'</a></li><li><a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review">The new Steam Controller is the only PC gamepad I'll ever need</a></li></ul><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=gaming&min_discount_ratio=0.95&widget_title=Top+Deals+Handpicked+by+Our+Editors&widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&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 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%;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      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 {      display: flex;      gap: 12px;      justify-content: center;      flex-wrap: wrap;    }    .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;    }        .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 {      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;    }        .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);      display: -webkit-box;      -webkit-line-clamp: 2;      -webkit-box-orient: vertical;      overflow: hidden;    }    .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;    }    .tg-df-container .tg-df-card-cta.tg-df-cta-savings-squad {      background-color: #3c8d0d;    }    .tg-df-card:hover .tg-df-card-cta.tg-df-cta-savings-squad,    .tg-df-card-cta.tg-df-cta-savings-squad:hover {      background-color: #2b6509;    }    /*       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: 0;      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: 0 16px;      }            .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-filters {        width: calc(100% + 32px);        margin: 0 -16px;        padding: 0 16px 4px 16px;        display: flex;        justify-content: flex-start;        gap: 8px;        flex-wrap: nowrap;        overflow-x: auto;        -webkit-overflow-scrolling: touch;        scrollbar-width: none;      }      .tg-df-filters::after {        content: "";        display: block;        flex: 0 0 8px;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }            .tg-df-sort-wrapper {        flex: 0 0 max(42%, 130px);        min-width: 0;      }      .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;      }            .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;        -webkit-line-clamp: 3;      }      /* 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;        -webkit-line-clamp: 3;        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;    }    .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: 16px;      text-align: center;      width: 100%;      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; }    @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: #f8fafc;      border-color: #cbd5e1;    }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right {      background-color: rgba(255, 255, 255, 0.4);      border: none;      box-shadow: none;      backdrop-filter: blur(4px);      -webkit-backdrop-filter: blur(4px);    }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right { right: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-right { right: 0; }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left:hover,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);      border: none;    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-carousel-roundels::after {      content: "";      flex: 0 0 32px;    }    .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;      transition: font-weight 0.2s;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-label {      font-weight: 700;    }    .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;      display: inline-flex;      align-items: center;      justify-content: center;      min-height: 36px;      box-sizing: border-box;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .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::after {      content: "";      flex: 0 0 32px;    }    .tg-df-grid-wrapper {      position: relative;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card {      flex: 0 0 auto;      width: 100px;      border-radius: 15px;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      border: 2px solid #1e293b;      background: white;      color: #1e293b;      display: flex;      flex-direction: column;      justify-content: center;      align-items: center;      font-weight: 600;      font-size: 14px;      cursor: pointer;      padding: 16px;      text-align: center;      transition: all 0.2s;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card:hover {      background: #1e293b;      color: white;    }    .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;      -webkit-line-clamp: 2;      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 {      -webkit-line-clamp: 3;    }    .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.45);        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: #5aaf0b; 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: #4a9109; 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; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \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-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\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>        \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-controls" id="tg-df-controls" style="display:flex;">      \x3Cdiv class="tg-df-top-bar">        \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>                \x3Cdiv class="tg-df-settings-wrapper">          \x3Cbutton type="button" class="tg-df-settings-btn" aria-label="Settings" id="tg-df-settings-toggle">            \x3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20">                \x3Cpath d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.73 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .43-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.49-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>            \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-settings-dropdown-backdrop" id="tg-df-settings-backdrop">\x3C/div>          \x3Cdiv class="tg-df-settings-dropdown" id="tg-df-settings-panel">            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Search Region\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-region-select">                \x3Coption value="auto">🌍 Auto-detect\x3C/option>                \x3Coption value="US">🇺🇸 United States (US)\x3C/option>                \x3Coption value="GB">🇬🇧 United Kingdom (UK)\x3C/option>                \x3Coption value="CA">🇨🇦 Canada (CA)\x3C/option>                \x3Coption value="AU">🇦🇺 Australia (AU)\x3C/option>                \x3Coption value="DE">🇩🇪 Germany (DE)\x3C/option>                \x3Coption value="FR">🇫🇷 France (FR)\x3C/option>                \x3Coption value="IT">🇮🇹 Italy (IT)\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Retailer\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-retailer-select">                \x3Coption value="">All Retailers\x3C/option>                \x3Coption value="Amazon">Amazon\x3C/option>                \x3Coption value="Walmart">Walmart\x3C/option>                \x3Coption value="Best Buy">Best Buy\x3C/option>                \x3Coption value="Target">Target\x3C/option>                \x3Coption value="John Lewis">John Lewis\x3C/option>                \x3Coption value="Currys">Currys\x3C/option>                \x3Coption value="Argos">Argos\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Offer Type\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-offer-type-select">                \x3Coption value="">All Offers\x3C/option>                \x3Coption value="amazon_prime">Amazon Prime\x3C/option>                \x3Coption value="recommended_promo">Recommended Promo\x3C/option>                \x3Coption value="amazon_lightning">Amazon Lightning Deal\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Result Count\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-rows-select">                \x3Coption value="3">3 Items\x3C/option>                \x3Coption value="4">4 Items\x3C/option>                \x3Coption value="6">6 Items\x3C/option>                \x3Coption value="12" selected>12 Items\x3C/option>                \x3Coption value="24">24 Items\x3C/option>                \x3Coption value="48">48 Items\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Deal Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Only show products with active offers or previous prices (was_price)\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-deal-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Editor Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Enable multi-select to copy deals to CMS\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-editor-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">View Mode\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-view-mode-select">                \x3Coption value="auto">Auto Collection\x3C/option>                \x3Coption value="carousel">Carousel\x3C/option>                \x3Coption value="savings_squad">Savings Squad\x3C/option>                \x3Coption value="grid">Grid (Columns)\x3C/option>                \x3Coption value="row">Row (List)\x3C/option>              \x3C/select>            \x3C/div>          \x3C/div>        \x3C/div>      \x3C/div>      \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">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/>          \x3C/svg>          \x3Cselect class="tg-df-sort-select" aria-label="Sort Deals">            \x3Coption value="date_desc">Newest First\x3C/option>            \x3Coption value="best_match">Sort by: Match\x3C/option>            \x3Coption value="price_asc">Price Low to High\x3C/option>            \x3Coption value="price_desc">Price High to Low\x3C/option>            \x3Coption value="discount_desc">Biggest Discount\x3C/option>          \x3C/select>        \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!-- 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();            if (['carousel', 'carousel-compact', 'auto', 'grid', 'row'].includes(this.getViewMode())) { this.loadCarouselSpreadsheet(); }        }        getViewMode() {          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();          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          if (mode === 'carousel' || mode === 'auto' || mode === 'grid' || mode === 'row') {             if (mode === 'carousel') this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container') && mode === 'carousel') {               this.root.classList.add('is-carousel');             } else if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             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 (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Everything';             if (this.discountFilter && !params.has('min_discount_ratio')) {               this.discountFilter.value = '5';             }          }          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 (params.has('bg_color')) {            const bg = params.get('bg_color');            if (bg === 'white') {              this.root.style.setProperty('background-color', '#ffffff', 'important');            } else if (bg === 'transparent') {              this.root.style.setProperty('background-color', 'transparent', 'important');            } else if (bg === 'light_blue') {              this.root.style.setProperty('background-color', '#E7F0FF', 'important');            }          } else {             this.root.style.removeProperty('background-color');          }                    if (params.has('view_mode')) {            if (this.viewModeSelect) {              this.viewModeSelect.value = params.get('view_mode');            } else {              this.viewModeOverride = 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') || 'discount_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }                    // 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) {            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 !== 'discount_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 roundels = this.root.querySelectorAll('.tg-df-carousel-cat.original-hardcoded');          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');              }            });          }          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              if (this.getViewMode() === 'savings_squad' && this.autocompleteDropdown && this.airedaleTags && query.length > 0) {                 const matches = this.airedaleTags.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase()).slice(0, 5);                 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');                 }              } else if (this.autocompleteDropdown) {                 this.autocompleteDropdown.classList.remove('active');              }              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  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;                this.activeDealTag = null;                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   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;                   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 });              this.activeDealTag = null;              this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.fetchDeals(query);              }            });          }          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;               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 = this.viewModeSelect.value === 'savings_squad' ? 'date_desc' : 'discount_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 loadCarouselSpreadsheet() {          try {              const parseCSVRow = (str) => {                  let result = [], cur = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (inQuotes) {                          if (char === '"') {                              if (str[i + 1] === '"') { cur += '"'; i++; }                              else { inQuotes = false; }                          } else { cur += char; }                      } else {                          if (char === '"') { inQuotes = true; }                          else if (char === ',') { result.push(cur); cur = ''; }                          else { cur += char; }                      }                  }                  result.push(cur); return result;              };              const parseCSV = (str) => {                  const rows = []; let curRow = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (char === '"') inQuotes = !inQuotes;                      if ((char === '\n' || char === '\r') && !inQuotes) {                          if (char === '\r' && str[i+1] === '\n') i++;                          if (curRow) rows.push(parseCSVRow(curRow));                          curRow = '';                      } else { curRow += char; }                  }                  if (curRow) rows.push(parseCSVRow(curRow));                  return rows;              };              const preloadedCSV = decodeURIComponent(escape(atob("LCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNQ0KUm91bmRlbCB0ZXh0LEFsbCxUVnMsRm9vdHdlYXIsQXBwYXJlbCxNYXR0cmVzZXMsQXBwbGlhbmNlcyxXZWFyYWJsZSB0ZWNoLEhlYWRwaG9uZXMsU21hcnQgSG9tZSxTcGVha2VycyxMYXB0b3BzLFRhYmxldHMsQ29tcHV0aW5nLFBob25lcyxHYW1pbmcsTGVnbw0KUm91bmRlbCBpbWFnZSxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2FpLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3R2cy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvN2IzYTIyNGIwNzk2M2M2MjdiNmI5MDliZDc4MzM4MzZlMDJmZjgxOS5qcGcud2VicCxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy84NGRhYzVkNDhlZDJkNDQ4NTU5ZWJhNjdhY2U4MzE0Y2M2N2NjZDk0LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvbWF0dHJlc3Nlcy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvNzY4ZTk3Y2ViMDcxODAxZmFlMjA5MTBkMDgyMGIxNmY3NDdhZjkzOS5qcGcud2VicCxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3dlbGxuZXNzLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2hlYWRwaG9uZXMuanBnLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzg5NTM1YmVlYmUyMGRiYmQ0YTM0NmQ2ZDZiZGZlOTFkOGE4ODRhMjEuanBnLndlYnAsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9hdWRpby5qcGcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9sYXB0b3BzLmpwZyxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy8yMzk3NTY0ZWQ3YTVmZjk0N2U5YjZiMzBlNTRmNDc0OTRiODQxZjg5LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvY29tcHV0aW5nLmpwZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3Bob25lcy5wbmcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9nYW1pbmcucG5nLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzRmNmM2MjFjYWMwYmMxYTg1ZDU5M2UzNTk0YmE1YjM0OWVmZmQyOTIuanBnLndlYnANClNlYXJjaCBRdWVyeSxFdmVyeXRoaW5nLFRlbGV2aXNpb25zLCJTbmVha2VycywgcnVubmluZyBzaG9lcywgc2FuZGFscyIsQ2xvdGhpbmcsTWF0dHJlc3NlcyxIb21lIEFwcGxpYW5jZXMsV2VhcmFibGVzICYgRml0bmVzcyBUZWNoLEhlYWRwaG9uZXMsSG9tZSBUZWNoLFNwZWFrZXJzLExhcHRvcHMsVGFibGV0cyxDb21wdXRpbmcsUGhvbmVzLEdhbWluZyxDb25zdHJ1Y3Rpb24gVG95cw0KRGlzY291bnQgQW1vdW50LG1pbiA1JSxtaW4gMTAlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUNClByaWNlIFJhbmdlLCwsLCxtaW4gJDQwMCwsLCxtaW4gJDI1LCxtaW4gJDMwMCwsLG1pbiAkMTAwLCwNCkJyYW5kIFNlbGVjdGlvbiwsLCwsLCwsLCwsLCwsLCwNCkZpbHRlciBidXR0b25zLCwsLCwsLCwsLCwsLCwsLA0KMSxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMNCjIsQW1hem9uIGRlYWxzLFVuZGVyICQxMDAwLDUwJSBvZmYsQWRpZGFzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsNTAlIG9mZixBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscw0KMyxPdmVyICQ0MDAsVW5kZXIgJDUwMCxIb2thLE5pa2UsU2FhdHZhLE5pbmphLDQwJSBvZmYsSkxhYiwsSkJMLERlbGwsLEFzdXMsQXBwbGUsQ29uc29sZXMsU3RhciBXYXJzDQo0LFVuZGVyICQxMDAwLDUwJSBvZmYsU2tlY2hlcnMsVW5kZXIgQXJtb3VyLEhlbGl4LFNoYXJrLEdhcm1pbixBbmtlciBTb3VuZGNvcmUsUmluZyxTb25vcyxBcHBsZSxBcHBsZSxUUC1saW5rLFNhbXN1bmcsQWNjZXNzb3JpZXMsVW5kZXIgJDI1DQo1LFVuZGVyICQ1MDAsTEcsQXNpY3MsQ29sdW1iaWEsRHJlYW1DbG91ZCxLZXVyaWcsQXBwbGUsU29ueSxHb3ZlZSxUcmliaXQsTGVub3ZvLFNhbXN1bmcsRWVybyxHb29nbGUsR2FtZXMsVW5kZXIgJDUwDQo2LDUwJSBvZmYsU2Ftc3VuZyxOaWtlLFBhdGFnb25pYSxOZWN0YXIsRGUnTG9uZ2hpLEFtYXpmaXQsQXBwbGUsS2FzYSBzbWFydCxTb255LEFsaWVud2FyZSxUQ0wsTmV0Z2VhcixNb3Rvcm9sYSxOaW50ZW5kbyxCb3RhbmljYWxzDQo3LEFtYXpvbixIaXNlbnNlLE5ldyBCYWxhbmNlLEFyYyd0ZXJ5eCxUZW1wdXItcGVkaWMsRHlzb24sRml0Yml0LEJlYXRzLFBoaWxpcHMgSHVlLEFua2VyLEFjZXIsT25lUGx1cyxEZWxsLE9uZVBsdXMsU29ueSxEaXNuZXkNCjgsQXBwbGUsVENMLEFkaWRhcyxDYXJoYXJ0dCxCZWFyLEJpc3NlbGwsU2Ftc3VuZyxFYXJmdW4sQmxpbmssQmVhdHMsTVNJLE1pY3Jvc29mdCxBY2VyLE5vdGhpbmcsWGJveCxNYXJ2ZWwNCjksLFNvbnksU2F1Y29ueSxUaGUgTm9ydGggRmFjZSxTaWVuYSxOdXRyaWJ1bGxldCxPdXJhLFNhbXN1bmcsR29vZ2xlIE5lc3QgLE1hcnNoYWxsLFNhbXN1bmcsTGVub3ZvLExlbm92bywsLFBva2Vtb24NCjEwLCxSb2t1LEJpcmtlbnN0b2NrLENSWiBZb2dhLFdpbmtCZWRzLEJsYWNrIGFuZCBEZWNrZXIsUmluZ2Nvbm4sQ01GLEV1ZnksU2Ftc3VuZyxNaWNyb3NvZnQsUmVNYXJrYWJsZSxBbGllbndhcmUsLCwNCjExLCwsQnJvb2tzLFRoZSBHeW0gUGVvcGxlLEJyb29rbHluIGJlZGRpbmcsTmVzcHJlc3NvLCwxTW9yZSxBcmxvLCxSYXplciwsQ29yc2FpciwsLA0KMTIsLCxDcm9jcywsRWlnaHQgU2xlZXAsQ3Vpc2luYXJ0LCxKQkwsLCwsLEhQLCwsDQpOb3RlcywsLCwsLCwsLCwsLCwsLCwNCiwsIlByaW9yaXRpc2UgYmlnZ2VzdCAlLyQgZGlzY291bnQsIFR2cyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiB0aGUgbW9zdCBwb3B1bGFyIGV2ZW4gaWYgdGhleSBhcmUgc3RpbGwgZXhwZW5zaXZlIiwiTm8gcGF0dGVybiB0byBwcmljaW5nL2Rpc2NvdW50LCByZWFkZXJzIG1haW5seSBzaG9wIGJ5IGJyYW5kL3JlY29nbmlzYWJsZSBzaG9lcyIsIk5vIHBhdHRlcm4gdG8gcHJpY2luZy9kaXNjb3VudCwgcmVhZGVycyBtYWlubHkgc2hvcCBieSBicmFuZCIsIkEgbGFiZWwgd2lsbCBkZWZpbml0ZWx5IGhlbHAgaGVyZSBlLmcuIGJlc3QgZm9yIHNpZGUgc2xlZXBlciwgYmVzdCBtZW1vcnkgZm9hbSIsIkFwcGxpYW5jZXMgaXMgYSBiaWcgY2F0ZWdvcnksIGlzIGl0IHBvc3NpYmxlIHRvIHNwbGl0IGludG8ga2l0Y2hlbiBhcHBsaWFuY2VzLCBmbG9vcmNhcmUsIGFpciBoZWFsdGgvY29vbGluZz8gT3Igc2ltaWxhciIsIkZvY3VzIG9uIHZhbHVlIGZvciBtb25leSwgR2FybWlucyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiBwb3B1bGFyIGV2ZW4gdGhvdWdoIHRoZXkgYXJlIHN0aWxsICQ1MDAiLCwsLCxJbmNsdWRlIEtpbmRsZXMsSSB3b3VsZCBpbmNsdWRlIHdpZmkgcm91dGVycyBoZXJlIGluc3RlYWQgb2Ygc21hcnQgaG9tZSxDYW4gd2Ugc3VyZmFjZSBwaG9uZSBwcm92aWRlciBkZWFscz8gVC1tb2JpbGUgYW5kIHZlcml6b24gd291bGQgbWFrZSBhIGxvdCBtb3JlIG1vbmV5IHRoYW4gQW1hem9uLCwNCiwsaGF2aW5nIGEgJ2Jlc3QgZm9yJyBsYWJlbCB3b3VsZCBiZSBoZWxwZnVsIGUuZy4gYmVzdCBmb3IgYnJpZ2h0IHJvb20sQ2FuIHdlIHN0b3Aga2lkcyBzaG9lcyBmcm9tIHB1bGxpbmcgdGhyb3VnaD8sIldpbGwgdGhpcyBpbmNsdWRlIGFjY2Vzc29yaWVzIGUuZy4gY2FwcywgYmFncywgaWYgc28gbWFrZSBzdXJlIHRoZXNlIGFyZSBtaXhlZCB0aHJvdWdob3V0IGNsb3RoaW5nIGRlYWxzIixXaWxsIHRoaXMgaW5jbHVkZSB0b3BwZXJzIGFuZCBwaWxsb3dzPyBTZWVpbmcgbW9yZSBtb21lbnR1bSB3aXRoIHRoaXMgY2F0ZWdvcnkgcmVjZW50bHkgc28gYSBiZWRkaW5nIHRhYiBtaWdodCB3b3JrLCwiTmVlZCB0byBtYWtlIHN1cmUgYmFuZHMsIHNjcmVlbiBwcm90ZWN0b3JzIGV0Yy4gZG9uJ3QgcHVsbCBpbnRvIGhlcmUiLCwsLCwsLCwsDQosLCJQcmlvcml0aXNlIDY1JycgYW5kIDU1JyBpbmNoIFRWcywgdGhlbiBiaWdnZXIgc2NyZWVucyBiZWZvcmUgdGhlIHNtYWxsZXIgc2l6ZXMiLCwsUXVlZW4gaXMgdGhlIG1vc3QgcG9wdWxhciBzaXplIGluIHRoZSBVUyAtIHByaW9yaXRpc2UgZGVhbHMgZm9yIHRoaXMgc2l6ZSwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpDYXRlZ29yaWVzIHRvIGNvbnNpZGVyLCxQcm9kdWN0cyBpbmNsdWRlZCwsLCwsLCwsLCwsLCwsDQpVbmRlciAkNTA/LCxBaXIgdGFncywsLCwsLCwsLCwsLCwsDQosLFBvcnRhYmxlIGNoYXJnZXJzL3dpcmVsZXNzIGNoYXJnZXJzLCwsLCwsLCwsLCwsLCwNCiwsIldhdGVyIGJvdHRsZXMgKHN0YW5sZXlzLCBPd2FsYSwgSHlkcm8gZmxhc2ssIFlldGkpIiwsLCwsLCwsLCwsLCwsDQosLEhhbmQgaGVsZCBmYW5zLCwsLCwsLCwsLCwsLCwNCiwsLCwsLCwsLCwsLCwsLCwNCmhvbWUgb2ZmaWNlLCxvZmZpY2UgY2hhaXJzLCwsLCwsLCwsLCwsLCwNCiwsc3RhbmRpbmcgZGVza3MsLCwsLCwsLCwsLCwsLA0KLCxtb25pdG9ycywsLCwsLCwsLCwsLCwsDQosLEtleWJvYXJkcywsLCwsLCwsLCwsLCwsDQosLGRvY2tpbmcgc3RhdGlvbiwsLCwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpHYW1pbmcsLENvbnNvbGVzLCwsLCwsLCwsLCwsLCwNCiwsQWNjZXNzb3JpZXMsLCwsLCwsLCwsLCwsLA0KLCxHYW1lcywsLCwsLCwsLCwsLCwsDQosLENvdWxkIGluY2x1ZGUgTGVnbz8sLCwsLCwsLCwsLCwsLA==")));              const text = preloadedCSV;              const parsed = parseCSV(text);                            const rowsByName = {};              let filterStart = -1;              parsed.forEach((rc, i) => {                 if (rc && rc.length > 0 && rc[0]) rowsByName[rc[0]] = rc;                 if (rc && rc.length > 0 && rc[0] === 'Filter buttons') filterStart = i;              });                            const cols = [];              if(rowsByName['Roundel text']) {                const headerRow = rowsByName['Roundel text'];                for(let col = 1; col < headerRow.length; col++) {                   let label = headerRow[col];                   if (!label) continue;                                      let q = rowsByName['Search Query'] && rowsByName['Search Query'][col] ? rowsByName['Search Query'][col] : '';                   let img = rowsByName['Roundel image'] && rowsByName['Roundel image'][col] ? rowsByName['Roundel image'][col] : '';                   let ds = rowsByName['Discount Amount'] && rowsByName['Discount Amount'][col] ? rowsByName['Discount Amount'][col] : '';                   let pr = rowsByName['Price Range'] && rowsByName['Price Range'][col] ? rowsByName['Price Range'][col] : '';                   let rt = rowsByName['Retailer'] && rowsByName['Retailer'][col] ? rowsByName['Retailer'][col] : '';                   let ot = rowsByName['Offer Type'] && rowsByName['Offer Type'][col] ? rowsByName['Offer Type'][col] : '';                                      let filters = [];                   if(filterStart > 0) {                     for(let r = filterStart + 1; r < parsed.length; r++) {                         if(!parsed[r] || parsed[r][0] === 'Notes' || parsed[r][0] === 'Categories to consider') break;                         let f = parsed[r][col];                         if(f) filters.push(f);                     }                   }                   cols.push({ label, img, q, ds, pr, rt, ot, filters });                }              }              this.carouselData = cols;              if (this.carouselData && this.carouselData.length > 0) {                 const isMatched = this.carouselData.some(c => c.q === this.currentQuery || c.label === this.currentQuery);                 if (!isMatched) {                    const first = this.carouselData[0];                    this.currentQuery = first.q || first.label;                    if (this.priceFilter) this.priceFilter.value = 'all';                    if (this.customPriceMin) this.customPriceMin.value = '';                    if (this.customPriceMax) this.customPriceMax.value = '';                    let dPr = first.pr || 'all';                    if (typeof dPr === 'string' && dPr !== 'all') {                       let prLower = dPr.toLowerCase();                       if (prLower.includes('min') || prLower.includes('over')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else if (prLower.includes('max') || prLower.includes('under')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       }                    }                    let dAm = '0';                    if(first.ds && typeof first.ds === 'string') {                       let m = first.ds.match(/(\d+)/);                       if(m) dAm = m[1];                    }                    if (this.discountFilter) this.discountFilter.value = dAm;                    if (this.offerTypeSelect) this.offerTypeSelect.value = first.ot || '';                    if (this.retailerSelect) this.retailerSelect.value = first.rt || '';                    this.selectedBrands = [];                    if (this.brandDropdown) {                        const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                        chks.forEach(chk => chk.checked = false);                    }                    if (this.searchInput) this.searchInput.value = this.currentQuery;                 }              }              this.renderCarouselUI();          } catch(e){ console.warn(e); }        }                renderCarouselUI() {           const roundelWrapper = this.root.querySelector('.tg-df-carousel-roundels');           if(!roundelWrapper || !this.carouselData) return;                      let html = '';           this.carouselData.forEach(r => {              const q = r.q || r.label;              const isActive = (this.currentQuery === q || this.currentQuery === r.label) ? 'active' : '';              const imgHtml = r.img ? `\x3Cimg src="${r.img}" alt="${r.label}" />` : `\x3Csvg width="32" height="32" fill="#1F69FF" viewBox="0 0 24 24">\x3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>\x3C/svg>`;              html += `                \x3Cdiv class="tg-df-roundel tg-df-carousel-cat ${isActive}" data-label="${this.escapeHTML(r.label)}">                  \x3Cdiv class="tg-df-roundel-img-box">${imgHtml}\x3C/div>                  \x3Cspan class="tg-df-roundel-label">${this.escapeHTML(r.label)}\x3C/span>                \x3C/div>              `;           });           roundelWrapper.innerHTML = html;                      // Rebind clicks           const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');           roundels.forEach(rNode => {             rNode.addEventListener('click', () => {                const r = this.carouselData.find(c => c.label === rNode.getAttribute('data-label'));                 if(!r) return;                                  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: r.label,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = r.q || r.label;                const labelTitle = this.root.querySelector('#tg-df-carousel-title-label');                if (labelTitle) labelTitle.textContent = 'Best ' + this.currentQuery;                if (this.priceFilter) this.priceFilter.value = 'all';                if (this.customPriceMin) this.customPriceMin.value = '';                if (this.customPriceMax) this.customPriceMax.value = '';                let dPr = r.pr || 'all';                if (typeof dPr === 'string' && dPr !== 'all') {                   let prLower = dPr.toLowerCase();                   if (prLower.includes('min') || prLower.includes('over')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMin) this.customPriceMin.value = m[1];                   } else if (prLower.includes('max') || prLower.includes('under')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMax) this.customPriceMax.value = m[1];                   }                }                                let discountAmount = '0';                if(r.ds && typeof r.ds === 'string') {                   let m = r.ds.match(/(\d+)/);                   if(m) discountAmount = m[1];                }                if (this.discountFilter) this.discountFilter.value = discountAmount;                if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                                // Clear brands                    this.selectedBrands = [];                    if (this.brandDropdown) {                    const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                    chks.forEach(chk => chk.checked = false);                }                                if (this.searchInput) this.searchInput.value = this.currentQuery;                                roundels.forEach(ro => ro.classList.remove('active'));                if (rNode) rNode.classList.add('active');                                this.renderCarouselFilters(r);                this.fetchDeals(this.currentQuery);             });           });                      // Auto-highlight active           const activeR = this.carouselData.find(c => c.q === this.currentQuery || c.label === this.currentQuery);           if(activeR) this.renderCarouselFilters(activeR);        }                renderCarouselFilters(r) {           const filtersWrap = this.root.querySelector('.tg-df-carousel-filters-wrap');           if(!filtersWrap) return;                      let html = `\x3Cbutton class="tg-df-carousel-filter-btn" data-type="all">All\x3C/button>`;                      r.filters.forEach(f => {              let fL = f.toLowerCase();              let icon = '';              let logic = `data-type="custom" data-v="${this.escapeHTML(f)}"`;              if (fL === 'amazon deals' || fL === 'prime deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\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>`;              } else if (fL === 'lightning deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\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>`;              } else {                 if (fL.includes('lightning')) {                    icon = `\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-zap">\x3Cpolygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2">\x3C/polygon>\x3C/svg>`;                 } else if (fL.includes('% off')) {                    icon = `\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>`;                 } else if (fL.includes('under') || fL.includes('min ')) {                    icon = `\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>`;                 }                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>${icon} ${this.escapeHTML(f)}\x3C/button>`;              }           });                      filtersWrap.innerHTML = html;                      const btns = filtersWrap.querySelectorAll('button');           btns.forEach(b => {             b.addEventListener('click', () => {                const type = b.getAttribute('data-type');                if (type === 'custom') {                   const v = b.getAttribute('data-v');                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-custom-${(v||'').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, name: 'Custom Filter', label: v });                }                if (type === 'all') {                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: 'filter-clear-all', name: 'Clear all', label: 'Clear all filters' });                   // reset everything                   btns.forEach(btn => btn.classList.remove('active'));                   b.classList.add('active');                                      // Reset prices                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   if (this.brandDropdown) {                     const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                     chks.forEach(chk => chk.checked = false);                   }                } else {                   const v = b.getAttribute('data-v');                   const fL = v.toLowerCase();                                      let mapRet = ['amazon', 'walmart', 'best buy', 'target', 'john lewis', 'currys', 'argos'];                   const getCategory = (s) => {                      if (s === 'lightning deals' || s === 'amazon deals' || s === 'prime deals') return 'offer';                      if (s.includes('% off')) return 'discount';                      if (s.includes('under') || s.includes('over') || s.includes('min') || s.includes('max')) return 'price';                      if (mapRet.includes(s)) return 'retailer';                      return 'brand';                   };                   const cat = getCategory(fL);                   const wasActive = b.classList.contains('active');                   if (cat !== 'brand') {                      btns.forEach(btn => {                          if (btn === b) return;                          if (btn.getAttribute('data-type') === 'all') return;                          const bV = btn.getAttribute('data-v');                          if (!bV) return;                          if (getCategory(bV.toLowerCase()) === cat) btn.classList.remove('active');                      });                   }                   if (wasActive) b.classList.remove('active');                   else b.classList.add('active');                   let anyActive = Array.from(btns).some(btn => btn !== btns[0] && btn.classList.contains('active'));                   if (!anyActive) {                       btns[0].click();                       return;                   } else {                       btns[0].classList.remove('active');                   }                                      if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   btns.forEach(btn => {                       if (!btn.classList.contains('active') || btn.getAttribute('data-type') === 'all') return;                       const vv = btn.getAttribute('data-v');                       const vl = vv.toLowerCase();                                              if (vl === 'lightning deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_lightning';                       } else if (vl === 'amazon deals' || vl === 'prime deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_prime';                       } else if (vl.includes('% off')) {                          let m = vl.match(/(\d+)%/);                          if (m && this.discountFilter) this.discountFilter.value = m[1];                       } else if (vl.includes('under') || vl.includes('max')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       } else if (vl.includes('min') || vl.includes('over')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else {                          let foundR = mapRet.find(x => x === vl);                          if (foundR) {                             let realR = ['Amazon', 'Walmart', 'Best Buy', 'Target', 'John Lewis', 'Currys', 'Argos'].find(x => x.toLowerCase() === vl);                             if (this.retailerSelect) this.retailerSelect.value = realR;                          } else {                             this.selectedBrands.push(vv);                          }                       }                   });                                      if (this.brandDropdown) {                       const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                       chks.forEach(c => c.checked = this.selectedBrands.includes(c.value));                   }                                      if (r.pr && typeof r.pr === 'string') {                       let prL = r.pr.toLowerCase();                       if (prL.includes('under $')) {                           let m = prL.match(/under \$(\d+)/i);                           if (m && this.customPriceMax && !this.customPriceMax.value) this.customPriceMax.value = m[1];                       }                   }                }                                this.fetchDeals(this.currentQuery);             });           });                      // default to highlighting first           btns[0].classList.add('active');        }async fetchDeals(query, append = false) {          if (!append) {             this.showLoading();             this.deals = [];             this.displayLimit = this.getRowsLimit();          } else {             this.displayLimit += this.getRowsLimit();          }                    try {            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad(append);            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query, append);               } else {                 await this.fetchHawkDeals(query, append);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query, append);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&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=tomsguide&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) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const url = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&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 dynamicBrandsCounts = {};                    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();                   dynamicBrandsCounts[data.brand] = (dynamicBrandsCounts[data.brand] || 0) + 1;                }                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;                   }                }                                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 || ''                });             });          });                    const airedaleBrandsList = Object.keys(dynamicBrandsCounts).map(b => ({              formatted_value: b,              count: dynamicBrandsCounts[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, append = false) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (append && this.deals.length > 0) {            url.searchParams.append('offset', this.deals.length.toString());          }                    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 : (this.getViewMode() === 'savings_squad' ? 'date_desc' : 'discount_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}                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin-top:8px;">${_div}                ${_div}              ${_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)} (${this.airedaleTagCounts[tag] || 0})${_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 = isSavingsSquadMode ? 'View Deal' : 'Check Price';              if (isSavingsSquadMode) {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                  ${_div}                `;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \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 = `                \x3Cdiv class="tg-df-card-merchant-wrapper">                  \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                ${_div}                \x3Cdiv class="tg-df-card-price-group">                  ${isSavingsSquadMode ? '' : `                  \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">\x3Cp>${this.escapeHTML(deal.description)}${_p}${_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>${deal.isCheckPrice ? 'Check Price' : '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}                ${_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 ? `\x3Cp style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 12px; line-height: 1.4;">${this.escapeHTML(deal.description)}${_p}` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${priceGroupHtml}                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta ${isSavingsSquadMode ? 'tg-df-cta-savings-squad' : ''}" style="text-decoration: none;">${ctaText}${_a}                  ${_div}                ${_div}              ${_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 || ((this.getViewMode() === 'carousel' || this.getViewMode() === 'auto') && displayDeals.length > 0 && displayDeals.length % ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12) === 0)) {            if (this.getViewMode() === 'carousel') {               dealsHtml += `                 \x3Cbutton type="button" class="tg-df-load-more-card tg-df-load-more">                   \x3Csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-bottom: 8px;">\x3Cpath d="M5 12h14">\x3C/path>\x3Cpath d="m12 5 7 7-7 7">\x3C/path>\x3C/svg>                   Load More                 ${_button}               `;            } else {               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; display: flex; align-items: center;">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); }                    let gridWrapper = this.grid.parentElement;          if (gridWrapper && gridWrapper.classList.contains('tg-df-grid-wrapper')) {             let rightChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-right');             let leftChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-left');             if (this.getViewMode() === 'carousel') {                 // The observer set up in setupScrollListeners handles visibility.                 if (rightChevron) rightChevron.style.display = 'flex';                 if (leftChevron) leftChevron.style.display = 'none'; // reset correctly             } else {                 if (rightChevron) rightChevron.style.display = 'none';                 if (leftChevron) leftChevron.style.display = 'none';             }          }                    const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', async () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              if (displayDeals.length <= this.displayLimit) {                 loadMoreBtn.innerHTML = `                  <svg class="tg-df-spinner" style="width: 16px; height: 16px; display: inline-block; vertical-align: middle; margin-right: 8px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/></svg>                  Loading...                 `;                 loadMoreBtn.disabled = true;                 await this.fetchDeals(this.currentQuery, true);              } else {                 this.displayLimit += this.getRowsLimit();                 this.render();              }            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();                        // 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');            }            setTimeout(() => {               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);          } 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[ The Razer Huntsman V3 just became my go-to PC gaming keyboard — here’s why ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/keyboards/the-razer-huntsman-v3-just-became-my-go-to-pc-gaming-keyboard-heres-why</link>
                                                                            <description>
                            <![CDATA[ The Razer Huntsman V3 Tenkeyless 8KHz packs a ton of pro-grade features at a relatively affordable price. Here's what makes it worth considering. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">KGkcnrUvYLHwpfHSiUEeV4</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/iF3DdXTMBxzpFoVncGnzSK-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 17 Jul 2026 08:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Keyboards]]></category>
                                                    <category><![CDATA[Gaming Peripherals]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/iF3DdXTMBxzpFoVncGnzSK-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Razer Huntsman V3 Tenkeyless 8KHz]]></media:description>                                                            <media:text><![CDATA[Razer Huntsman V3 Tenkeyless 8KHz]]></media:text>
                                <media:title type="plain"><![CDATA[Razer Huntsman V3 Tenkeyless 8KHz]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/iF3DdXTMBxzpFoVncGnzSK-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I haven’t used a Razer gaming keyboard for a while, so testing the new Razer Huntsman V3 TKL 8KHz feels like reuniting with an old friend. Since the company uses proprietary switches, its keyboards feel different from competitors that use third-party parts. This remains true for the Huntsman V3.</p><p>This more affordable variant of last year’s Huntsman V3 Pro TKL 8KHz packs several competitive gaming-focused features, such as super-fast 8KHz polling and adjustable actuation points. While the keyboard is relatively thin, its aluminum build makes it sturdy and safe to travel with. And while it’s a gaming keyboard at its core, it’s also great for typing.</p><p>If you’re a competitive gamer who needs a keyboard that can keep up with you and won’t break the bank, the Razer Huntsman V3 Tenkeyless 8KHz is one of the <a href="https://www.tomsguide.com/best-picks/best-gaming-keyboard">best gaming keyboards</a> that's worth checking out. Here’s why.</p><div class="product"><a data-dimension112="56b2384a-814b-11f1-b86a-11d34ca164b1" data-action="Deal Block" data-label="The Razer Huntsman V3 Tenkeyless 8KHz is a pro-grade gaming keyboard, featuring precise optical switches, a super-high 8K polling rate, adjustable actuation points, and full RGB lighting. At $169, it's the most affordable Huntsman V3 model currently available, and it's worth the money if you're a hardcore competitive PC gamer." data-dimension48="The Razer Huntsman V3 Tenkeyless 8KHz is a pro-grade gaming keyboard, featuring precise optical switches, a super-high 8K polling rate, adjustable actuation points, and full RGB lighting. At $169, it's the most affordable Huntsman V3 model currently available, and it's worth the money if you're a hardcore competitive PC gamer." data-dimension25="$169" href="https://www.amazon.com/Razer-Huntsman-Esports-Gaming-Keyboard/dp/B0GWNHWWN8" 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="GQZWYf9pyTNyTxNzdKcnQh" name="Razer Huntsman V3 Tenkeyless 8KHz" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/GQZWYf9pyTNyTxNzdKcnQh.jpg" mos="" align="middle" fullscreen="" width="1500" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Razer Huntsman V3 Tenkeyless 8KHz is a pro-grade gaming keyboard, featuring precise optical switches, a super-high 8K polling rate, adjustable actuation points, and full RGB lighting. At $169, it's the most affordable Huntsman V3 model currently available, and it's worth the money if you're a hardcore competitive PC gamer.<a class="view-deal button" href="https://www.amazon.com/Razer-Huntsman-Esports-Gaming-Keyboard/dp/B0GWNHWWN8" target="_blank" rel="nofollow" data-dimension112="56b2384a-814b-11f1-b86a-11d34ca164b1" data-action="Deal Block" data-label="The Razer Huntsman V3 Tenkeyless 8KHz is a pro-grade gaming keyboard, featuring precise optical switches, a super-high 8K polling rate, adjustable actuation points, and full RGB lighting. At $169, it's the most affordable Huntsman V3 model currently available, and it's worth the money if you're a hardcore competitive PC gamer." data-dimension48="The Razer Huntsman V3 Tenkeyless 8KHz is a pro-grade gaming keyboard, featuring precise optical switches, a super-high 8K polling rate, adjustable actuation points, and full RGB lighting. At $169, it's the most affordable Huntsman V3 model currently available, and it's worth the money if you're a hardcore competitive PC gamer." data-dimension25="$169">View Deal</a></p></div><h2 id="what-s-this-razer-huntsman-v3-all-about">What's this Razer Huntsman V3 all about?</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="qfm62vGH79v4W9e5Ythv4U" name="Razer Huntsman V3 TKL 8K--1" alt="Razer Huntsman V3 Tenkeyless 8KHz" src="https://cdn.mos.cms.futurecdn.net/qfm62vGH79v4W9e5Ythv4U.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 Razer Huntsman V3 TKL 8KHz is a competitive gaming keyboard built for fast-paced first-person shooters and other genres that demand quick reflexes. It utilizes the company’s proprietary analog optical switches, 8K “HyperPolling,” adjustable actuation, and a slew of RGB customization options.</p><p><a href="https://www.tomsguide.com/computing/peripherals/i-finally-tried-magnetic-key-switches-but-i-never-thought-id-find-them-in-a-split-keyboard-thats-also-wireless">Magnetic switches</a> have been all the rage in recent years, but Razer has remained true to its optical switches. Both switch types provide faster response times than traditional mechanical switches, which is why competitive gamers tend to gravitate toward them. I won’t debate whether optical or magnetic switches are better for gaming, but I will say Razer’s optical switches are insanely responsive.</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="pCtyQhZn2pFFSxbjm22wGd" name="Razer Huntsman V3 TKL 8K--3" alt="Razer Huntsman V3 Tenkeyless 8KHz" src="https://cdn.mos.cms.futurecdn.net/pCtyQhZn2pFFSxbjm22wGd.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>Like with magnetic switches, you can set multiple actuation points on a single key—two actuation points in this case. For example, you can have an actuation point of 2.0 mm on the W key to walk and 4.0 to run. Here, you can set actuation points between 0.1 mm and 4.0, which is standard for both magnetic and optical keyboards.</p><p>Then there’s the 8K polling (the speed at which the keyboard sends signals to your computer), which Razer says is faster than other keyboards claiming such a high polling rate. According to the company, most keyboards with 8K polling have a 1.6ms response time, but the Huntsman V3 has a faster 0.48ms response time.</p><p>So, how does all of that translate to real-world use? Though I’m nowhere near a competitive gamer, even I could feel the overall smoothness and fast response when playing a first-person shooter like <a href="https://www.tomsguide.com/gaming/doom-the-dark-ages-is-a-heavy-metal-album-cover-come-to-life-and-i-cant-wait-to-play-ithttps://www.tomsguide.com/gaming/doom-the-dark-ages-review">Doom: The Dark Ages</a>. I especially like setting a faster actuation point for shooting since I could lightly brush the key instead of pressing it down all the way. And in case you’re wondering, you can set the actuation points right on the keyboard, though I still preferred doing so via the Razer Synapse app on PC.</p><h2 id="the-experience">The experience</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="HijJ7EnLSEG77tMhHZry8n" name="Razer Huntsman V3 TKL 8K--5" alt="Razer Huntsman V3 Tenkeyless 8KHz" src="https://cdn.mos.cms.futurecdn.net/HijJ7EnLSEG77tMhHZry8n.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>While I’m not the target customer for a competitive gaming keyboard, I enjoy using them because of their fast response time and smooth keystrokes—which the Razer Huntsman V3 has in spades. While the blazing performance and high customization are fantastic, there’s more to this keyboard than those selling points.</p><p>The elevated keys, with their PBT-coated keycaps, are a joy to type on. One thing I especially appreciate as someone with a heavy touch is how the keys have more resistance the further you press them. The tenkeyless layout is also ideal for me since I don’t need a numberpad, making the board unnecessarily larger.</p><p>The thocky sound the keys produce also makes using the keyboard more enjoyable. Sure, the sound isn’t as deep as you’d find on mechanical keyboards, but it’s still good. While not a clicky board, it’s definitely noisy, so you might not want to use it in an office or anywhere that could annoy others (though I used it in the office anyway!).</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="uuNMe4PGQ9m4HzhL9F2pBB" name="Razer Huntsman V3 TKL 8K--6" alt="Razer Huntsman V3 Tenkeyless 8KHz" src="https://cdn.mos.cms.futurecdn.net/uuNMe4PGQ9m4HzhL9F2pBB.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 aluminum frame not only helps give the keyboard a richer sound, but also makes it sturdy and durable. That’s important if you need to travel with the Huntsman V3. The brushed aluminum is a nice touch that gives the keyboard a more premium look without being overbearing. And while this is a gaming keyboard, it doesn’t look like one thanks to its overall subdued design.</p><p>Of course, if you want more of a gamer aesthetic, there is no shortage of RGB options to toy around with. I’m somewhat neutral on RGB lighting, but I like that folks can customize the lighting to their exact preference. This is Razer, so the company isn’t skimping on that front.</p><p>Lastly, this isn't a wireless keyboard, so you'll need to use a USB-A port on your PC. That said, the braided cable is detachable, which is good if you need to take the keyboard on the road.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eEqDge"></div>                            </div>                            <script src="https://kwizly.com/embed/eEqDge.js" async></script><h2 id="outlook-2">Outlook</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="wCUPYccXjWrNm5u7hH2xcK" name="Razer Huntsman V3 TKL 8K--7" alt="Razer Huntsman V3 Tenkeyless 8KHz" src="https://cdn.mos.cms.futurecdn.net/wCUPYccXjWrNm5u7hH2xcK.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 Razer Huntsman V3 Tenkeyless 8K is an excellent gaming keyboard thanks to its robust, competitive gamer-focused features. Outside of gaming, it also delivers a nice typing experience thanks to its durable build and responsive keys. It’s a bit pricey at $169, but for what it offers, you’re definitely getting your money’s worth.</p><p>Again, I'm a fan of Razer keyboards, and this one has everything I've come to expect from the company's peripherals. While the Pro versions of this keyboard might have more features, I like the simplicity of this board, as it still delivers excellent performance. At $169, it's worth considering.</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/computing/keyboards/logitech-g-g512-x-review">I became a keyboard tinkerer with the Logitech G G512 X</a></li><li><a href="https://www.tomsguide.com/computing/peripherals/i-just-got-my-first-gaming-keyboard-heres-why-ill-never-use-a-regular-board-again">I just got my first gaming keyboard — I’ll never use a regular board again</a></li><li><a href="https://www.tomsguide.com/computing/buying-a-gaming-keyboard-rapid-trigger-and-snap-tap-explained">Buying a gaming keyboard? Rapid Trigger and Snap Tap explained</a></li></ul><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=gaming+laptops&min_discount_ratio=0.95&widget_title=Top+Deals+Handpicked+by+Our+Editors&widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&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 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%;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      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 {      display: flex;      gap: 12px;      justify-content: center;      flex-wrap: wrap;    }    .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;    }        .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 {      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;    }        .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);      display: -webkit-box;      -webkit-line-clamp: 2;      -webkit-box-orient: vertical;      overflow: hidden;    }    .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;    }    .tg-df-container .tg-df-card-cta.tg-df-cta-savings-squad {      background-color: #3c8d0d;    }    .tg-df-card:hover .tg-df-card-cta.tg-df-cta-savings-squad,    .tg-df-card-cta.tg-df-cta-savings-squad:hover {      background-color: #2b6509;    }    /*       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: 0;      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: 0 16px;      }            .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-filters {        width: calc(100% + 32px);        margin: 0 -16px;        padding: 0 16px 4px 16px;        display: flex;        justify-content: flex-start;        gap: 8px;        flex-wrap: nowrap;        overflow-x: auto;        -webkit-overflow-scrolling: touch;        scrollbar-width: none;      }      .tg-df-filters::after {        content: "";        display: block;        flex: 0 0 8px;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }            .tg-df-sort-wrapper {        flex: 0 0 max(42%, 130px);        min-width: 0;      }      .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;      }            .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;        -webkit-line-clamp: 3;      }      /* 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;        -webkit-line-clamp: 3;        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;    }    .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: 16px;      text-align: center;      width: 100%;      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; }    @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: #f8fafc;      border-color: #cbd5e1;    }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right {      background-color: rgba(255, 255, 255, 0.4);      border: none;      box-shadow: none;      backdrop-filter: blur(4px);      -webkit-backdrop-filter: blur(4px);    }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right { right: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-right { right: 0; }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left:hover,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);      border: none;    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-carousel-roundels::after {      content: "";      flex: 0 0 32px;    }    .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;      transition: font-weight 0.2s;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-label {      font-weight: 700;    }    .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;      display: inline-flex;      align-items: center;      justify-content: center;      min-height: 36px;      box-sizing: border-box;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .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::after {      content: "";      flex: 0 0 32px;    }    .tg-df-grid-wrapper {      position: relative;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card {      flex: 0 0 auto;      width: 100px;      border-radius: 15px;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      border: 2px solid #1e293b;      background: white;      color: #1e293b;      display: flex;      flex-direction: column;      justify-content: center;      align-items: center;      font-weight: 600;      font-size: 14px;      cursor: pointer;      padding: 16px;      text-align: center;      transition: all 0.2s;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card:hover {      background: #1e293b;      color: white;    }    .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;      -webkit-line-clamp: 2;      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 {      -webkit-line-clamp: 3;    }    .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.45);        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: #5aaf0b; 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: #4a9109; 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; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \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-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\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>        \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-controls" id="tg-df-controls" style="display:flex;">      \x3Cdiv class="tg-df-top-bar">        \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>                \x3Cdiv class="tg-df-settings-wrapper">          \x3Cbutton type="button" class="tg-df-settings-btn" aria-label="Settings" id="tg-df-settings-toggle">            \x3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20">                \x3Cpath d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.73 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .43-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.49-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>            \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-settings-dropdown-backdrop" id="tg-df-settings-backdrop">\x3C/div>          \x3Cdiv class="tg-df-settings-dropdown" id="tg-df-settings-panel">            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Search Region\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-region-select">                \x3Coption value="auto">🌍 Auto-detect\x3C/option>                \x3Coption value="US">🇺🇸 United States (US)\x3C/option>                \x3Coption value="GB">🇬🇧 United Kingdom (UK)\x3C/option>                \x3Coption value="CA">🇨🇦 Canada (CA)\x3C/option>                \x3Coption value="AU">🇦🇺 Australia (AU)\x3C/option>                \x3Coption value="DE">🇩🇪 Germany (DE)\x3C/option>                \x3Coption value="FR">🇫🇷 France (FR)\x3C/option>                \x3Coption value="IT">🇮🇹 Italy (IT)\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Retailer\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-retailer-select">                \x3Coption value="">All Retailers\x3C/option>                \x3Coption value="Amazon">Amazon\x3C/option>                \x3Coption value="Walmart">Walmart\x3C/option>                \x3Coption value="Best Buy">Best Buy\x3C/option>                \x3Coption value="Target">Target\x3C/option>                \x3Coption value="John Lewis">John Lewis\x3C/option>                \x3Coption value="Currys">Currys\x3C/option>                \x3Coption value="Argos">Argos\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Offer Type\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-offer-type-select">                \x3Coption value="">All Offers\x3C/option>                \x3Coption value="amazon_prime">Amazon Prime\x3C/option>                \x3Coption value="recommended_promo">Recommended Promo\x3C/option>                \x3Coption value="amazon_lightning">Amazon Lightning Deal\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Result Count\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-rows-select">                \x3Coption value="3">3 Items\x3C/option>                \x3Coption value="4">4 Items\x3C/option>                \x3Coption value="6">6 Items\x3C/option>                \x3Coption value="12" selected>12 Items\x3C/option>                \x3Coption value="24">24 Items\x3C/option>                \x3Coption value="48">48 Items\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Deal Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Only show products with active offers or previous prices (was_price)\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-deal-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Editor Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Enable multi-select to copy deals to CMS\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-editor-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">View Mode\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-view-mode-select">                \x3Coption value="auto">Auto Collection\x3C/option>                \x3Coption value="carousel">Carousel\x3C/option>                \x3Coption value="savings_squad">Savings Squad\x3C/option>                \x3Coption value="grid">Grid (Columns)\x3C/option>                \x3Coption value="row">Row (List)\x3C/option>              \x3C/select>            \x3C/div>          \x3C/div>        \x3C/div>      \x3C/div>      \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">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/>          \x3C/svg>          \x3Cselect class="tg-df-sort-select" aria-label="Sort Deals">            \x3Coption value="date_desc">Newest First\x3C/option>            \x3Coption value="best_match">Sort by: Match\x3C/option>            \x3Coption value="price_asc">Price Low to High\x3C/option>            \x3Coption value="price_desc">Price High to Low\x3C/option>            \x3Coption value="discount_desc">Biggest Discount\x3C/option>          \x3C/select>        \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!-- 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();            if (['carousel', 'carousel-compact', 'auto', 'grid', 'row'].includes(this.getViewMode())) { this.loadCarouselSpreadsheet(); }        }        getViewMode() {          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();          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          if (mode === 'carousel' || mode === 'auto' || mode === 'grid' || mode === 'row') {             if (mode === 'carousel') this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container') && mode === 'carousel') {               this.root.classList.add('is-carousel');             } else if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             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 (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Everything';             if (this.discountFilter && !params.has('min_discount_ratio')) {               this.discountFilter.value = '5';             }          }          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 (params.has('bg_color')) {            const bg = params.get('bg_color');            if (bg === 'white') {              this.root.style.setProperty('background-color', '#ffffff', 'important');            } else if (bg === 'transparent') {              this.root.style.setProperty('background-color', 'transparent', 'important');            } else if (bg === 'light_blue') {              this.root.style.setProperty('background-color', '#E7F0FF', 'important');            }          } else {             this.root.style.removeProperty('background-color');          }                    if (params.has('view_mode')) {            if (this.viewModeSelect) {              this.viewModeSelect.value = params.get('view_mode');            } else {              this.viewModeOverride = 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') || 'discount_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }                    // 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) {            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 !== 'discount_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 roundels = this.root.querySelectorAll('.tg-df-carousel-cat.original-hardcoded');          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');              }            });          }          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              if (this.getViewMode() === 'savings_squad' && this.autocompleteDropdown && this.airedaleTags && query.length > 0) {                 const matches = this.airedaleTags.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase()).slice(0, 5);                 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');                 }              } else if (this.autocompleteDropdown) {                 this.autocompleteDropdown.classList.remove('active');              }              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  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;                this.activeDealTag = null;                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   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;                   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 });              this.activeDealTag = null;              this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.fetchDeals(query);              }            });          }          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;               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 = this.viewModeSelect.value === 'savings_squad' ? 'date_desc' : 'discount_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 loadCarouselSpreadsheet() {          try {              const parseCSVRow = (str) => {                  let result = [], cur = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (inQuotes) {                          if (char === '"') {                              if (str[i + 1] === '"') { cur += '"'; i++; }                              else { inQuotes = false; }                          } else { cur += char; }                      } else {                          if (char === '"') { inQuotes = true; }                          else if (char === ',') { result.push(cur); cur = ''; }                          else { cur += char; }                      }                  }                  result.push(cur); return result;              };              const parseCSV = (str) => {                  const rows = []; let curRow = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (char === '"') inQuotes = !inQuotes;                      if ((char === '\n' || char === '\r') && !inQuotes) {                          if (char === '\r' && str[i+1] === '\n') i++;                          if (curRow) rows.push(parseCSVRow(curRow));                          curRow = '';                      } else { curRow += char; }                  }                  if (curRow) rows.push(parseCSVRow(curRow));                  return rows;              };              const preloadedCSV = decodeURIComponent(escape(atob("LCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNQ0KUm91bmRlbCB0ZXh0LEFsbCxUVnMsRm9vdHdlYXIsQXBwYXJlbCxNYXR0cmVzZXMsQXBwbGlhbmNlcyxXZWFyYWJsZSB0ZWNoLEhlYWRwaG9uZXMsU21hcnQgSG9tZSxTcGVha2VycyxMYXB0b3BzLFRhYmxldHMsQ29tcHV0aW5nLFBob25lcyxHYW1pbmcsTGVnbw0KUm91bmRlbCBpbWFnZSxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2FpLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3R2cy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvN2IzYTIyNGIwNzk2M2M2MjdiNmI5MDliZDc4MzM4MzZlMDJmZjgxOS5qcGcud2VicCxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy84NGRhYzVkNDhlZDJkNDQ4NTU5ZWJhNjdhY2U4MzE0Y2M2N2NjZDk0LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvbWF0dHJlc3Nlcy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvNzY4ZTk3Y2ViMDcxODAxZmFlMjA5MTBkMDgyMGIxNmY3NDdhZjkzOS5qcGcud2VicCxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3dlbGxuZXNzLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2hlYWRwaG9uZXMuanBnLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzg5NTM1YmVlYmUyMGRiYmQ0YTM0NmQ2ZDZiZGZlOTFkOGE4ODRhMjEuanBnLndlYnAsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9hdWRpby5qcGcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9sYXB0b3BzLmpwZyxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy8yMzk3NTY0ZWQ3YTVmZjk0N2U5YjZiMzBlNTRmNDc0OTRiODQxZjg5LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvY29tcHV0aW5nLmpwZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3Bob25lcy5wbmcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9nYW1pbmcucG5nLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzRmNmM2MjFjYWMwYmMxYTg1ZDU5M2UzNTk0YmE1YjM0OWVmZmQyOTIuanBnLndlYnANClNlYXJjaCBRdWVyeSxFdmVyeXRoaW5nLFRlbGV2aXNpb25zLCJTbmVha2VycywgcnVubmluZyBzaG9lcywgc2FuZGFscyIsQ2xvdGhpbmcsTWF0dHJlc3NlcyxIb21lIEFwcGxpYW5jZXMsV2VhcmFibGVzICYgRml0bmVzcyBUZWNoLEhlYWRwaG9uZXMsSG9tZSBUZWNoLFNwZWFrZXJzLExhcHRvcHMsVGFibGV0cyxDb21wdXRpbmcsUGhvbmVzLEdhbWluZyxDb25zdHJ1Y3Rpb24gVG95cw0KRGlzY291bnQgQW1vdW50LG1pbiA1JSxtaW4gMTAlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUNClByaWNlIFJhbmdlLCwsLCxtaW4gJDQwMCwsLCxtaW4gJDI1LCxtaW4gJDMwMCwsLG1pbiAkMTAwLCwNCkJyYW5kIFNlbGVjdGlvbiwsLCwsLCwsLCwsLCwsLCwNCkZpbHRlciBidXR0b25zLCwsLCwsLCwsLCwsLCwsLA0KMSxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMNCjIsQW1hem9uIGRlYWxzLFVuZGVyICQxMDAwLDUwJSBvZmYsQWRpZGFzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsNTAlIG9mZixBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscw0KMyxPdmVyICQ0MDAsVW5kZXIgJDUwMCxIb2thLE5pa2UsU2FhdHZhLE5pbmphLDQwJSBvZmYsSkxhYiwsSkJMLERlbGwsLEFzdXMsQXBwbGUsQ29uc29sZXMsU3RhciBXYXJzDQo0LFVuZGVyICQxMDAwLDUwJSBvZmYsU2tlY2hlcnMsVW5kZXIgQXJtb3VyLEhlbGl4LFNoYXJrLEdhcm1pbixBbmtlciBTb3VuZGNvcmUsUmluZyxTb25vcyxBcHBsZSxBcHBsZSxUUC1saW5rLFNhbXN1bmcsQWNjZXNzb3JpZXMsVW5kZXIgJDI1DQo1LFVuZGVyICQ1MDAsTEcsQXNpY3MsQ29sdW1iaWEsRHJlYW1DbG91ZCxLZXVyaWcsQXBwbGUsU29ueSxHb3ZlZSxUcmliaXQsTGVub3ZvLFNhbXN1bmcsRWVybyxHb29nbGUsR2FtZXMsVW5kZXIgJDUwDQo2LDUwJSBvZmYsU2Ftc3VuZyxOaWtlLFBhdGFnb25pYSxOZWN0YXIsRGUnTG9uZ2hpLEFtYXpmaXQsQXBwbGUsS2FzYSBzbWFydCxTb255LEFsaWVud2FyZSxUQ0wsTmV0Z2VhcixNb3Rvcm9sYSxOaW50ZW5kbyxCb3RhbmljYWxzDQo3LEFtYXpvbixIaXNlbnNlLE5ldyBCYWxhbmNlLEFyYyd0ZXJ5eCxUZW1wdXItcGVkaWMsRHlzb24sRml0Yml0LEJlYXRzLFBoaWxpcHMgSHVlLEFua2VyLEFjZXIsT25lUGx1cyxEZWxsLE9uZVBsdXMsU29ueSxEaXNuZXkNCjgsQXBwbGUsVENMLEFkaWRhcyxDYXJoYXJ0dCxCZWFyLEJpc3NlbGwsU2Ftc3VuZyxFYXJmdW4sQmxpbmssQmVhdHMsTVNJLE1pY3Jvc29mdCxBY2VyLE5vdGhpbmcsWGJveCxNYXJ2ZWwNCjksLFNvbnksU2F1Y29ueSxUaGUgTm9ydGggRmFjZSxTaWVuYSxOdXRyaWJ1bGxldCxPdXJhLFNhbXN1bmcsR29vZ2xlIE5lc3QgLE1hcnNoYWxsLFNhbXN1bmcsTGVub3ZvLExlbm92bywsLFBva2Vtb24NCjEwLCxSb2t1LEJpcmtlbnN0b2NrLENSWiBZb2dhLFdpbmtCZWRzLEJsYWNrIGFuZCBEZWNrZXIsUmluZ2Nvbm4sQ01GLEV1ZnksU2Ftc3VuZyxNaWNyb3NvZnQsUmVNYXJrYWJsZSxBbGllbndhcmUsLCwNCjExLCwsQnJvb2tzLFRoZSBHeW0gUGVvcGxlLEJyb29rbHluIGJlZGRpbmcsTmVzcHJlc3NvLCwxTW9yZSxBcmxvLCxSYXplciwsQ29yc2FpciwsLA0KMTIsLCxDcm9jcywsRWlnaHQgU2xlZXAsQ3Vpc2luYXJ0LCxKQkwsLCwsLEhQLCwsDQpOb3RlcywsLCwsLCwsLCwsLCwsLCwNCiwsIlByaW9yaXRpc2UgYmlnZ2VzdCAlLyQgZGlzY291bnQsIFR2cyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiB0aGUgbW9zdCBwb3B1bGFyIGV2ZW4gaWYgdGhleSBhcmUgc3RpbGwgZXhwZW5zaXZlIiwiTm8gcGF0dGVybiB0byBwcmljaW5nL2Rpc2NvdW50LCByZWFkZXJzIG1haW5seSBzaG9wIGJ5IGJyYW5kL3JlY29nbmlzYWJsZSBzaG9lcyIsIk5vIHBhdHRlcm4gdG8gcHJpY2luZy9kaXNjb3VudCwgcmVhZGVycyBtYWlubHkgc2hvcCBieSBicmFuZCIsIkEgbGFiZWwgd2lsbCBkZWZpbml0ZWx5IGhlbHAgaGVyZSBlLmcuIGJlc3QgZm9yIHNpZGUgc2xlZXBlciwgYmVzdCBtZW1vcnkgZm9hbSIsIkFwcGxpYW5jZXMgaXMgYSBiaWcgY2F0ZWdvcnksIGlzIGl0IHBvc3NpYmxlIHRvIHNwbGl0IGludG8ga2l0Y2hlbiBhcHBsaWFuY2VzLCBmbG9vcmNhcmUsIGFpciBoZWFsdGgvY29vbGluZz8gT3Igc2ltaWxhciIsIkZvY3VzIG9uIHZhbHVlIGZvciBtb25leSwgR2FybWlucyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiBwb3B1bGFyIGV2ZW4gdGhvdWdoIHRoZXkgYXJlIHN0aWxsICQ1MDAiLCwsLCxJbmNsdWRlIEtpbmRsZXMsSSB3b3VsZCBpbmNsdWRlIHdpZmkgcm91dGVycyBoZXJlIGluc3RlYWQgb2Ygc21hcnQgaG9tZSxDYW4gd2Ugc3VyZmFjZSBwaG9uZSBwcm92aWRlciBkZWFscz8gVC1tb2JpbGUgYW5kIHZlcml6b24gd291bGQgbWFrZSBhIGxvdCBtb3JlIG1vbmV5IHRoYW4gQW1hem9uLCwNCiwsaGF2aW5nIGEgJ2Jlc3QgZm9yJyBsYWJlbCB3b3VsZCBiZSBoZWxwZnVsIGUuZy4gYmVzdCBmb3IgYnJpZ2h0IHJvb20sQ2FuIHdlIHN0b3Aga2lkcyBzaG9lcyBmcm9tIHB1bGxpbmcgdGhyb3VnaD8sIldpbGwgdGhpcyBpbmNsdWRlIGFjY2Vzc29yaWVzIGUuZy4gY2FwcywgYmFncywgaWYgc28gbWFrZSBzdXJlIHRoZXNlIGFyZSBtaXhlZCB0aHJvdWdob3V0IGNsb3RoaW5nIGRlYWxzIixXaWxsIHRoaXMgaW5jbHVkZSB0b3BwZXJzIGFuZCBwaWxsb3dzPyBTZWVpbmcgbW9yZSBtb21lbnR1bSB3aXRoIHRoaXMgY2F0ZWdvcnkgcmVjZW50bHkgc28gYSBiZWRkaW5nIHRhYiBtaWdodCB3b3JrLCwiTmVlZCB0byBtYWtlIHN1cmUgYmFuZHMsIHNjcmVlbiBwcm90ZWN0b3JzIGV0Yy4gZG9uJ3QgcHVsbCBpbnRvIGhlcmUiLCwsLCwsLCwsDQosLCJQcmlvcml0aXNlIDY1JycgYW5kIDU1JyBpbmNoIFRWcywgdGhlbiBiaWdnZXIgc2NyZWVucyBiZWZvcmUgdGhlIHNtYWxsZXIgc2l6ZXMiLCwsUXVlZW4gaXMgdGhlIG1vc3QgcG9wdWxhciBzaXplIGluIHRoZSBVUyAtIHByaW9yaXRpc2UgZGVhbHMgZm9yIHRoaXMgc2l6ZSwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpDYXRlZ29yaWVzIHRvIGNvbnNpZGVyLCxQcm9kdWN0cyBpbmNsdWRlZCwsLCwsLCwsLCwsLCwsDQpVbmRlciAkNTA/LCxBaXIgdGFncywsLCwsLCwsLCwsLCwsDQosLFBvcnRhYmxlIGNoYXJnZXJzL3dpcmVsZXNzIGNoYXJnZXJzLCwsLCwsLCwsLCwsLCwNCiwsIldhdGVyIGJvdHRsZXMgKHN0YW5sZXlzLCBPd2FsYSwgSHlkcm8gZmxhc2ssIFlldGkpIiwsLCwsLCwsLCwsLCwsDQosLEhhbmQgaGVsZCBmYW5zLCwsLCwsLCwsLCwsLCwNCiwsLCwsLCwsLCwsLCwsLCwNCmhvbWUgb2ZmaWNlLCxvZmZpY2UgY2hhaXJzLCwsLCwsLCwsLCwsLCwNCiwsc3RhbmRpbmcgZGVza3MsLCwsLCwsLCwsLCwsLA0KLCxtb25pdG9ycywsLCwsLCwsLCwsLCwsDQosLEtleWJvYXJkcywsLCwsLCwsLCwsLCwsDQosLGRvY2tpbmcgc3RhdGlvbiwsLCwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpHYW1pbmcsLENvbnNvbGVzLCwsLCwsLCwsLCwsLCwNCiwsQWNjZXNzb3JpZXMsLCwsLCwsLCwsLCwsLA0KLCxHYW1lcywsLCwsLCwsLCwsLCwsDQosLENvdWxkIGluY2x1ZGUgTGVnbz8sLCwsLCwsLCwsLCwsLA==")));              const text = preloadedCSV;              const parsed = parseCSV(text);                            const rowsByName = {};              let filterStart = -1;              parsed.forEach((rc, i) => {                 if (rc && rc.length > 0 && rc[0]) rowsByName[rc[0]] = rc;                 if (rc && rc.length > 0 && rc[0] === 'Filter buttons') filterStart = i;              });                            const cols = [];              if(rowsByName['Roundel text']) {                const headerRow = rowsByName['Roundel text'];                for(let col = 1; col < headerRow.length; col++) {                   let label = headerRow[col];                   if (!label) continue;                                      let q = rowsByName['Search Query'] && rowsByName['Search Query'][col] ? rowsByName['Search Query'][col] : '';                   let img = rowsByName['Roundel image'] && rowsByName['Roundel image'][col] ? rowsByName['Roundel image'][col] : '';                   let ds = rowsByName['Discount Amount'] && rowsByName['Discount Amount'][col] ? rowsByName['Discount Amount'][col] : '';                   let pr = rowsByName['Price Range'] && rowsByName['Price Range'][col] ? rowsByName['Price Range'][col] : '';                   let rt = rowsByName['Retailer'] && rowsByName['Retailer'][col] ? rowsByName['Retailer'][col] : '';                   let ot = rowsByName['Offer Type'] && rowsByName['Offer Type'][col] ? rowsByName['Offer Type'][col] : '';                                      let filters = [];                   if(filterStart > 0) {                     for(let r = filterStart + 1; r < parsed.length; r++) {                         if(!parsed[r] || parsed[r][0] === 'Notes' || parsed[r][0] === 'Categories to consider') break;                         let f = parsed[r][col];                         if(f) filters.push(f);                     }                   }                   cols.push({ label, img, q, ds, pr, rt, ot, filters });                }              }              this.carouselData = cols;              if (this.carouselData && this.carouselData.length > 0) {                 const isMatched = this.carouselData.some(c => c.q === this.currentQuery || c.label === this.currentQuery);                 if (!isMatched) {                    const first = this.carouselData[0];                    this.currentQuery = first.q || first.label;                    if (this.priceFilter) this.priceFilter.value = 'all';                    if (this.customPriceMin) this.customPriceMin.value = '';                    if (this.customPriceMax) this.customPriceMax.value = '';                    let dPr = first.pr || 'all';                    if (typeof dPr === 'string' && dPr !== 'all') {                       let prLower = dPr.toLowerCase();                       if (prLower.includes('min') || prLower.includes('over')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else if (prLower.includes('max') || prLower.includes('under')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       }                    }                    let dAm = '0';                    if(first.ds && typeof first.ds === 'string') {                       let m = first.ds.match(/(\d+)/);                       if(m) dAm = m[1];                    }                    if (this.discountFilter) this.discountFilter.value = dAm;                    if (this.offerTypeSelect) this.offerTypeSelect.value = first.ot || '';                    if (this.retailerSelect) this.retailerSelect.value = first.rt || '';                    this.selectedBrands = [];                    if (this.brandDropdown) {                        const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                        chks.forEach(chk => chk.checked = false);                    }                    if (this.searchInput) this.searchInput.value = this.currentQuery;                 }              }              this.renderCarouselUI();          } catch(e){ console.warn(e); }        }                renderCarouselUI() {           const roundelWrapper = this.root.querySelector('.tg-df-carousel-roundels');           if(!roundelWrapper || !this.carouselData) return;                      let html = '';           this.carouselData.forEach(r => {              const q = r.q || r.label;              const isActive = (this.currentQuery === q || this.currentQuery === r.label) ? 'active' : '';              const imgHtml = r.img ? `\x3Cimg src="${r.img}" alt="${r.label}" />` : `\x3Csvg width="32" height="32" fill="#1F69FF" viewBox="0 0 24 24">\x3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>\x3C/svg>`;              html += `                \x3Cdiv class="tg-df-roundel tg-df-carousel-cat ${isActive}" data-label="${this.escapeHTML(r.label)}">                  \x3Cdiv class="tg-df-roundel-img-box">${imgHtml}\x3C/div>                  \x3Cspan class="tg-df-roundel-label">${this.escapeHTML(r.label)}\x3C/span>                \x3C/div>              `;           });           roundelWrapper.innerHTML = html;                      // Rebind clicks           const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');           roundels.forEach(rNode => {             rNode.addEventListener('click', () => {                const r = this.carouselData.find(c => c.label === rNode.getAttribute('data-label'));                 if(!r) return;                                  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: r.label,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = r.q || r.label;                const labelTitle = this.root.querySelector('#tg-df-carousel-title-label');                if (labelTitle) labelTitle.textContent = 'Best ' + this.currentQuery;                if (this.priceFilter) this.priceFilter.value = 'all';                if (this.customPriceMin) this.customPriceMin.value = '';                if (this.customPriceMax) this.customPriceMax.value = '';                let dPr = r.pr || 'all';                if (typeof dPr === 'string' && dPr !== 'all') {                   let prLower = dPr.toLowerCase();                   if (prLower.includes('min') || prLower.includes('over')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMin) this.customPriceMin.value = m[1];                   } else if (prLower.includes('max') || prLower.includes('under')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMax) this.customPriceMax.value = m[1];                   }                }                                let discountAmount = '0';                if(r.ds && typeof r.ds === 'string') {                   let m = r.ds.match(/(\d+)/);                   if(m) discountAmount = m[1];                }                if (this.discountFilter) this.discountFilter.value = discountAmount;                if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                                // Clear brands                    this.selectedBrands = [];                    if (this.brandDropdown) {                    const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                    chks.forEach(chk => chk.checked = false);                }                                if (this.searchInput) this.searchInput.value = this.currentQuery;                                roundels.forEach(ro => ro.classList.remove('active'));                if (rNode) rNode.classList.add('active');                                this.renderCarouselFilters(r);                this.fetchDeals(this.currentQuery);             });           });                      // Auto-highlight active           const activeR = this.carouselData.find(c => c.q === this.currentQuery || c.label === this.currentQuery);           if(activeR) this.renderCarouselFilters(activeR);        }                renderCarouselFilters(r) {           const filtersWrap = this.root.querySelector('.tg-df-carousel-filters-wrap');           if(!filtersWrap) return;                      let html = `\x3Cbutton class="tg-df-carousel-filter-btn" data-type="all">All\x3C/button>`;                      r.filters.forEach(f => {              let fL = f.toLowerCase();              let icon = '';              let logic = `data-type="custom" data-v="${this.escapeHTML(f)}"`;              if (fL === 'amazon deals' || fL === 'prime deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\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>`;              } else if (fL === 'lightning deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\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>`;              } else {                 if (fL.includes('lightning')) {                    icon = `\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-zap">\x3Cpolygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2">\x3C/polygon>\x3C/svg>`;                 } else if (fL.includes('% off')) {                    icon = `\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>`;                 } else if (fL.includes('under') || fL.includes('min ')) {                    icon = `\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>`;                 }                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>${icon} ${this.escapeHTML(f)}\x3C/button>`;              }           });                      filtersWrap.innerHTML = html;                      const btns = filtersWrap.querySelectorAll('button');           btns.forEach(b => {             b.addEventListener('click', () => {                const type = b.getAttribute('data-type');                if (type === 'custom') {                   const v = b.getAttribute('data-v');                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-custom-${(v||'').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, name: 'Custom Filter', label: v });                }                if (type === 'all') {                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: 'filter-clear-all', name: 'Clear all', label: 'Clear all filters' });                   // reset everything                   btns.forEach(btn => btn.classList.remove('active'));                   b.classList.add('active');                                      // Reset prices                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   if (this.brandDropdown) {                     const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                     chks.forEach(chk => chk.checked = false);                   }                } else {                   const v = b.getAttribute('data-v');                   const fL = v.toLowerCase();                                      let mapRet = ['amazon', 'walmart', 'best buy', 'target', 'john lewis', 'currys', 'argos'];                   const getCategory = (s) => {                      if (s === 'lightning deals' || s === 'amazon deals' || s === 'prime deals') return 'offer';                      if (s.includes('% off')) return 'discount';                      if (s.includes('under') || s.includes('over') || s.includes('min') || s.includes('max')) return 'price';                      if (mapRet.includes(s)) return 'retailer';                      return 'brand';                   };                   const cat = getCategory(fL);                   const wasActive = b.classList.contains('active');                   if (cat !== 'brand') {                      btns.forEach(btn => {                          if (btn === b) return;                          if (btn.getAttribute('data-type') === 'all') return;                          const bV = btn.getAttribute('data-v');                          if (!bV) return;                          if (getCategory(bV.toLowerCase()) === cat) btn.classList.remove('active');                      });                   }                   if (wasActive) b.classList.remove('active');                   else b.classList.add('active');                   let anyActive = Array.from(btns).some(btn => btn !== btns[0] && btn.classList.contains('active'));                   if (!anyActive) {                       btns[0].click();                       return;                   } else {                       btns[0].classList.remove('active');                   }                                      if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   btns.forEach(btn => {                       if (!btn.classList.contains('active') || btn.getAttribute('data-type') === 'all') return;                       const vv = btn.getAttribute('data-v');                       const vl = vv.toLowerCase();                                              if (vl === 'lightning deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_lightning';                       } else if (vl === 'amazon deals' || vl === 'prime deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_prime';                       } else if (vl.includes('% off')) {                          let m = vl.match(/(\d+)%/);                          if (m && this.discountFilter) this.discountFilter.value = m[1];                       } else if (vl.includes('under') || vl.includes('max')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       } else if (vl.includes('min') || vl.includes('over')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else {                          let foundR = mapRet.find(x => x === vl);                          if (foundR) {                             let realR = ['Amazon', 'Walmart', 'Best Buy', 'Target', 'John Lewis', 'Currys', 'Argos'].find(x => x.toLowerCase() === vl);                             if (this.retailerSelect) this.retailerSelect.value = realR;                          } else {                             this.selectedBrands.push(vv);                          }                       }                   });                                      if (this.brandDropdown) {                       const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                       chks.forEach(c => c.checked = this.selectedBrands.includes(c.value));                   }                                      if (r.pr && typeof r.pr === 'string') {                       let prL = r.pr.toLowerCase();                       if (prL.includes('under $')) {                           let m = prL.match(/under \$(\d+)/i);                           if (m && this.customPriceMax && !this.customPriceMax.value) this.customPriceMax.value = m[1];                       }                   }                }                                this.fetchDeals(this.currentQuery);             });           });                      // default to highlighting first           btns[0].classList.add('active');        }async fetchDeals(query, append = false) {          if (!append) {             this.showLoading();             this.deals = [];             this.displayLimit = this.getRowsLimit();          } else {             this.displayLimit += this.getRowsLimit();          }                    try {            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad(append);            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query, append);               } else {                 await this.fetchHawkDeals(query, append);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query, append);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&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=tomsguide&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) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const url = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&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 dynamicBrandsCounts = {};                    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();                   dynamicBrandsCounts[data.brand] = (dynamicBrandsCounts[data.brand] || 0) + 1;                }                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;                   }                }                                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 || ''                });             });          });                    const airedaleBrandsList = Object.keys(dynamicBrandsCounts).map(b => ({              formatted_value: b,              count: dynamicBrandsCounts[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, append = false) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (append && this.deals.length > 0) {            url.searchParams.append('offset', this.deals.length.toString());          }                    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 : (this.getViewMode() === 'savings_squad' ? 'date_desc' : 'discount_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}                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin-top:8px;">${_div}                ${_div}              ${_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)} (${this.airedaleTagCounts[tag] || 0})${_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 = isSavingsSquadMode ? 'View Deal' : 'Check Price';              if (isSavingsSquadMode) {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                  ${_div}                `;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \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 = `                \x3Cdiv class="tg-df-card-merchant-wrapper">                  \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                ${_div}                \x3Cdiv class="tg-df-card-price-group">                  ${isSavingsSquadMode ? '' : `                  \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">\x3Cp>${this.escapeHTML(deal.description)}${_p}${_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>${deal.isCheckPrice ? 'Check Price' : '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}                ${_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 ? `\x3Cp style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 12px; line-height: 1.4;">${this.escapeHTML(deal.description)}${_p}` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${priceGroupHtml}                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta ${isSavingsSquadMode ? 'tg-df-cta-savings-squad' : ''}" style="text-decoration: none;">${ctaText}${_a}                  ${_div}                ${_div}              ${_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 || ((this.getViewMode() === 'carousel' || this.getViewMode() === 'auto') && displayDeals.length > 0 && displayDeals.length % ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12) === 0)) {            if (this.getViewMode() === 'carousel') {               dealsHtml += `                 \x3Cbutton type="button" class="tg-df-load-more-card tg-df-load-more">                   \x3Csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-bottom: 8px;">\x3Cpath d="M5 12h14">\x3C/path>\x3Cpath d="m12 5 7 7-7 7">\x3C/path>\x3C/svg>                   Load More                 ${_button}               `;            } else {               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; display: flex; align-items: center;">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); }                    let gridWrapper = this.grid.parentElement;          if (gridWrapper && gridWrapper.classList.contains('tg-df-grid-wrapper')) {             let rightChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-right');             let leftChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-left');             if (this.getViewMode() === 'carousel') {                 // The observer set up in setupScrollListeners handles visibility.                 if (rightChevron) rightChevron.style.display = 'flex';                 if (leftChevron) leftChevron.style.display = 'none'; // reset correctly             } else {                 if (rightChevron) rightChevron.style.display = 'none';                 if (leftChevron) leftChevron.style.display = 'none';             }          }                    const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', async () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              if (displayDeals.length <= this.displayLimit) {                 loadMoreBtn.innerHTML = `                  <svg class="tg-df-spinner" style="width: 16px; height: 16px; display: inline-block; vertical-align: middle; margin-right: 8px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/></svg>                  Loading...                 `;                 loadMoreBtn.disabled = true;                 await this.fetchDeals(this.currentQuery, true);              } else {                 this.displayLimit += this.getRowsLimit();                 this.render();              }            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();                        // 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');            }            setTimeout(() => {               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);          } 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 just tested the new Alienware 34 280Hz QD-OLED — and it’s about as perfect as gaming monitors can get ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/alienware-34-280hz-qd-oled-aw3426dw-review</link>
                                                                            <description>
                            <![CDATA[ The Alienware 34 280Hz OLED features the same design and curved panel as before, only with brighter HDR and a faster refresh rate. At $799, it's a no-brainer. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">ReBSjYyyMgtFDsdVeHaWPc</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/zqifcW3uuqi28RXrZPDUAV-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 09 Jul 2026 13:00:00 +0000</pubDate>                                                                                                                                <updated>Tue, 14 Jul 2026 09:17:23 +0000</updated>
                                                                                                                                            <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/zqifcW3uuqi28RXrZPDUAV-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Alienware AW3426DW]]></media:description>                                                            <media:text><![CDATA[Alienware AW3426DW]]></media:text>
                                <media:title type="plain"><![CDATA[Alienware AW3426DW]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/zqifcW3uuqi28RXrZPDUAV-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I’ve been a big fan of the Alienware 34 QD-OLED gaming monitor series since its launch in 2022. Subsequent models have introduced subtle but necessary improvements over the years, maintaining the line’s sterling reputation. Now, we have the best iteration yet — the new Alienware 34 280Hz QD-OLED (AW3426DW).</p><p>Like the AW3425DW before it, this latest model features an immersive 1800R curved panel with an ultrawide 21:9 aspect ratio. It retains the same flat, space-saving stand and the classy “Interstellar Indigo” color I’ve grown to love. This is a seriously sexy-looking gaming monitor.</p><p>As for what’s new, we get a higher refresh rate of 280Hz, up from the previous 240Hz. Then there’s the 4-stack Penta Tandem tech that delivers deeper blacks even in bright environments, along with sharper text with no fringing. Best of all, the panel is now brighter than before, which addresses my chief complaint with prior versions.</p><p>Given all its improvements and the same relatively low $799 asking price, the Alienware AW3426DW is another winner and an easy addition to our <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html"><u>best gaming monitors</u></a> list. Find out why in my full review.</p><h3 class="article-body__section" id="section-alienware-34-280hz-qd-oled-review-cheat-sheet"><span>Alienware 34 280Hz QD-OLED review: Cheat sheet</span></h3><ul><li><strong>What is it?</strong> The Alienware AW3426DW is a curved ultrawide QD-OLED gaming monitor.</li><li><strong>Who is it for?</strong> For gamers seeking a curved OLED gaming monitor priced under $1,000.</li><li><strong>How much does it cost?</strong> The Alienware AW3426DW costs $799, which is the same price as last year's model.</li><li><strong>What do we like?</strong> We like the vivid ultrawide display, elegant design, fast performance, and clean UI.</li><li><strong>What don’t we like?</strong> Not worth upgrading from the previous model.</li></ul><h3 class="article-body__section" id="section-alienware-34-280hz-qd-oled-review-specs"><span>Alienware 34 280Hz QD-OLED review: Specs</span></h3><div ><table><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>Alienware AW3426DW</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p>$799</p></td></tr><tr><td class="firstcol " ><p><strong>Display</strong></p></td><td  ><p>34 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Resolution</strong></p></td><td  ><p>3440 x 1440</p></td></tr><tr><td class="firstcol " ><p><strong>Aspect ratio</strong></p></td><td  ><p>21:9</p></td></tr><tr><td class="firstcol " ><p><strong>Refresh rate</strong></p></td><td  ><p>280Hz</p></td></tr><tr><td class="firstcol " ><p><strong>Response time</strong></p></td><td  ><p>0.03ms</p></td></tr><tr><td class="firstcol " ><p><strong>Panel type</strong></p></td><td  ><p>QD-OLED</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>1x DisplayPort, 2x HDMI, 1x USB-A, 1x USB-B, 1x USB-C</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>32.05 x 14.23 x 4.38 inches (without stand)</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>17.95 pounds (with stand)</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-alienware-34-280hz-qd-oled-review-the-ups"><span>Alienware 34 280Hz QD-OLED review: The ups</span></h3><p>The Alienware 34 280Hz OLED is a phenomenal gaming monitor thanks to its sleek, space-saving design, vibrant picture quality, and buttery smooth performance.</p><h2 id="elegant-design">Elegant design</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:5609px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="mQXGfUW2X6zxSANXfyvZYR" name="Alienware 34 QD-OLED 2026-2" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/mQXGfUW2X6zxSANXfyvZYR.jpg" mos="" align="middle" fullscreen="" width="5609" height="3155" 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 Alienware AW3426DW shares the same design as its predecessor, which I’m okay with given how lovely and practical it still is. It won’t look out of place in an office environment or a gaming den.</p><p>With its panel measuring 32.05 x 14.23 x 4.38 inches, you’ll need a decent-sized table for this beauty, but nothing overly large. The flat stand is unobtrusive, so it’s unlikely to get in the way of peripherals like your keyboard and mouse. The cutaway on the stand’s shaft makes cable management easy, and you can raise or lower the monitor to your desired height.</p><p>You can raise or lower the screen by 4.3 inches along the stand’s shaft and tilt it backward by 5 degrees or forward by up to 21 degrees. You can also swivel the screen 20 degrees left and right. Adjusting the screen to your preferred viewing angle is seamless and should take less than a minute.</p><p>There’s a good selection of ports on the back, including a pair of HDMI 2.1 ports, a DisplayPort, a USB-A port, a USB-B port, and a single USB-C port. There’s also an OSD (on-screen display) joystick just below the ports, which you use to access and navigate the display settings.</p><p>Again, I’m glad Alienware didn’t change the AW3426DW’s design, since it’s about as perfect as you can get. It might not immediately scream “gaming monitor,” but it keeps the focus on the display and, thus, on whatever game you’re currently playing.</p><h2 id="vivid-panel">Vivid panel</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:4666px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="82cSzcb2sG9f78SSyKcF56" name="Alienware 34 QD-OLED 2026-LIST" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/82cSzcb2sG9f78SSyKcF56.jpg" mos="" align="middle" fullscreen="" width="4666" height="2625" 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 Alienware AW3426DW draws you into whatever game you’re playing thanks to its immersive 1800R curvature, sharp 3,440 x 1,440 resolution, and expansive 21:9 aspect ratio. The image quality is so good that you won’t mind that it’s not a 4K OLED panel. </p><p>I tested <a href="https://www.tomsguide.com/reviews/cyberpunk-2077">Cyberpunk 2077</a> and was blown away by the rich picture quality. The increased contrast between dark and light elements is noticeable on this updated panel, making colors feel more vibrant. It’s also brighter than other OLED gaming monitors, resulting in a more vivid image overall.</p><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Alienware AW3426DW</strong></p></td><td  ><p><strong>Asus ROG Swift OLED</strong></p></td><td  ><p><strong>Alienware 27 AW2726DM</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Nits (brightness)</strong></p></td><td  ><p>298</p></td><td  ><p>252</p></td><td  ><p>181</p></td></tr><tr><td class="firstcol " ><p><strong>sRGB</strong></p></td><td  ><p>187.6%</p></td><td  ><p>198.8%</p></td><td  ><p>190%</p></td></tr><tr><td class="firstcol " ><p><strong>DCI-P3</strong></p></td><td  ><p>132.9%</p></td><td  ><p>140.8%</p></td><td  ><p>140.9%</p></td></tr><tr><td class="firstcol " ><p><strong>Delta-E</strong></p></td><td  ><p>0.20</p></td><td  ><p>0.30</p></td><td  ><p>0.24</p></td></tr></tbody></table></div><p>Our lab tests align with my own testing. In its standard display mode, the AW3426DW produces oversaturated colors in sRGB and DCI-P3, while maintaining good color accuracy (Delta-E). As shown in the table above, its color representation and accuracy are comparable to those of the $899 Asus ROG Swift OLED (PG34WCDM) and the $349 Alienware 27 AW2726DM.</p><p>Where the AW3426DW literally outshines the competition is in brightness, which is generally around 300 nits. We even saw HDR nearly hit 500 nits on 10% of the display in certain modes. That might not sound high, but considering how similar gaming monitors are in the 200 to 250 nit range, this is marvelous. Right now, it’s one of the brightest gaming monitors I’ve tested.</p><p>You’ll find 11 display modes here. This includes modes dedicated to game genres like FPS, RTS, and Sports. The monitor also has a Creator mode, which offers better color accuracy for creatives (as the name suggests). Other than that, the modes are only slightly different from one another, depending on what they’re designed for.</p><h2 id="excellent-performance">Excellent performance</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:3632px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="TFv3c7xBzm337tLujZ4pRE" name="Alienware 34 QD-OLED 2026-1" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/TFv3c7xBzm337tLujZ4pRE.jpg" mos="" align="middle" fullscreen="" width="3632" height="2043" 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 AW3426DW performs like a dream thanks to its high 280Hz refresh rate and low 0.03ms response time. Compatibility with Nvidia G-Sync and AMD FreeSync also ensures a buttery-smooth gaming experience for both casual gamers and professionals.</p><p>I tested the AW3426DW by connecting it to the new <a href="https://www.tomsguide.com/computing/gaming-laptops/alienware-16-area-51-gaming-laptop-review">Alienware 16 Area-51</a> gaming laptop, which packs an Intel Core Ultra 9 290HX CPU, an Nvidia RTX 5080 GPU, and 32GB RAM. You don’t need a gaming rig this powerful to enjoy the monitor, but having the extra horsepower helps if you’re trying to maximize frame rates to match the refresh rate.</p><p>Thanks to the high refresh rate and low latency, I had a smooth time playing Cyberpunk 2077. I couldn’t get the frame rate anywhere near the refresh rate, but having all that extra headroom effectively eliminates any choppiness. I also didn’t notice any input lag. Like previous models, you’ll get excellent gaming performance from the AW3426DW.</p><h2 id="intuitive-ui">Intuitive UI</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="Gp3k5HB89ou7yGuq6XfiNn" name="Alienware AW3426DW Gaming Monitor-7" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/Gp3k5HB89ou7yGuq6XfiNn.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>We get the same basic interface as on previous models. The UI features a black-and-gray background with blue-and-white lettering. Within the menus, you’ll find the aforementioned display modes and other settings to adjust the picture to your liking. While there’s certainly a lot to go through, it’s easy enough to find what you’re looking for.</p><p>As always, the OSD joystick you use to navigate the menus is responsive and easy to reach. It isn’t flimsy either, despite being a relatively small joystick.</p><h3 class="article-body__section" id="section-alienware-34-280hz-qd-oled-review-the-downs"><span>Alienware 34 280Hz QD-OLED review: The downs</span></h3><p>If you’re new to the Alienware 34 QD-OLED series, you’re in for a treat thanks to everything this gaming monitor offers. However, if you own the previous model, you might want to hold off.</p><h2 id="a-minor-upgrade">A minor upgrade</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:5326px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="yqhBJPXYWF2FT5LtiLHtye" name="Alienware 34 QD-OLED 2026-3" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/yqhBJPXYWF2FT5LtiLHtye.jpg" mos="" align="middle" fullscreen="" width="5326" height="2996" 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 Alienware AW3426DW is a nearly perfect gaming monitor for what it offers. If you’ve never owned a monitor in this lineup, then this is an easy recommendation. This is especially true thanks to its $799 asking price.</p><p>While the AW3426DW is undeniably great, it’s not a mandatory upgrade if you own its direct predecessor. Yes, the higher refresh rate and sharper image make a difference, but not a major one. Besides that, the AW3426DW has the same design as before and many of the same features.</p><p>If you own the original AW3423DW — which has lower performance and a less desk-friendly design — then upgrading to the AW3426DW is a no-brainer. If you have the 2025 model, then you can skip this one, as that older monitor is still fantastic.</p><h3 class="article-body__section" id="section-alienware-34-280hz-qd-oled-review-verdict"><span>Alienware 34 280Hz QD-OLED review: Verdict</span></h3><p>The Alienware AW3426DW is a phenomenal gaming monitor thanks to its immersive, sharp display, excellent performance, and elegant design. Though it’s not a major upgrade from last year’s model, it’s an easy choice for anyone looking to upgrade from an older monitor. And in a time when everything is going up in price, I commend Alienware for keeping this at $799.</p><p>If you’re looking for a smaller and more affordable gaming monitor with a QD-OLED panel and fast performance, you can’t go wrong with the $349 Alienware 27 AW2726DM. And if you’re willing to pay $100 for a more overtly “gaming” monitor, then the Asus ROG Swift OLED is a phenomenal pick.</p><p>Though there are certainly other solid options, few deliver the same brilliant experience as the Alienware AW3426DM. This is still my favorite gaming monitor line. As such, this model comes with my highest recommendation. I promise you won’t be disappointed.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Steam Machine vs. PS5 Pro — there’s a clear winner (for most gamers) ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/steam-machine-vs-ps5-pro-theres-a-clear-winner-for-most-gamers</link>
                                                                            <description>
                            <![CDATA[ Is the $899 PS5 Pro a better value than the $1,049 Steam Machine? We look at the pros and cons of each platform to determine which offers more. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">JwvoHGEQuzKtVT2RmMUj8K</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/aDHDQdFKxRTwaNvpAinvG8-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 03 Jul 2026 04:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/aDHDQdFKxRTwaNvpAinvG8-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[PS5 Pro vs Steam Machine]]></media:description>                                                            <media:text><![CDATA[PS5 Pro vs Steam Machine]]></media:text>
                                <media:title type="plain"><![CDATA[PS5 Pro vs Steam Machine]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/aDHDQdFKxRTwaNvpAinvG8-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The <a href="https://www.tomsguide.com/gaming/steam-machine-review">Steam Machine</a> promised to bring the PC experience to the living room at an affordable cost. While it has certainly lived up to the former, it has absolutely not lived up to the latter. Sure, it can play the <a href="https://www.tomsguide.com/best-picks/best-steam-games">best Steam games</a>, but it’s going to cost you at least $1,049 to buy Valve’s system — or it <em>will</em> cost that much when you’re next up on the waitlist.</p><p>In fairness to the Steam Machine, the price of all gaming hardware has increased dramatically thanks to the <a href="https://www.tomsguide.com/computing/ram-price-crisis-2026-everything-you-need-to-know">RAM crisis</a>. Case in point: the <a href="https://www.tomsguide.com/gaming/playstation/ps5-pro-review">PS5 Pro</a>, which was already pricey at its original $699 price, now costs $899! No matter what, gamers are paying a premium. Given that, you want to make the best choice before plunking down your hard-earned cash on your next system.</p><p>To that end, I want to compare the Steam Machine to the PS5 Pro. I’ll take a look at what each offers in terms of performance, price, and gaming libraries to see which system is the best one for you. Should you get the Steam Machine or the PS5 Pro? Let’s find out!</p><div class="product"><a data-dimension112="4627ba46-8b2f-40bd-ad37-802f5e81e710" data-action="Deal Block" data-label="The PS5 Pro is now more expensive at $899, but it's still the most powerful PlayStation console ever made. Building on the base PS5, it packs upgraded internal components, a 2TB SSD, and a very slight visual redesign. It also comes with a standard DualSense controller." data-dimension48="The PS5 Pro is now more expensive at $899, but it's still the most powerful PlayStation console ever made. Building on the base PS5, it packs upgraded internal components, a 2TB SSD, and a very slight visual redesign. It also comes with a standard DualSense controller." data-dimension25="$899" href="https://www.amazon.com/PlayStation-5-Pro-Console/dp/B0DGY63Z2H" 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="o53gSodihxPkSztuP2Lt4Z" name="PS5_Pro_Quick_List" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/o53gSodihxPkSztuP2Lt4Z.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The PS5 Pro is now more expensive at $899, but it's still the most powerful PlayStation console ever made. Building on the base PS5, it packs upgraded internal components, a 2TB SSD, and a very slight visual redesign. It also comes with a standard DualSense controller.<a class="view-deal button" href="https://www.amazon.com/PlayStation-5-Pro-Console/dp/B0DGY63Z2H" target="_blank" rel="nofollow" data-dimension112="4627ba46-8b2f-40bd-ad37-802f5e81e710" data-action="Deal Block" data-label="The PS5 Pro is now more expensive at $899, but it's still the most powerful PlayStation console ever made. Building on the base PS5, it packs upgraded internal components, a 2TB SSD, and a very slight visual redesign. It also comes with a standard DualSense controller." data-dimension48="The PS5 Pro is now more expensive at $899, but it's still the most powerful PlayStation console ever made. Building on the base PS5, it packs upgraded internal components, a 2TB SSD, and a very slight visual redesign. It also comes with a standard DualSense controller." data-dimension25="$899">View Deal</a></p></div><h2 id="pricing-value">Pricing & value</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="bMX2buAmAL7uK2BwXXj5F" name="PS5 Pro-17" alt="PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/bMX2buAmAL7uK2BwXXj5F.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 be clear, the Steam Machine and PS5 Pro are not inexpensive systems. This is especially true because of the dreaded RAMageddon, which is driving up prices for components like RAM and SSDs. With that established, here’s how much you’re paying for each system.</p><p>The PS5 Pro now costs $899, up from its original $699 starting price two years ago. It offers strong raw graphics performance and ample storage for the price. You get the system and a single controller in the box.</p><p>Then there’s the Steam Machine, which starts at $1,049 for the 512GB model and jumps to $1,349 for the 2TB model. Neither of these comes with a controller, so you’ll have to pay $1,128 and $1,428 (respectively) for models bundled with the <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review">Steam Controller</a>.</p><p>Again, neither of these systems is cheap, but if you want to make less of a dent on your wallet, then the PS5 Pro is the way to go.</p><h2 id="performance-specs">Performance & specs</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="MAg7YrXBVV5qCA9x3tbdpE" name="PS5 Pro-18" alt="PS5 Pro playing Marvel's Spider-Man 2" src="https://cdn.mos.cms.futurecdn.net/MAg7YrXBVV5qCA9x3tbdpE.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 / Tom's Guide)</span></figcaption></figure><p>The PS5 Pro runs on a custom AMD Zen 2 CPU and a powerful custom RDNA GPU capable of 16.7 Teraflops with Sony’s PSSR machine-learning upscaler. The system also has 16GB of unified GDDR6 memory and a 2TB SSD.</p><p>Based on raw, unoptimized rendering, the PS5 Pro has power comparable to an AMD Radeon RX 7700 XT or an Nvidia GeForce RTX 4060 Ti. However, when you factor in console-level optimization and PSSR, Sony’s console can deliver performance comparable to an RTX 5060 Ti or an RX 9060 XT.</p><p>Select PS5 Pro-enhanced games offer 60 fps at the same resolution as the base PS5’s Fidelity mode (which limits gameplay to 30 fps). For instance, The <a href="https://www.tomsguide.com/reviews/the-last-of-us-part-ii-remastered">Last of Us Part II Remastered</a> uses the Pro’s improved processing power to deliver an upscaled 4K image while maintaining a rock-solid frame rate. The PS5 Pro also delivers ray tracing, which adds lifelike reflections to certain games. Ray tracing usually comes at the cost of performance, but it sure makes games look beautiful.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="peBzSSYAbw8dX6vM5LcvAA" name="Valve Steam Machine" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/peBzSSYAbw8dX6vM5LcvAA.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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 for the Steam Machine, it’s running on a semi-custom AMD Zen 4 CPU and RDNA 3 architecture. It comes with 16GB of DDR5 RAM, 8GB of dedicated GDDR6 VRAM, and a 2TB NVMe SSD.</p><p>In terms of power, the Steam Machine’s GPU is roughly equivalent to a desktop AMD Radeon RX 7600 or an Nvidia GeForce RTX 3060 in raw raster performance. Since it uses a lower-power, mobile-tier chip similar to an RX 7600M, it’s fair to say it sits between an Xbox Series S and a PS5 in overall gaming performance.</p><p>To be clear, the Steam Machine is not a 4K gaming machine. It’s basically a 1080p system with some QHD on the side. While it does well with less demanding games, things fall apart the instant you try to play anything AAA. You can make 4K work at FPS, but you’ll lose detail since you’ll have to rely on FSR. Also, forget about ray tracing at 4K, as that is this system’s kryptonite.</p><div ><table><caption>Steam Machine performance</caption><thead><tr><th class="firstcol " ><p><strong>Game</strong></p></th><th  ><p>Steam Machine (custom AMD GPU)</p></th><th  ><p>RTX 5060 PC</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Black Myth: Wukong (1080p Medium)</strong></p></td><td  ><p>36 FPS</p></td><td  ><p>82 FPS</p></td></tr><tr><td class="firstcol " ><p><strong>Black Myth: Wukong (4K Medium)</strong></p></td><td  ><p>19 FPS</p></td><td  ><p>30 FPS</p></td></tr><tr><td class="firstcol " ><p><strong>Cyberpunk 2077 (1080p RT: Ultra)</strong></p></td><td  ><p>17.7 FPS</p></td><td  ><p>45.42 FPS</p></td></tr><tr><td class="firstcol " ><p><strong>Forza Horizon 6 (1080p Ultra)</strong></p></td><td  ><p>50 FPS</p></td><td  ><p>101 FPS</p></td></tr><tr><td class="firstcol " ><p><strong>Red Dead Redemption 2 (4K Medium)</strong></p></td><td  ><p>22 FPS</p></td><td  ><p>31 FPS</p></td></tr></tbody></table></div><p>With FSR and settings tweaks, you can make 4K work at 60 FPS, but by that point, you lose the detail. <a href="https://www.tomsguide.com/reviews/cyberpunk-2077-phantom-liberty">Cyberpunk 2077</a> is the ultimate proof that ray tracing is this machine’s kryptonite, as it simply did not run in 4K.  </p><p>When it comes to specs and performance, the PS5 Pro easily bests the Steam Machine. So if your primary concern is performance, Sony’s console is the one to get between these two.</p><h2 id="gaming-experience">Gaming experience</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="DJwAH5Qdj6ginZR2kxbKn7" name="PS5 Pro-22.jpg" alt="PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/DJwAH5Qdj6ginZR2kxbKn7.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>Here is where performance becomes less important. After all, what’s the point of owning a powerful system if it doesn’t have the games and experiences you’re looking for? Yes, both systems can play many of the same titles, but there’s more to it than that.</p><p>Naturally, the PS5 Pro has all the latest PlayStation exclusives at launch. Yes, there are many PlayStation games on PC, but they’re mostly older titles. If recent reports are true, Sony plans to stop launching its single-player exclusives on PC. If that pans out, you’ll need a Sony system (either the PS5 Pro or PS5) to play Sony’s games.</p><p>Beyond exclusives, the PS5 Pro (and PS5) is a plug-and-play system that doesn’t require tweaking settings, updating drivers, or troubleshooting, unlike the more hands-on PC gaming experience. That’s not to say you’ll always get a smooth experience, as games can crash or updates might cause problems. But for the most part, the PS5 Pro delivers a seamless console experience because, well… it’s a console!</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="2tbgG6dNDEgWdjJjA6eeSP" name="Valve Steam Machine" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/2tbgG6dNDEgWdjJjA6eeSP.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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 the Steam Machine ostensibly offers a console-like experience with its intuitive UI, it’s still a PC at its core. For instance, the Linux-based SteamOS lets you boot into desktop mode, connect DisplayPort monitors, and use third-party launchers and emulators. If you wanted to, you could use the Steam Machine as your primary home computer. None of these features are available on the PS5 Pro.</p><p>The Steam Machine also lets you play the thousands of games available on Steam. This includes modern AAA blockbusters, indie titles, strategy games, older classics, and early access games that you won’t find on any console. If you’ve accumulated a giant Steam library over the years (I know you have!), the Steam Machine is a convenient way to enjoy it in your living room.</p><p>For a no-frills console experience, the PS5 Pro is the winner here. However, if you want an open platform for gaming or other projects, the Steam Machine offers more freedom.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-ey4oAX"></div>                            </div>                            <script src="https://kwizly.com/embed/ey4oAX.js" async></script><h2 id="bottom-line-4">Bottom line</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="raSPyZf7LKggAeX3Hf9HgP" name="Valve Steam Machine" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/raSPyZf7LKggAeX3Hf9HgP.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>Inflated costs aside, both the PS5 Pro and Steam Machine deliver on their respective promises. The PS5 Pro is a powerful, plug-and-play console, while the Steam Machine gives you the freedom of a PC in your living room.</p><p>You can’t go wrong with either system, but for the average gamer who wants a higher-end experience, the PS5 Pro is the better option. For $899, it has a wide selection of first- and third-party games that can run at 4K resolution and up to 120 fps. And since it’s a console first, you don’t have to mess around with settings.</p><p>Though the Steam Machine is a wonderful little device, its $1,049 asking price is too high for what is effectively a 1080p machine. Those already heavily invested in Steam will want to pick this up (if they can justify the price), but for everyone else, get a PS5 Pro. Not only is it the better overall option, but you also don’t have to join a waitlist to get one right now.</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/gaming/playstation/customers-need-assurances-their-games-wont-be-taken-from-them-after-purchase-stop-killing-games-on-playstations-decision-to-kill-physical-discs">Stop Killing Games Founder on PlayStation's decision to kill physical discs</a></li><li><a href="https://www.tomsguide.com/gaming/playstation/playstation-is-officially-killing-physical-discs-heres-when-they-disappear-and-what-that-means-for-you">PlayStation is officially killing physical discs</a></li><li><a href="https://www.tomsguide.com/gaming/playstation/ps6-price-could-be-in-the-same-stratosphere-as-the-steam-machine-based-on-new-leak">PS6 price could be in the same stratosphere as the Steam Machine</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested Control Resonant on an RTX 5090 — and I'm now preparing for a new benchmark for PC gaming ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/pc-gaming/i-tested-control-resonant-on-an-rtx-5090-and-im-now-preparing-for-a-new-benchmark-for-pc-gaming</link>
                                                                            <description>
                            <![CDATA[ I played three hours of Remedy Entertainment's upcoming Control Resonant on an RTX 5090 gaming PC, and its reality-bending action is looking to take full advantage of Nvidia's latest graphics cards. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">MYWRrJijVuMZQ6774gA35V</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/uzDcZoSrtzEyFsr74wSvDi-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 27 Jun 2026 09:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[GPUs]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                                    <dc:creator><![CDATA[ Darragh Murphy ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/5QiaTSWf9FcVB7STxcdo4M.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Darragh is Tom’s Guide’s Computing Editor and is fascinated by all things bizarre in tech. This usually leads to assorted coverage varying from washing machines designed for earbuds to the wild world of laptops. Whether it&#039;s connecting Scar from The Lion King to two-factor authentication or turning his love for laptops into a fabricated rap battle from 8 Mile, he believes there’s always a quirky spin to be made.&lt;br&gt;&lt;br&gt;Darragh has previously been an Editor for Laptop Mag and a News Editor for Time Out Dubai, where he also headed the gaming and tech section. His work can be seen in Mashable, Android Police, Shortlist Dubai, Proton, theBit.nz, ReviewsFire and more. &lt;br&gt;&lt;br&gt;While laptops are his bread and butter, he’s also reviewed smartphones, monitors, speakers, docking stations and VPNs. He’s covered IFA, MWC Barcelona, the Consumer Electronics Show (&lt;a href=&quot;https://www.tomsguide.com/uk/tag/ces&quot; target=&quot;_blank&quot;&gt;CES&lt;/a&gt;) and more.&lt;br&gt;&lt;br&gt;When he&#039;s not checking out the latest devices and all things computing, he can be found going for dreaded long runs, watching terrible shark movies, and trying to find time to game.&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/uzDcZoSrtzEyFsr74wSvDi-1280-80.jpg">
                                                            <media:credit><![CDATA[Future / Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Control Resonant on display next to PC]]></media:description>                                                            <media:text><![CDATA[Control Resonant on display next to PC]]></media:text>
                                <media:title type="plain"><![CDATA[Control Resonant on display next to PC]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/uzDcZoSrtzEyFsr74wSvDi-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Whenever I get the chance to test out the <a href="https://www.tomsguide.com/best-picks/best-gaming-laptops">best gaming laptops</a>, my first port of call is to actually <em>game </em>as a form of benchmarking. For years, <a href="https://www.tomsguide.com/reviews/control">Control</a> has long been one of my go-to titles, but that will quickly change once Control Resonant arrives on PC.</p><p>Horrifying, bleak and messy — not exactly "positive" words to use for developer Remedy Entertainment's upcoming action-heavy sequel, but I mean these in the most endearing way possible from what I saw when playing Control Resonant on an <a href="https://www.tomsguide.com/gaming/pc-gaming/the-rtx-5090-is-the-best-graphics-card-ive-ever-owned-but-theres-a-catch-for-living-room-pc-gamers">RTX 5090</a> gaming PC during a three-hour hands-on session. </p><p>Fighting off hordes of The Hiss (the main threat in the game) is thrillingly horrifying with their grotesquely detailed forms, the bleak atmosphere of a warped Manhattan is enthralling and the mind-bending, twisted environments you get to explore are satisfyingly messy. If you thought The Oldest House in Control was a trip, just wait for what Control Resonant has to offer. </p><p>With Nvidia's RTX 50-series GPUs lending their power, though, with <a href="https://www.tomsguide.com/computing/gpus/what-is-nvidia-dlss-explaining-the-ai-tech-transforming-pc-gaming-and-why-its-getting-controversial">DLSS</a> turned on and ray tracing set to high, Remedy's follow-up had me immersed. From the expert use of lighting in a chaotic world to the smooth, fast-paced combat, I already see Control Resonant being an all-new PC gaming benchmark. </p><p>You can check our <a href="https://www.tomsguide.com/gaming/i-played-control-resonant-for-2-hours-and-trust-me-remedy-cooked-with-this-sequel">Control Resonant preview</a> for how the game plays and our <a href="https://www.tomsguide.com/gaming/control-resonant-interview">interview with Remedy Entertainment's Creative Director</a> for more on what is now one of my most highly anticipated games of the year. But for how it handles on PC, let's dive in. </p><h2 id="control-resonant-pc-requirements">Control Resonant PC requirements</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="2RJAaTxpN9a5XEwiDx7H3i" name="Control Resonant on RTX PC" alt="Control Resonant on display next to PC" src="https://cdn.mos.cms.futurecdn.net/2RJAaTxpN9a5XEwiDx7H3i.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 / Tom's Guide)</span></figcaption></figure><p>While I played Control Resonant on a monster of a gaming PC (the RTX 5090 says it all), I was assured by the team at Remedy Entertainment that PCs that don't reach those heights, like many of the more affordable <a href="https://www.tomsguide.com/us/best-gaming-pc,review-2219.html">best gaming PCs</a>, will be able to play the game without trouble. </p><p>Take a look at the system requirements for Control Resonant below, along with the PC specs I played on. Spoiler alert: you <em>will </em>need a lot of storage.</p><div ><table><caption>Control Resonant System Requirements</caption><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Minimum specs</strong></p></td><td  ><p><strong>Recommended specs</strong></p></td><td  ><p><strong>Tested specs</strong></p></td></tr><tr><td class="firstcol " ><p><strong>CPU</strong></p></td><td  ><p>Intel i5-8500 or AMD equivalent</p></td><td  ><p>Ryzen 7 3700X or Intel equivalent</p></td><td  ><p>Intel Core i9-14900K</p></td></tr><tr><td class="firstcol " ><p><strong>GPU</strong></p></td><td  ><p>Nvidia GeForce GTX 1070 / AMD Radeon RX 5600 XT (6GB)</p></td><td  ><p>Nvidia GeForce RTX 3070 / AMD Radeon RX 6700 XT (8GB)</p></td><td  ><p>Nvidia GeForce RTX 5090</p></td></tr><tr><td class="firstcol " ><p><strong>RAM</strong></p></td><td  ><p>16GB</p></td><td  ><p>16GB</p></td><td  ><p>128GB</p></td></tr><tr><td class="firstcol " ><p><strong>Storage</strong></p></td><td  ><p>100GB</p></td><td  ><p>100GB</p></td><td  ><p>100GB</p></td></tr></tbody></table></div><h2 id="brimming-with-power">Brimming with power</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="3gLe9x7DPQZW5AfrDGXr6i" name="Control Resonant on RTX PC" alt="Control Resonant on display next to PC" src="https://cdn.mos.cms.futurecdn.net/3gLe9x7DPQZW5AfrDGXr6i.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 / Tom's Guide)</span></figcaption></figure><p>First, a few preliminary points. As with most previews, this isn't the final version of Control Resonant. Not only is lighting and framerate still being worked on, but also audio mixing, hit impacts and more. This is still very much in beta, but honestly, from the time I had playing through the opening act and a mid-game area called The Sinkhole (it's a masterpiece), it's already looking to be in good shape. </p><p>I can imagine a lot of that has to do with the RTX 5090 working behind the scenes. With DLSS upscaling (no frame generation) and DLSS Ray Reconstruction (for sharper reflections and accurate lighting), zipping and levitating through a disfigured Manhattan as the all-powerful Dylan Faden (our up-close-and-personal protagonist) was a treat for the eyes. </p><p>And that was with graphics and ray tracing presets set to high, only made better by the 4K (3840 x 2160) resolution I was playing on. From the many twisted forms of The Hiss shown in terrifying detail to the deep contrast of red hues streaking across the screen, along with the subtle yet clear reflections in windows of buildings turned upside down, it's all beautifully crafted — and I often found myself taking it all in. </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-W5xZ0e"></div>                            </div>                            <script src="https://kwizly.com/embed/W5xZ0e.js" async></script><p>After leaving The Oldest House after the opening act, I was impressed by the visual distortion effect beaming off cars, with The Hiss floating in midair endlessly in the background. That, along with blaring, dangerous red lighting reflecting off the pavement. For those stationary moments, it all hits right.</p><p>In combat, with Remedy changing pace from a third-person shooter to pure melee action, things can get chaotic, but unsurprisingly, this rig could handle it all. As in, the copious amounts of rubble Dylan hurls at enemies while quickly dashing to slash through them using his Aberrant weapon (I chose the sword-like Flurry form as my weapon of choice), while the almost faded rainbow oil mist blasts off foes as he hits them. </p><p>It's smooth, clean action, which is what you'd want in a fast-moving action game. It's the little nuances, like the aftereffect of dashing being so crystal clear, like a sleek afterimage of static video, that make it work. </p><p>Now, I wasn't able to see frame rates or tinker with different settings, as it appeared the game was locked at a rock-solid 60 frames per second (FPS) for beta purposes. But even with the mass of Hiss shooting red beams from every direction during The Sinkhole section, along with the gravity-bending environment Dylan can shift through, it's clear Control Resonant will be taking full advantage of what Nvidia's GPUs have to offer. </p><p>And I'm here for it. </p><h2 id="reaching-a-new-pc-benchmark">Reaching a new PC benchmark </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="CnSPTRGg2bjPzspUo58MFi" name="Control Resonant on RTX PC" alt="Control Resonant on display next to PC" src="https://cdn.mos.cms.futurecdn.net/CnSPTRGg2bjPzspUo58MFi.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 / Tom's Guide)</span></figcaption></figure><p>While Remedy is still polishing off Control Resonant, especially the PC version, we can expect plenty of RTX features to be fully on show (just like path tracing in <a href="https://www.tomsguide.com/gaming/pc-gaming/resident-evil-requiem-with-path-tracing-is-horrifying-and-i-mean-that-as-a-compliment-to-nvidia-and-dlss-4">Resident Evil Requiem</a>). That includes <a href="https://www.tomsguide.com/computing/gpus/i-tested-dlss-4-5-dynamic-multi-frame-generation-its-not-just-ai-trickery-its-nvidias-cheat-code-for-4k-240hz-and-a-true-console-killer">DLSS 4.5</a> and its dynamic multi-frame gen tech (expect frame rates to hit over 200 FPS), DLSS Super Resolution and path tracing for photorealistic lighting, no less. </p><p>That's exciting, considering just how well it already looks, and there's still plenty of time for the team at Remedy to cook. During my session, I had a chat with Lead Gameplay Designer Sergey Mohov, and he explained how there's now more to play around with. </p><p>"We weren't limited by hardware in terms of gameplay. It's very helpful that computers and consoles these days can actually run games like this, and we're able to put all of these enemies on screen, all of these effects and make it look nice while feeling very satisfying to kill them all. </p><p>"The hardest thing was actually making the world, making it bigger and increasing draw distances. But we've invested in improving our in-house engine (Northlight Engine) to handle these things. But, you know, we've done it."</p><p>I believe Mohov is spot on, taking the improvements we saw in <a href="https://www.tomsguide.com/reviews/alan-wake-2">Alan Wake 2</a> and pushing it even further. Of course, just like how <a href="https://www.tiktok.com/@tomsguide/video/7635330240482479391">Control is now available on iOS</a>, there's the aim for Resonant to be flexible enough to be played on, well, anything that isn't just an RTX 5090 while still delivering great visuals and performance. </p><p>"We have a lot of people who are really excited about putting all the latest tech in. Nvidia is helping out, and we'll have all the latest Nvidia stuff in [Control Resonant]. So that's going to be pretty cool. But if somebody can run Control on, like, a potato or a fridge, I'll be pretty happy."</p><p>Control Resonant is set to launch on September 24, available on PS5, Xbox Series X/S, macOS and cloud streaming via Nvidia GeForce Now. But just from my brief experience, it will be a PC purchase for me. </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/gaming/6-best-video-games-of-2026-so-far-on-ps5-nintendo-switch-2-pc-and-xbox">The 6 best video games we've played in 2026 (so far) on PS5, Switch 2, PC and Xbox</a></li><li><a href="https://www.tomsguide.com/gaming/nintendo/star-fox-review">I just finished Star Fox on Switch 2 — and it’s better than the game I imagined I was playing as a kid</a></li><li><a href="https://www.tomsguide.com/gaming/5-recently-announced-video-games-im-most-excited-about-including-a-sequel-ive-been-waiting-13-long-years-for">5 recently announced video games I’m most excited about, including a sequel I’ve been waiting 13 long years for</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Level up with these 15 Prime Day PC gaming deals — save up to $600 on Acer, Alienware, and more ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/entertainment/level-up-with-these-15-prime-day-pc-gaming-deals-save-up-to-usd600-on-acer-alienware-and-more</link>
                                                                            <description>
                            <![CDATA[ Make the most of the final day of the Prime Day sales with these great deals on new gaming PCs and accessories. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Ke7t39DgGyMFsQr8ikbqyJ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/pfbqSpQnMKMm75GQmmdeCe-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 26 Jun 2026 14:02:13 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Entertainment]]></category>
                                                                                                                    <dc:creator><![CDATA[ Will Salmon ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/HpRWP7Mh9ErgRGoTvZBbBJ.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Will Salmon is Tom&#039;s Guide&#039;s Collections Editor, curating advice on the best products to spend your money on. Will has been writing about tech and entertainment for almost 20 years, including stints as GamesRadar+&#039;s Streaming Editor, editing comics website Newsarama, and writing for lots and lots of magazines.&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/pfbqSpQnMKMm75GQmmdeCe-1280-80.jpg">
                                                            <media:credit><![CDATA[Logitech, Asus, Alienware, Acer / Edited by Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A selection of gaming peripherals on a colorful background.]]></media:description>                                                            <media:text><![CDATA[A selection of gaming peripherals on a colorful background.]]></media:text>
                                <media:title type="plain"><![CDATA[A selection of gaming peripherals on a colorful background.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/pfbqSpQnMKMm75GQmmdeCe-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>It's the final day of Amazon's sales event, but there's still time to pick up some <a href="https://www.tomsguide.com/live/news/last-minute-prime-day-deals-picked-by-editors-2026">Prime Day deals</a>. There are big savings to be had across everything from <a href="https://www.tomsguide.com/home/home-appliances/i-found-15-prime-day-tool-deals-up-to-47-percent-off-save-big-on-dewalt-bosch-and-more">DIY tools</a> to <a href="https://www.tomsguide.com/wellness/sleep/sleep-easy-with-these-12-mattress-prime-day-deals-prices-starting-at-usd70">mattresses</a>, <a href="https://www.tomsguide.com/home/get-all-set-for-summer-party-season-save-up-to-20-percent-on-my-top-choice-of-outdoor-decor">outdoor decorations</a> to <a href="prime-day-3d-printer-deals-worth-buying-save-up-to-usd430">3D printers</a>. If you're a gamer then it's a particularly good time to pick up a peripheral or two that will help you take your gaming to the next level.</p><p>There are super-responsive gaming mice, tactile keyboards, gorgeous monitors and fearsomely fast gaming PCs all on offer right now, with many coming from trusted brands like Alienware, Acer, Logitech, and more.</p><p>As it's the last day of the sale you'll need to move fast if you want to take advantage of these savings. There's a lot to choose from across the site, but here are our 15 favorites.</p>        <div class="featured_product_block featured_block_hero" data-id="d1bf2f0e-1fde-45e9-ad91-5104181d830a">            <a href="https://www.amazon.com/dp/B07MRMHML9?" data-model-name="Logitech G432 Wired Gaming Headset" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/4iHnjp3w4kYR5fSuxhYbK6.jpg" alt="Logitech G432 Wired Gaming Headset, 7.1 Surround Sound, Dts Headphone:x 2.0, 50 Mm Audio Drivers, Usb and 3.5 Mm Jack, Flip-To-Mute Mic, Pc, Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Logitech G</div>                                        <div class="featured__title">Logitech G432 Wired Gaming Headset</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="dc1ab138-891c-4300-a3a0-56865d8f98fe">            <a href="https://www.amazon.com/Logitech-Lightspeed-Lightsync-Compatible-Lightweight/dp/B07NSSPV9S/" data-model-name="Logitech G703 Lightspeed Wireless Gaming Mouse" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/ZRfKYdDNZgfsz9guVaUBuf.jpg" alt="Logitech G703 Lightspeed Wireless Gaming Mouse W/hero 25k Sensor, Powerplay Compatible, Lightsync Rgb, Lightweight 95g+10g Optional, 100-25, 600 Dpi, Rubber Side Grips - Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Logitech G</div>                                        <div class="featured__title">Logitech G703 Lightspeed Wireless Gaming Mouse</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="6f1df268-2335-4899-85e9-9e63d5c569ae">            <a href="https://www.amazon.com/Edifier-Computer-Bluetooth-Multimedia-subwoofer/dp/B00UAFSN5O/" data-model-name="Edifier G2000 Speakers" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/hxfVjAEhy8CZQKQB8Q3kER.jpg" alt="Edifier G2000 32w Pc Gaming Computer Speakers for Laptop Mac Desktop Computer Woofer Speakers Bluetooth Usb 3.5mm Aux Inputs Rgb Lights Multimedia Speakers Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Edifier</div>                                        <div class="featured__title">Edifier G2000 Speakers</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="5a30fedc-feb7-4eb3-9ae4-523959ce919e">            <a href="https://www.amazon.com/dp/B01LY6Z2M6" data-model-name="Logitech Creators Blue Yeti USB Microphone" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/NcJrmThNoaA6DjKXFuwQd6.jpg" alt="Logitech Creators Blue Yeti Usb Microphone for Pc, Mac, Gaming, Streaming, Podcasting, Studio and Computer Condenser Mic With Blue Vo!ce Effects, 4 Pickup Patterns, Plug and Play - Midnight Blue"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Logitech G</div>                                        <div class="featured__title">Logitech Creators Blue Yeti USB Microphone</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="a95a7b70-694e-4e86-af46-0daf87cb537e">            <a href="https://www.amazon.com/dp/B0F7XMH5LW" data-model-name="ASUS ROG Harpe II Ace Wireless Gaming Mouse" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/TcjpuqekrTKY8hc7erzyUg.jpg" alt="An ASUS ROG Harpe II Ace Wireless Esports Gaming Mouse."></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Asus</div>                                        <div class="featured__title">ASUS ROG Harpe II Ace Wireless Gaming Mouse</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="40af0bfd-b29f-4c30-a131-cbd8e988a474">            <a href="https://www.amazon.com/Elgato-Production-Controller-Streaming-Customizable/dp/B0BXHL5DMD/" data-model-name="Elgato Stream Deck" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/ieHc6h8EZMDPKQB5ZoaexA.jpg" alt="Elgato Stream Deck + White, Audio Mixer, Production Console and Studio Controller for Content Creators, Streaming, Gaming, With Customizable Touch Strip Dials and Lcd Keys, Works With Mac and Pc"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Elgato</div>                                        <div class="featured__title">Elgato Stream Deck</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="b66f13e7-da2e-47ac-b174-73aa392da9bf">            <a href="https://www.amazon.com/dp/B0CCX2DMXV?th=1" data-model-name="Razer Kitsune All-Button Arcade Controller" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/4quQXnZPeGx47KAzNwfD3A.jpg" alt="Razer Kitsune All-Button Arcade Controller: for Ps5 / Playstation 5 & Pc - Low-Profile Optical Switches - Slim Form Factor - Removable Top Plate - Chroma Rgb Lighting - Usb Type C - Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Razer</div>                                        <div class="featured__title">Razer Kitsune All-Button Arcade Controller</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="1e6f8125-f375-42e6-b417-d81e3369cf84">            <a href="https://www.amazon.com/dp/B0FC9DTDJ3" data-model-name="Razer Wolverine V3 Pro Wireless Gaming Controller" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/3wQfhBuBri7fcT5nhfvCZT.jpg" alt="Razer Wolverine V3 Pro 8k Pc Wireless Gaming Controller: 8000 Hz Polling Rate - Tmr Thumbsticks With Swappable Caps - Up to 36 Hr Battery - 6 Remappable Buttons - Fast Triggers - Carrying Case - Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Razer</div>                                        <div class="featured__title">Razer Wolverine V3 Pro Wireless Gaming Controller</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="515fb011-aad1-437f-8a7a-231cd1884325">            <a href="https://www.amazon.com/dp/B0GJXBMY43?th=1" data-model-name="Asus Rog Azoth 96 Wireless Gaming Keyboard" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/seSCks4RFNM8QEe5sx7ryB.jpg" alt="Asus Rog Azoth 96 He Wireless Hall Effect Gaming Keyboard – 96% Full-Size, Tri-Mode, Hot Swappable Magnetic Switch, Rapid Trigger, Speed Tap, 8k Hz Polling, Color Oled Screen, Pbt Keycaps – Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>ASUS</div>                                        <div class="featured__title">Asus Rog Azoth 96 Wireless Gaming Keyboard</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="90aeb103-6d50-4988-bb05-9b95895761c3">            <a href="https://www.amazon.com/Alienware-Curved-Gaming-Monitor-AdaptiveSync/dp/B0DZL719V1/" data-model-name="Alienware 34-Inch Curved Gaming Monitor" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/QQuQkcLts6XZUKSsFQHaoA.jpg" alt="Alienware 34 Curved Gaming Monitor – Aw3425dwm - 34-Inch Wqhd 180hz 1ms Display, 1500r, Amd Freesync Premium, Vesa Adaptivesync."></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Alienware</div>                                        <div class="featured__title">Alienware 34-Inch Curved Gaming Monitor</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="d43f84ee-1066-444c-8ceb-22d1951a93ef">            <a href="https://www.amazon.com/dp/B0BRXJDQC1" data-model-name="Logitech G Astro A50 X Wireless Gaming Headset" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/gxvDodwZ6qQP7Ma3Xe6n2A.jpg" alt="Logitech G Astro A50 X Multi-Platform Wireless Gaming Headset + Base Station for Ps5/xbox/pc: Playsync Video & Audio Switcher, Hdmi 2.1 4k 120hz Vrr,"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Logitech G</div>                                        <div class="featured__title">Logitech G Astro A50 X Wireless Gaming Headset</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="029b8373-c4a7-4fcd-b340-a5f5684d0ba7">            <a href="https://www.amazon.com/Lenovo-Computer-Display-Bluetooth-Windows/dp/B0GSQC3QHS/" data-model-name="Lenovo 15-Inch Gaming Laptop" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/HKWf6QutgiJ4yGrzute7rC.jpg" alt="Lenovo 15" Gaming Laptop Computer, Amd Ryzen 5 7535hs 6-Core, 8gb Ddr5 Ram, 256gb Pcie Ssd, Fhd+ Display, Wifi 6, Bluetooth 5.3, Webcam, Luna Grey, Windows 11 Home"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Lenovo</div>                                        <div class="featured__title">Lenovo 15-Inch Gaming Laptop</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="e8b11548-f806-442b-81b7-25267abe8b50">            <a href="https://www.amazon.com/samsung-oled-displayhdr-freesync-adjustable-ls49cg932snxza/dp/B0CDQMQQS2/" data-model-name="Samsung 49-Inch Curved Gaming Monitor" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/Lj5cpfzRaunyXHNaufGszE.jpg" alt="Samsung 49" Odyssey G93sc Series Curved Gaming Monitor, Qd-Oled, 240hz, 0.03ms, Dqhd, G-Sync Compatible, Freesync Premium Pro, Adjustable Stand"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Samsung</div>                                        <div class="featured__title">Samsung 49-Inch Curved Gaming Monitor</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="1024952d-0a26-407c-b7fd-aff337d64f16">            <a href="https://www.amazon.com/acer-Predator-Processor-GeForce-PHN16-73-92B8/dp/B0FN15LKGD/" data-model-name="Acer Predator Helios Neo 16 AI Gaming Laptop" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/aGnDvBgsdjgNghqBoYNsfk.jpg" alt="Acer Predator Helios Neo 16 AI Gaming Laptop"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Acer</div>                                        <div class="featured__title">Acer Predator Helios Neo 16 AI Gaming Laptop</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="eb0215da-4456-4b2b-948f-be52b25a837b">            <a href="https://www.amazon.com/Alienware-Area-51-AA18250-18-inch-Display-9-275HX/dp/B0FFPTXBC2/" data-model-name="Alienware 18 Area-51 Gaming Laptop" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/3FP4P24c3mbPM8Jxrbmq3K.jpg" alt="Alienware 18 Area-51 Gaming Laptop Aa18250-18-Inch Qhd+ 300hz 3ms Display, Intel Core Ultra 9-275hx, 32gb Ddr5 Ram, 1tb Ssd, Nvidia Geforce Rtx 5070, Windows 11 Home, Onsite Service - Liquid Teal"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Alienware</div>                                        <div class="featured__title">Alienware 18 Area-51 Gaming Laptop</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div><h2 id="gaming">GAMING</h2><h3 class="article-body__section" id="section-we-re-tracking-all-the-best-prime-day-gaming-deals"><span>We're tracking all the best Prime Day gaming deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=Gaming&min_discount_ratio=0.95&offer_type=all&rows=4&widget_title=Top+Deals+Handpicked+by+Our+Editors&widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&show_countdown=true&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 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%;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      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 {      display: flex;      gap: 12px;      justify-content: center;      flex-wrap: wrap;    }    .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;    }        .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 {      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;    }        .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);      display: -webkit-box;      -webkit-line-clamp: 2;      -webkit-box-orient: vertical;      overflow: hidden;    }    .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;    }    .tg-df-container .tg-df-card-cta.tg-df-cta-savings-squad {      background-color: #3c8d0d;    }    .tg-df-card:hover .tg-df-card-cta.tg-df-cta-savings-squad,    .tg-df-card-cta.tg-df-cta-savings-squad:hover {      background-color: #2b6509;    }    /*       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: 0;      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: 0 16px;      }            .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-filters {        width: calc(100% + 32px);        margin: 0 -16px;        padding: 0 16px 4px 16px;        display: flex;        justify-content: flex-start;        gap: 8px;        flex-wrap: nowrap;        overflow-x: auto;        -webkit-overflow-scrolling: touch;        scrollbar-width: none;      }      .tg-df-filters::after {        content: "";        display: block;        flex: 0 0 8px;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }            .tg-df-sort-wrapper {        flex: 0 0 max(42%, 130px);        min-width: 0;      }      .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;      }            .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;        -webkit-line-clamp: 3;      }      /* 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;        -webkit-line-clamp: 3;        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;    }    .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: 16px;      text-align: center;      width: 100%;      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-right {      position: absolute;      right: 8px;      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-right:hover {      background-color: #f8fafc;      border-color: #cbd5e1;    }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right {      right: 0;      background-color: rgba(255, 255, 255, 0.4);      border: none;      box-shadow: none;      backdrop-filter: blur(4px);      -webkit-backdrop-filter: blur(4px);    }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);      border: none;    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-carousel-roundels::after {      content: "";      flex: 0 0 32px;    }    .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;      transition: font-weight 0.2s;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-label {      font-weight: 700;    }    .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;      display: inline-flex;      align-items: center;      justify-content: center;      min-height: 36px;      box-sizing: border-box;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .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::after {      content: "";      flex: 0 0 32px;    }    .tg-df-grid-wrapper {      position: relative;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card {      flex: 0 0 auto;      width: 100px;      border-radius: 15px;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      border: 2px solid #1e293b;      background: white;      color: #1e293b;      display: flex;      flex-direction: column;      justify-content: center;      align-items: center;      font-weight: 600;      font-size: 14px;      cursor: pointer;      padding: 16px;      text-align: center;      transition: all 0.2s;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card:hover {      background: #1e293b;      color: white;    }    .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;      -webkit-line-clamp: 2;      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 {      -webkit-line-clamp: 3;    }    .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.45);        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: #5aaf0b; 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: #4a9109; 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; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \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">          \x3Cdiv class="tg-df-carousel-roundels">            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>          \x3C/div>          \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.previousElementSibling.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>        \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>\n        \x3C/div>\n      \x3C/div>\n    \x3C/div>          \x3C!-- Search & Filter Controls --\x3E    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">      \x3Cdiv class="tg-df-top-bar">        \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>                \x3Cdiv class="tg-df-settings-wrapper">          \x3Cbutton type="button" class="tg-df-settings-btn" aria-label="Settings" id="tg-df-settings-toggle">            \x3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20">                \x3Cpath d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.73 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .43-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.49-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>            \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-settings-dropdown-backdrop" id="tg-df-settings-backdrop">\x3C/div>          \x3Cdiv class="tg-df-settings-dropdown" id="tg-df-settings-panel">            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Search Region\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-region-select">                \x3Coption value="auto">🌍 Auto-detect\x3C/option>                \x3Coption value="US">🇺🇸 United States (US)\x3C/option>                \x3Coption value="GB">🇬🇧 United Kingdom (UK)\x3C/option>                \x3Coption value="CA">🇨🇦 Canada (CA)\x3C/option>                \x3Coption value="AU">🇦🇺 Australia (AU)\x3C/option>                \x3Coption value="DE">🇩🇪 Germany (DE)\x3C/option>                \x3Coption value="FR">🇫🇷 France (FR)\x3C/option>                \x3Coption value="IT">🇮🇹 Italy (IT)\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Retailer\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-retailer-select">                \x3Coption value="">All Retailers\x3C/option>                \x3Coption value="Amazon">Amazon\x3C/option>                \x3Coption value="Walmart">Walmart\x3C/option>                \x3Coption value="Best Buy">Best Buy\x3C/option>                \x3Coption value="Target">Target\x3C/option>                \x3Coption value="John Lewis">John Lewis\x3C/option>                \x3Coption value="Currys">Currys\x3C/option>                \x3Coption value="Argos">Argos\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Offer Type\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-offer-type-select">                \x3Coption value="">All Offers\x3C/option>                \x3Coption value="amazon_prime">Amazon Prime\x3C/option>                \x3Coption value="recommended_promo">Recommended Promo\x3C/option>                \x3Coption value="amazon_lightning">Amazon Lightning Deal\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Result Count\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-rows-select">                \x3Coption value="3">3 Items\x3C/option>                \x3Coption value="4">4 Items\x3C/option>                \x3Coption value="6">6 Items\x3C/option>                \x3Coption value="12" selected>12 Items\x3C/option>                \x3Coption value="24">24 Items\x3C/option>                \x3Coption value="48">48 Items\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Deal Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Only show products with active offers or previous prices (was_price)\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-deal-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Editor Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Enable multi-select to copy deals to CMS\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-editor-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">View Mode\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-view-mode-select">                \x3Coption value="auto">Auto Collection\x3C/option>                \x3Coption value="carousel">Carousel\x3C/option>                \x3Coption value="savings_squad">Savings Squad\x3C/option>                \x3Coption value="grid">Grid (Columns)\x3C/option>                \x3Coption value="row">Row (List)\x3C/option>              \x3C/select>            \x3C/div>          \x3C/div>        \x3C/div>      \x3C/div>      \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">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/>          \x3C/svg>          \x3Cselect class="tg-df-sort-select" aria-label="Sort Deals">            \x3Coption value="date_desc">Newest First\x3C/option>            \x3Coption value="best_match">Sort by: Match\x3C/option>            \x3Coption value="price_asc">Price Low to High\x3C/option>            \x3Coption value="price_desc">Price High to Low\x3C/option>            \x3Coption value="discount_desc">Biggest Discount\x3C/option>          \x3C/select>        \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!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>    \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();            if (['carousel', 'carousel-compact', 'auto', 'grid', 'row'].includes(this.getViewMode())) { this.loadCarouselSpreadsheet(); }        }        getViewMode() {          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();          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          if (mode === 'carousel' || mode === 'auto' || mode === 'grid' || mode === 'row') {             if (mode === 'carousel') this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container') && mode === 'carousel') {               this.root.classList.add('is-carousel');             } else if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             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 (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Everything';             if (this.discountFilter && !params.has('min_discount_ratio')) {               this.discountFilter.value = '5';             }          }                    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 (params.has('bg_color')) {            const bg = params.get('bg_color');            if (bg === 'white') {              this.root.style.setProperty('background-color', '#ffffff', 'important');            } else if (bg === 'transparent') {              this.root.style.setProperty('background-color', 'transparent', 'important');            } else if (bg === 'light_blue') {              this.root.style.setProperty('background-color', '#E7F0FF', 'important');            }          } else {             this.root.style.removeProperty('background-color');          }                    if (params.has('view_mode')) {            if (this.viewModeSelect) {              this.viewModeSelect.value = params.get('view_mode');            } else {              this.viewModeOverride = 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') || 'discount_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }                    // 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) {            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 !== 'discount_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 roundels = this.root.querySelectorAll('.tg-df-carousel-cat.original-hardcoded');          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');              }            });          }          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              if (this.getViewMode() === 'savings_squad' && this.autocompleteDropdown && this.airedaleTags && query.length > 0) {                 const matches = this.airedaleTags.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase()).slice(0, 5);                 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');                 }              } else if (this.autocompleteDropdown) {                 this.autocompleteDropdown.classList.remove('active');              }              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  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;                this.activeDealTag = null;                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   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;                   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 });              this.activeDealTag = null;              this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.fetchDeals(query);              }            });          }          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;               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 = this.viewModeSelect.value === 'savings_squad' ? 'date_desc' : 'discount_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')}`                });              }            });          }        }        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';          }        }        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 loadCarouselSpreadsheet() {          try {              const parseCSVRow = (str) => {                  let result = [], cur = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (inQuotes) {                          if (char === '"') {                              if (str[i + 1] === '"') { cur += '"'; i++; }                              else { inQuotes = false; }                          } else { cur += char; }                      } else {                          if (char === '"') { inQuotes = true; }                          else if (char === ',') { result.push(cur); cur = ''; }                          else { cur += char; }                      }                  }                  result.push(cur); return result;              };              const parseCSV = (str) => {                  const rows = []; let curRow = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (char === '"') inQuotes = !inQuotes;                      if ((char === '\n' || char === '\r') && !inQuotes) {                          if (char === '\r' && str[i+1] === '\n') i++;                          if (curRow) rows.push(parseCSVRow(curRow));                          curRow = '';                      } else { curRow += char; }                  }                  if (curRow) rows.push(parseCSVRow(curRow));                  return rows;              };              const preloadedCSV = decodeURIComponent(escape(atob("LCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNQ0KUm91bmRlbCB0ZXh0LEFsbCxUVnMsRm9vdHdlYXIsQXBwYXJlbCxNYXR0cmVzZXMsQXBwbGlhbmNlcyxXZWFyYWJsZSB0ZWNoLEhlYWRwaG9uZXMsU21hcnQgSG9tZSxTcGVha2VycyxMYXB0b3BzLFRhYmxldHMsQ29tcHV0aW5nLFBob25lcyxHYW1pbmcsTGVnbw0KUm91bmRlbCBpbWFnZSxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2FpLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3R2cy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvN2IzYTIyNGIwNzk2M2M2MjdiNmI5MDliZDc4MzM4MzZlMDJmZjgxOS5qcGcud2VicCxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy84NGRhYzVkNDhlZDJkNDQ4NTU5ZWJhNjdhY2U4MzE0Y2M2N2NjZDk0LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvbWF0dHJlc3Nlcy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvNzY4ZTk3Y2ViMDcxODAxZmFlMjA5MTBkMDgyMGIxNmY3NDdhZjkzOS5qcGcud2VicCxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3dlbGxuZXNzLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2hlYWRwaG9uZXMuanBnLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzg5NTM1YmVlYmUyMGRiYmQ0YTM0NmQ2ZDZiZGZlOTFkOGE4ODRhMjEuanBnLndlYnAsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9hdWRpby5qcGcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9sYXB0b3BzLmpwZyxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy8yMzk3NTY0ZWQ3YTVmZjk0N2U5YjZiMzBlNTRmNDc0OTRiODQxZjg5LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvY29tcHV0aW5nLmpwZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3Bob25lcy5wbmcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9nYW1pbmcucG5nLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzRmNmM2MjFjYWMwYmMxYTg1ZDU5M2UzNTk0YmE1YjM0OWVmZmQyOTIuanBnLndlYnANClNlYXJjaCBRdWVyeSxFdmVyeXRoaW5nLFRlbGV2aXNpb25zLCJTbmVha2VycywgcnVubmluZyBzaG9lcywgc2FuZGFscyIsQ2xvdGhpbmcsTWF0dHJlc3NlcyxIb21lIEFwcGxpYW5jZXMsV2VhcmFibGVzICYgRml0bmVzcyBUZWNoLEhlYWRwaG9uZXMsSG9tZSBUZWNoLFNwZWFrZXJzLExhcHRvcHMsVGFibGV0cyxDb21wdXRpbmcsUGhvbmVzLEdhbWluZyxDb25zdHJ1Y3Rpb24gVG95cw0KRGlzY291bnQgQW1vdW50LG1pbiA1JSxtaW4gMTAlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUNClByaWNlIFJhbmdlLCwsLCxtaW4gJDQwMCwsLCxtaW4gJDI1LCxtaW4gJDMwMCwsLG1pbiAkMTAwLCwNCkJyYW5kIFNlbGVjdGlvbiwsLCwsLCwsLCwsLCwsLCwNCkZpbHRlciBidXR0b25zLCwsLCwsLCwsLCwsLCwsLA0KMSxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMNCjIsQW1hem9uIGRlYWxzLFVuZGVyICQxMDAwLDUwJSBvZmYsQWRpZGFzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsNTAlIG9mZixBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscw0KMyxPdmVyICQ0MDAsVW5kZXIgJDUwMCxIb2thLE5pa2UsU2FhdHZhLE5pbmphLDQwJSBvZmYsSkxhYiwsSkJMLERlbGwsLEFzdXMsQXBwbGUsQ29uc29sZXMsU3RhciBXYXJzDQo0LFVuZGVyICQxMDAwLDUwJSBvZmYsU2tlY2hlcnMsVW5kZXIgQXJtb3VyLEhlbGl4LFNoYXJrLEdhcm1pbixBbmtlciBTb3VuZGNvcmUsUmluZyxTb25vcyxBcHBsZSxBcHBsZSxUUC1saW5rLFNhbXN1bmcsQWNjZXNzb3JpZXMsVW5kZXIgJDI1DQo1LFVuZGVyICQ1MDAsTEcsQXNpY3MsQ29sdW1iaWEsRHJlYW1DbG91ZCxLZXVyaWcsQXBwbGUsU29ueSxHb3ZlZSxUcmliaXQsTGVub3ZvLFNhbXN1bmcsRWVybyxHb29nbGUsR2FtZXMsVW5kZXIgJDUwDQo2LDUwJSBvZmYsU2Ftc3VuZyxOaWtlLFBhdGFnb25pYSxOZWN0YXIsRGUnTG9uZ2hpLEFtYXpmaXQsQXBwbGUsS2FzYSBzbWFydCxTb255LEFsaWVud2FyZSxUQ0wsTmV0Z2VhcixNb3Rvcm9sYSxOaW50ZW5kbyxCb3RhbmljYWxzDQo3LEFtYXpvbixIaXNlbnNlLE5ldyBCYWxhbmNlLEFyYyd0ZXJ5eCxUZW1wdXItcGVkaWMsRHlzb24sRml0Yml0LEJlYXRzLFBoaWxpcHMgSHVlLEFua2VyLEFjZXIsT25lUGx1cyxEZWxsLE9uZVBsdXMsU29ueSxEaXNuZXkNCjgsQXBwbGUsVENMLEFkaWRhcyxDYXJoYXJ0dCxCZWFyLEJpc3NlbGwsU2Ftc3VuZyxFYXJmdW4sQmxpbmssQmVhdHMsTVNJLE1pY3Jvc29mdCxBY2VyLE5vdGhpbmcsWGJveCxNYXJ2ZWwNCjksLFNvbnksU2F1Y29ueSxUaGUgTm9ydGggRmFjZSxTaWVuYSxOdXRyaWJ1bGxldCxPdXJhLFNhbXN1bmcsR29vZ2xlIE5lc3QgLE1hcnNoYWxsLFNhbXN1bmcsTGVub3ZvLExlbm92bywsLFBva2Vtb24NCjEwLCxSb2t1LEJpcmtlbnN0b2NrLENSWiBZb2dhLFdpbmtCZWRzLEJsYWNrIGFuZCBEZWNrZXIsUmluZ2Nvbm4sQ01GLEV1ZnksU2Ftc3VuZyxNaWNyb3NvZnQsUmVNYXJrYWJsZSxBbGllbndhcmUsLCwNCjExLCwsQnJvb2tzLFRoZSBHeW0gUGVvcGxlLEJyb29rbHluIGJlZGRpbmcsTmVzcHJlc3NvLCwxTW9yZSxBcmxvLCxSYXplciwsQ29yc2FpciwsLA0KMTIsLCxDcm9jcywsRWlnaHQgU2xlZXAsQ3Vpc2luYXJ0LCxKQkwsLCwsLEhQLCwsDQpOb3RlcywsLCwsLCwsLCwsLCwsLCwNCiwsIlByaW9yaXRpc2UgYmlnZ2VzdCAlLyQgZGlzY291bnQsIFR2cyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiB0aGUgbW9zdCBwb3B1bGFyIGV2ZW4gaWYgdGhleSBhcmUgc3RpbGwgZXhwZW5zaXZlIiwiTm8gcGF0dGVybiB0byBwcmljaW5nL2Rpc2NvdW50LCByZWFkZXJzIG1haW5seSBzaG9wIGJ5IGJyYW5kL3JlY29nbmlzYWJsZSBzaG9lcyIsIk5vIHBhdHRlcm4gdG8gcHJpY2luZy9kaXNjb3VudCwgcmVhZGVycyBtYWlubHkgc2hvcCBieSBicmFuZCIsIkEgbGFiZWwgd2lsbCBkZWZpbml0ZWx5IGhlbHAgaGVyZSBlLmcuIGJlc3QgZm9yIHNpZGUgc2xlZXBlciwgYmVzdCBtZW1vcnkgZm9hbSIsIkFwcGxpYW5jZXMgaXMgYSBiaWcgY2F0ZWdvcnksIGlzIGl0IHBvc3NpYmxlIHRvIHNwbGl0IGludG8ga2l0Y2hlbiBhcHBsaWFuY2VzLCBmbG9vcmNhcmUsIGFpciBoZWFsdGgvY29vbGluZz8gT3Igc2ltaWxhciIsIkZvY3VzIG9uIHZhbHVlIGZvciBtb25leSwgR2FybWlucyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiBwb3B1bGFyIGV2ZW4gdGhvdWdoIHRoZXkgYXJlIHN0aWxsICQ1MDAiLCwsLCxJbmNsdWRlIEtpbmRsZXMsSSB3b3VsZCBpbmNsdWRlIHdpZmkgcm91dGVycyBoZXJlIGluc3RlYWQgb2Ygc21hcnQgaG9tZSxDYW4gd2Ugc3VyZmFjZSBwaG9uZSBwcm92aWRlciBkZWFscz8gVC1tb2JpbGUgYW5kIHZlcml6b24gd291bGQgbWFrZSBhIGxvdCBtb3JlIG1vbmV5IHRoYW4gQW1hem9uLCwNCiwsaGF2aW5nIGEgJ2Jlc3QgZm9yJyBsYWJlbCB3b3VsZCBiZSBoZWxwZnVsIGUuZy4gYmVzdCBmb3IgYnJpZ2h0IHJvb20sQ2FuIHdlIHN0b3Aga2lkcyBzaG9lcyBmcm9tIHB1bGxpbmcgdGhyb3VnaD8sIldpbGwgdGhpcyBpbmNsdWRlIGFjY2Vzc29yaWVzIGUuZy4gY2FwcywgYmFncywgaWYgc28gbWFrZSBzdXJlIHRoZXNlIGFyZSBtaXhlZCB0aHJvdWdob3V0IGNsb3RoaW5nIGRlYWxzIixXaWxsIHRoaXMgaW5jbHVkZSB0b3BwZXJzIGFuZCBwaWxsb3dzPyBTZWVpbmcgbW9yZSBtb21lbnR1bSB3aXRoIHRoaXMgY2F0ZWdvcnkgcmVjZW50bHkgc28gYSBiZWRkaW5nIHRhYiBtaWdodCB3b3JrLCwiTmVlZCB0byBtYWtlIHN1cmUgYmFuZHMsIHNjcmVlbiBwcm90ZWN0b3JzIGV0Yy4gZG9uJ3QgcHVsbCBpbnRvIGhlcmUiLCwsLCwsLCwsDQosLCJQcmlvcml0aXNlIDY1JycgYW5kIDU1JyBpbmNoIFRWcywgdGhlbiBiaWdnZXIgc2NyZWVucyBiZWZvcmUgdGhlIHNtYWxsZXIgc2l6ZXMiLCwsUXVlZW4gaXMgdGhlIG1vc3QgcG9wdWxhciBzaXplIGluIHRoZSBVUyAtIHByaW9yaXRpc2UgZGVhbHMgZm9yIHRoaXMgc2l6ZSwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpDYXRlZ29yaWVzIHRvIGNvbnNpZGVyLCxQcm9kdWN0cyBpbmNsdWRlZCwsLCwsLCwsLCwsLCwsDQpVbmRlciAkNTA/LCxBaXIgdGFncywsLCwsLCwsLCwsLCwsDQosLFBvcnRhYmxlIGNoYXJnZXJzL3dpcmVsZXNzIGNoYXJnZXJzLCwsLCwsLCwsLCwsLCwNCiwsIldhdGVyIGJvdHRsZXMgKHN0YW5sZXlzLCBPd2FsYSwgSHlkcm8gZmxhc2ssIFlldGkpIiwsLCwsLCwsLCwsLCwsDQosLEhhbmQgaGVsZCBmYW5zLCwsLCwsLCwsLCwsLCwNCiwsLCwsLCwsLCwsLCwsLCwNCmhvbWUgb2ZmaWNlLCxvZmZpY2UgY2hhaXJzLCwsLCwsLCwsLCwsLCwNCiwsc3RhbmRpbmcgZGVza3MsLCwsLCwsLCwsLCwsLA0KLCxtb25pdG9ycywsLCwsLCwsLCwsLCwsDQosLEtleWJvYXJkcywsLCwsLCwsLCwsLCwsDQosLGRvY2tpbmcgc3RhdGlvbiwsLCwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpHYW1pbmcsLENvbnNvbGVzLCwsLCwsLCwsLCwsLCwNCiwsQWNjZXNzb3JpZXMsLCwsLCwsLCwsLCwsLA0KLCxHYW1lcywsLCwsLCwsLCwsLCwsDQosLENvdWxkIGluY2x1ZGUgTGVnbz8sLCwsLCwsLCwsLCwsLA==")));              const text = preloadedCSV;              const parsed = parseCSV(text);                            const rowsByName = {};              let filterStart = -1;              parsed.forEach((rc, i) => {                 if (rc && rc.length > 0 && rc[0]) rowsByName[rc[0]] = rc;                 if (rc && rc.length > 0 && rc[0] === 'Filter buttons') filterStart = i;              });                            const cols = [];              if(rowsByName['Roundel text']) {                const headerRow = rowsByName['Roundel text'];                for(let col = 1; col < headerRow.length; col++) {                   let label = headerRow[col];                   if (!label) continue;                                      let q = rowsByName['Search Query'] && rowsByName['Search Query'][col] ? rowsByName['Search Query'][col] : '';                   let img = rowsByName['Roundel image'] && rowsByName['Roundel image'][col] ? rowsByName['Roundel image'][col] : '';                   let ds = rowsByName['Discount Amount'] && rowsByName['Discount Amount'][col] ? rowsByName['Discount Amount'][col] : '';                   let pr = rowsByName['Price Range'] && rowsByName['Price Range'][col] ? rowsByName['Price Range'][col] : '';                   let rt = rowsByName['Retailer'] && rowsByName['Retailer'][col] ? rowsByName['Retailer'][col] : '';                   let ot = rowsByName['Offer Type'] && rowsByName['Offer Type'][col] ? rowsByName['Offer Type'][col] : '';                                      let filters = [];                   if(filterStart > 0) {                     for(let r = filterStart + 1; r < parsed.length; r++) {                         if(!parsed[r] || parsed[r][0] === 'Notes' || parsed[r][0] === 'Categories to consider') break;                         let f = parsed[r][col];                         if(f) filters.push(f);                     }                   }                   cols.push({ label, img, q, ds, pr, rt, ot, filters });                }              }              this.carouselData = cols;              if (this.carouselData && this.carouselData.length > 0) {                 const isMatched = this.carouselData.some(c => c.q === this.currentQuery || c.label === this.currentQuery);                 if (!isMatched) {                    const first = this.carouselData[0];                    this.currentQuery = first.q || first.label;                    if (this.priceFilter) this.priceFilter.value = 'all';                    if (this.customPriceMin) this.customPriceMin.value = '';                    if (this.customPriceMax) this.customPriceMax.value = '';                    let dPr = first.pr || 'all';                    if (typeof dPr === 'string' && dPr !== 'all') {                       let prLower = dPr.toLowerCase();                       if (prLower.includes('min') || prLower.includes('over')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else if (prLower.includes('max') || prLower.includes('under')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       }                    }                    let dAm = '0';                    if(first.ds && typeof first.ds === 'string') {                       let m = first.ds.match(/(\d+)/);                       if(m) dAm = m[1];                    }                    if (this.discountFilter) this.discountFilter.value = dAm;                    if (this.offerTypeSelect) this.offerTypeSelect.value = first.ot || '';                    if (this.retailerSelect) this.retailerSelect.value = first.rt || '';                    this.selectedBrands = [];                    if (this.brandDropdown) {                        const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                        chks.forEach(chk => chk.checked = false);                    }                    if (this.searchInput) this.searchInput.value = this.currentQuery;                 }              }              this.renderCarouselUI();          } catch(e){ console.warn(e); }        }                renderCarouselUI() {           const roundelWrapper = this.root.querySelector('.tg-df-carousel-roundels');           if(!roundelWrapper || !this.carouselData) return;                      let html = '';           this.carouselData.forEach(r => {              const q = r.q || r.label;              const isActive = (this.currentQuery === q || this.currentQuery === r.label) ? 'active' : '';              const imgHtml = r.img ? `\x3Cimg src="${r.img}" alt="${r.label}" />` : `\x3Csvg width="32" height="32" fill="#1F69FF" viewBox="0 0 24 24">\x3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>\x3C/svg>`;              html += `                \x3Cdiv class="tg-df-roundel tg-df-carousel-cat ${isActive}" data-label="${this.escapeHTML(r.label)}">                  \x3Cdiv class="tg-df-roundel-img-box">${imgHtml}\x3C/div>                  \x3Cspan class="tg-df-roundel-label">${this.escapeHTML(r.label)}\x3C/span>                \x3C/div>              `;           });           roundelWrapper.innerHTML = html;                      // Rebind clicks           const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');           roundels.forEach(rNode => {             rNode.addEventListener('click', () => {                const r = this.carouselData.find(c => c.label === rNode.getAttribute('data-label'));                 if(!r) return;                                  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: r.label,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = r.q || r.label;                const labelTitle = this.root.querySelector('#tg-df-carousel-title-label');                if (labelTitle) labelTitle.textContent = 'Best ' + this.currentQuery;                if (this.priceFilter) this.priceFilter.value = 'all';                if (this.customPriceMin) this.customPriceMin.value = '';                if (this.customPriceMax) this.customPriceMax.value = '';                let dPr = r.pr || 'all';                if (typeof dPr === 'string' && dPr !== 'all') {                   let prLower = dPr.toLowerCase();                   if (prLower.includes('min') || prLower.includes('over')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMin) this.customPriceMin.value = m[1];                   } else if (prLower.includes('max') || prLower.includes('under')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMax) this.customPriceMax.value = m[1];                   }                }                                let discountAmount = '0';                if(r.ds && typeof r.ds === 'string') {                   let m = r.ds.match(/(\d+)/);                   if(m) discountAmount = m[1];                }                if (this.discountFilter) this.discountFilter.value = discountAmount;                if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                                // Clear brands                    this.selectedBrands = [];                    if (this.brandDropdown) {                    const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                    chks.forEach(chk => chk.checked = false);                }                                if (this.searchInput) this.searchInput.value = this.currentQuery;                                roundels.forEach(ro => ro.classList.remove('active'));                if (rNode) rNode.classList.add('active');                                this.renderCarouselFilters(r);                this.fetchDeals(this.currentQuery);             });           });                      // Auto-highlight active           const activeR = this.carouselData.find(c => c.q === this.currentQuery || c.label === this.currentQuery);           if(activeR) this.renderCarouselFilters(activeR);        }                renderCarouselFilters(r) {           const filtersWrap = this.root.querySelector('.tg-df-carousel-filters-wrap');           if(!filtersWrap) return;                      let html = `\x3Cbutton class="tg-df-carousel-filter-btn" data-type="all">All\x3C/button>`;                      r.filters.forEach(f => {              let fL = f.toLowerCase();              let icon = '';              let logic = `data-type="custom" data-v="${this.escapeHTML(f)}"`;              if (fL === 'amazon deals' || fL === 'prime deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\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>`;              } else if (fL === 'lightning deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\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>`;              } else {                 if (fL.includes('lightning')) {                    icon = `\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-zap">\x3Cpolygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2">\x3C/polygon>\x3C/svg>`;                 } else if (fL.includes('% off')) {                    icon = `\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>`;                 } else if (fL.includes('under') || fL.includes('min ')) {                    icon = `\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>`;                 }                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>${icon} ${this.escapeHTML(f)}\x3C/button>`;              }           });                      filtersWrap.innerHTML = html;                      const btns = filtersWrap.querySelectorAll('button');           btns.forEach(b => {             b.addEventListener('click', () => {                const type = b.getAttribute('data-type');                if (type === 'custom') {                   const v = b.getAttribute('data-v');                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-custom-${(v||'').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, name: 'Custom Filter', label: v });                }                if (type === 'all') {                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: 'filter-clear-all', name: 'Clear all', label: 'Clear all filters' });                   // reset everything                   btns.forEach(btn => btn.classList.remove('active'));                   b.classList.add('active');                                      // Reset prices                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   if (this.brandDropdown) {                     const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                     chks.forEach(chk => chk.checked = false);                   }                } else {                   const v = b.getAttribute('data-v');                   const fL = v.toLowerCase();                                      let mapRet = ['amazon', 'walmart', 'best buy', 'target', 'john lewis', 'currys', 'argos'];                   const getCategory = (s) => {                      if (s === 'lightning deals' || s === 'amazon deals' || s === 'prime deals') return 'offer';                      if (s.includes('% off')) return 'discount';                      if (s.includes('under') || s.includes('over') || s.includes('min') || s.includes('max')) return 'price';                      if (mapRet.includes(s)) return 'retailer';                      return 'brand';                   };                   const cat = getCategory(fL);                   const wasActive = b.classList.contains('active');                   if (cat !== 'brand') {                      btns.forEach(btn => {                          if (btn === b) return;                          if (btn.getAttribute('data-type') === 'all') return;                          const bV = btn.getAttribute('data-v');                          if (!bV) return;                          if (getCategory(bV.toLowerCase()) === cat) btn.classList.remove('active');                      });                   }                   if (wasActive) b.classList.remove('active');                   else b.classList.add('active');                   let anyActive = Array.from(btns).some(btn => btn !== btns[0] && btn.classList.contains('active'));                   if (!anyActive) {                       btns[0].click();                       return;                   } else {                       btns[0].classList.remove('active');                   }                                      if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   btns.forEach(btn => {                       if (!btn.classList.contains('active') || btn.getAttribute('data-type') === 'all') return;                       const vv = btn.getAttribute('data-v');                       const vl = vv.toLowerCase();                                              if (vl === 'lightning deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_lightning';                       } else if (vl === 'amazon deals' || vl === 'prime deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_prime';                       } else if (vl.includes('% off')) {                          let m = vl.match(/(\d+)%/);                          if (m && this.discountFilter) this.discountFilter.value = m[1];                       } else if (vl.includes('under') || vl.includes('max')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       } else if (vl.includes('min') || vl.includes('over')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else {                          let foundR = mapRet.find(x => x === vl);                          if (foundR) {                             let realR = ['Amazon', 'Walmart', 'Best Buy', 'Target', 'John Lewis', 'Currys', 'Argos'].find(x => x.toLowerCase() === vl);                             if (this.retailerSelect) this.retailerSelect.value = realR;                          } else {                             this.selectedBrands.push(vv);                          }                       }                   });                                      if (this.brandDropdown) {                       const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                       chks.forEach(c => c.checked = this.selectedBrands.includes(c.value));                   }                                      if (r.pr && typeof r.pr === 'string') {                       let prL = r.pr.toLowerCase();                       if (prL.includes('under $')) {                           let m = prL.match(/under \$(\d+)/i);                           if (m && this.customPriceMax && !this.customPriceMax.value) this.customPriceMax.value = m[1];                       }                   }                }                                this.fetchDeals(this.currentQuery);             });           });                      // default to highlighting first           btns[0].classList.add('active');        }async fetchDeals(query, append = false) {          if (!append) {             this.showLoading();             this.deals = [];             this.displayLimit = (this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12;          } else {             this.displayLimit += (this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12;          }                    try {            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad(append);            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query, append);               } else {                 await this.fetchHawkDeals(query, append);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query, append);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&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=tomsguide&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) {             const encodedTag = encodeURIComponent(this.activeDealTag.toLowerCase().replace(/\s+/g, '-'));             const url = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&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 dynamicBrandsCounts = {};                    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();                   dynamicBrandsCounts[data.brand] = (dynamicBrandsCounts[data.brand] || 0) + 1;                }                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;                   }                }                                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 || ''                });             });          });                    const airedaleBrandsList = Object.keys(dynamicBrandsCounts).map(b => ({              formatted_value: b,              count: dynamicBrandsCounts[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, append = false) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (append && this.deals.length > 0) {            url.searchParams.append('offset', this.deals.length.toString());          }                    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');                    if (this.rowsSelect && this.rowsSelect.value) {            url.searchParams.append('rows', this.rowsSelect.value);          } else {             url.searchParams.append('rows', '12'); // default          }          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 = 12;          if (this.rowsSelect && this.rowsSelect.value) {            rowLimit = parseInt(this.rowsSelect.value, 10) || 12;          }          // 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 : (this.getViewMode() === 'savings_squad' ? 'date_desc' : 'discount_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}                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin-top:8px;">${_div}                ${_div}              ${_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 => {              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}`;                }              }              return `                \x3Ca href="${this.escapeHTML(linkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item">                  ${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);                }              });            });                                  } 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)} (${this.airedaleTagCounts[tag] || 0})${_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 = isSavingsSquadMode ? 'View Deal' : 'Check Price';              if (isSavingsSquadMode) {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                  ${_div}                `;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \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 = `                \x3Cdiv class="tg-df-card-merchant-wrapper">                  \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                ${_div}                \x3Cdiv class="tg-df-card-price-group">                  ${isSavingsSquadMode ? '' : `                  \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 = `              \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">\x3Cp>${this.escapeHTML(deal.description)}${_p}${_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>${deal.isCheckPrice ? 'Check Price' : '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}                ${_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 ? `\x3Cp style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 12px; line-height: 1.4;">${this.escapeHTML(deal.description)}${_p}` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${priceGroupHtml}                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta ${isSavingsSquadMode ? 'tg-df-cta-savings-squad' : ''}" style="text-decoration: none;">${ctaText}${_a}                  ${_div}                ${_div}              ${_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 || ((this.getViewMode() === 'carousel' || this.getViewMode() === 'auto') && displayDeals.length > 0 && displayDeals.length % ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12) === 0)) {            if (this.getViewMode() === 'carousel') {               dealsHtml += `                 \x3Cbutton type="button" class="tg-df-load-more-card tg-df-load-more">                   \x3Csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-bottom: 8px;">\x3Cpath d="M5 12h14">\x3C/path>\x3Cpath d="m12 5 7 7-7 7">\x3C/path>\x3C/svg>                   Load More                 ${_button}               `;            } else {               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; display: flex; align-items: center;">Load More${_button}                 ${_div}               `;            }          }                    this.grid.innerHTML = dealsHtml;                    let gridWrapper = this.grid.parentElement;          if (gridWrapper && gridWrapper.classList.contains('tg-df-grid-wrapper')) {             let existingChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-right');             if (this.getViewMode() === 'carousel') {                 if (!existingChevron) {                     gridWrapper.insertAdjacentHTML('beforeend', '\n                 \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.previousElementSibling.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>');                 }             } else {                 if (existingChevron) {                     existingChevron.remove();                 }             }          }                    const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', async () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              if (displayDeals.length <= this.displayLimit) {                 loadMoreBtn.innerHTML = `                  <svg class="tg-df-spinner" style="width: 16px; height: 16px; display: inline-block; vertical-align: middle; margin-right: 8px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/></svg>                  Loading...                 `;                 loadMoreBtn.disabled = true;                 await this.fetchDeals(this.currentQuery, true);              } else {                 this.displayLimit += ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12);                 this.render();              }            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();                        // 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');            }            setTimeout(() => {               if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            if (!this.processArticleFired) {                  this.processArticleFired = true;                  document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));               }            }, 50);          } 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[ Forget overpriced OLEDs — this 40-inch ultrawide monitor is down to $359 for Prime Day ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/i-went-big-on-a-budget-with-this-40-inch-ultrawide-monitor-and-its-incredibly-immersive-without-breaking-the-bank</link>
                                                                            <description>
                            <![CDATA[ The Innocn 40C1R may be older, but you won’t find a flat, high-refresh 40-inch display that still holds up for this price anywhere else. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">ZXtHM5jfFvxL7ebdYm3XeF</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/gLCFQNJ85JYJAqsC9mGkji-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 23 Jun 2026 10:30:00 +0000</pubDate>                                                                                                                                <updated>Wed, 24 Jun 2026 14:43:30 +0000</updated>
                                                                                                                                            <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ anthony.spadafora@futurenet.com (Anthony Spadafora) ]]></author>                    <dc:creator><![CDATA[ Anthony Spadafora ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/z73LEoj7FkUjNG85GcWHtH.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Anthony Spadafora is the managing editor for security and home office furniture at Tom’s Guide where he covers everything from data breaches and malware to password managers and the best way to cover your whole home or business with a strong Wi-Fi signal.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Before joining the team, he spent three years covering cybersecurity and B2B tech for ITProPortal while living in South Korea. After moving back to the US. Anthony joined the TechRadar Pro team where he covered these topics along with VPNs, web hosting, online collaboration software and video conferencing for four years. Anthony also has his ears to the ground and is on the lookout for the next major cyberattack or data breach.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Based in Houston, Texas, Anthony also handles VPN testing for both Tom’s Guide and TechRadar. As someone who has worked from home exclusively since 2018, he has reviewed dozens of standing desks as well as office chairs and has taken a closer look at other essential remote working accessories. As part of these reviews, Anthony frequently builds intricate desk setups which is why he’s such a big advocate for cable management and keeping things organized. When he’s not writing, he can be found tinkering with PCs and game consoles, managing cables and making upgrades to his smart home.&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/gLCFQNJ85JYJAqsC9mGkji-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Innocn 40C1R ultrawide monitor playing a music video with a 21:9 aspect ratio]]></media:description>                                                            <media:text><![CDATA[The Innocn 40C1R ultrawide monitor playing a music video with a 21:9 aspect ratio]]></media:text>
                                <media:title type="plain"><![CDATA[The Innocn 40C1R ultrawide monitor playing a music video with a 21:9 aspect ratio]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/gLCFQNJ85JYJAqsC9mGkji-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>When people think about upgrading to a big, immersive display, the latest <a href="https://www.tomsguide.com/computing/monitors/i-tried-lgs-bendable-5k2k-gaming-monitor-and-its-now-the-screen-of-my-dreams">5K2K monitors</a> from LG and Samsung are usually the first that come to mind. However, while they’re certainly some of the <a href="https://www.tomsguide.com/best-picks/best-monitors">best monitors</a> you can buy, they come with premium price tags of at least $1,000.</p><p>Fortunately, if you want more screen real estate but don’t want to pay as much as you would for a high-end graphics card, there are more affordable alternatives. A few months back, I tried out the 5K2K <a href="https://www.tomsguide.com/computing/monitors/i-ditched-my-dual-monitor-setup-for-a-single-40-inch-ultrawide-and-two-screens-arent-better-than-one">Innocn 401CU</a> and it certainly fits the bill. While it has a list price of $999, I’ve seen it as low as $600 during major sales events.</p><p>After looking through the comments on that story though, I was surprised to see how many Tom’s Guide readers thought even <em>that</em> sale price was too expensive for a monitor, with many suggesting buying a budget 4K TV instead. To see if I could find a gem in the rough, I decided to try out Innocn’s even more affordable sibling: the 401CR ultrawide monitor.</p><p>At full price, it’s just under $500, but I’ve seen it go for as low as $350 while on sale. At that price, it’s a steal for a flat, 40-inch ultrawide with single-cable USB-C connectivity. Given <a href="https://www.tomsguide.com/sales-events/prime-day-apple-deals-are-live-now-get-up-to-32-percent-off-iphone-17-macbooks-ipads-and-airpods">Prime Day </a>starts today, I expect it to see a deep discount.</p><p>If you need massive screen space for productivity and more immersive gaming, this underdog might just be the perfect upgrade for your desk setup.</p><div class="product"><a data-dimension112="d46fa21a-ecfc-4b84-afae-0420d87f1b24" data-action="Deal Block" data-label="If you want the sheer scale of a massive 40-inch monitor but prioritize smooth gaming speeds over an excessive pixel count, the 40C1R is an unbeatable value. It trades the demanding 5K2K resolution of its premium sibling for a much more GPU-friendly 3440 x 1440 canvas, allowing it to bump the refresh rate up to a fluid 144Hz. It even manages to beat the more expensive model in raw utility — serving up a beefier 90W of power delivery over a single USB-C cable to easily keep power-hungry pro laptops fully charged while you play." data-dimension48="If you want the sheer scale of a massive 40-inch monitor but prioritize smooth gaming speeds over an excessive pixel count, the 40C1R is an unbeatable value. It trades the demanding 5K2K resolution of its premium sibling for a much more GPU-friendly 3440 x 1440 canvas, allowing it to bump the refresh rate up to a fluid 144Hz. It even manages to beat the more expensive model in raw utility — serving up a beefier 90W of power delivery over a single USB-C cable to easily keep power-hungry pro laptops fully charged while you play." data-dimension25="$379" href="https://www.amazon.com/INNOCN-Ultrawide-Monitor-Gaming-FreeSync/dp/B0G7VVZ229?th=1" 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:62.07%;"><img id="SD5VTihpfBoetQyx8jZckP" name="40C1R" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SD5VTihpfBoetQyx8jZckP.jpg" mos="" align="middle" fullscreen="" width="1500" height="931" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>If you want the sheer scale of a massive 40-inch monitor but prioritize smooth gaming speeds over an excessive pixel count, the 40C1R is an unbeatable value. It trades the demanding 5K2K resolution of its premium sibling for a much more GPU-friendly 3440 x 1440 canvas, allowing it to bump the refresh rate up to a fluid 144Hz. It even manages to beat the more expensive model in raw utility — serving up a beefier 90W of power delivery over a single USB-C cable to easily keep power-hungry pro laptops fully charged while you play.  <a class="view-deal button" href="https://www.amazon.com/INNOCN-Ultrawide-Monitor-Gaming-FreeSync/dp/B0G7VVZ229?th=1" target="_blank" rel="nofollow" data-dimension112="d46fa21a-ecfc-4b84-afae-0420d87f1b24" data-action="Deal Block" data-label="If you want the sheer scale of a massive 40-inch monitor but prioritize smooth gaming speeds over an excessive pixel count, the 40C1R is an unbeatable value. It trades the demanding 5K2K resolution of its premium sibling for a much more GPU-friendly 3440 x 1440 canvas, allowing it to bump the refresh rate up to a fluid 144Hz. It even manages to beat the more expensive model in raw utility — serving up a beefier 90W of power delivery over a single USB-C cable to easily keep power-hungry pro laptops fully charged while you play." data-dimension48="If you want the sheer scale of a massive 40-inch monitor but prioritize smooth gaming speeds over an excessive pixel count, the 40C1R is an unbeatable value. It trades the demanding 5K2K resolution of its premium sibling for a much more GPU-friendly 3440 x 1440 canvas, allowing it to bump the refresh rate up to a fluid 144Hz. It even manages to beat the more expensive model in raw utility — serving up a beefier 90W of power delivery over a single USB-C cable to easily keep power-hungry pro laptops fully charged while you play." data-dimension25="$379">View Deal</a></p></div><h2 id="flat-wide-and-fully-specced">Flat, wide and fully-specced</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="48CsMnEMukYzoiXGKopnsP" name="Innocn 401CR-6" alt="The Innocn 40C1R ultrawide monitor unboxed on a desk" src="https://cdn.mos.cms.futurecdn.net/48CsMnEMukYzoiXGKopnsP.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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 37.1 x 16.5 x 2.2 inches, the 40C1R is anything but a small display, and at roughly 20 pounds without the stand, it’s on the heavier side, too. Thankfully, Innocn includes a fairly heavy-duty stand with a thick metal baseplate and a plastic vertical arm that’s reinforced with a sturdy metal core.</p><p>Having unboxed my fair share of monitors over the years, I really like how Innocn includes a high-speed USB-C to USB-C video cable and a DisplayPort cable right in the box. You don’t get an HDMI cable though, but you likely have several of those laying around anyway. Likewise, you probably won’t want to use an HDMI connection with this display as your refresh rate will be capped at 100 Hz versus the full 144 Hz you get over DisplayPort.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="MDB4pzkvSjKpKqDmpu2cLU" name="Innocn 401CR-4" alt="The Innocn 40C1R ultrawide monitor lying face down on a desk showing off its rear ports and VESA mounting holes" src="https://cdn.mos.cms.futurecdn.net/MDB4pzkvSjKpKqDmpu2cLU.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>With the monitor lying face down on my desk, you get a clear look at its overall structural design. Right off the bat, I love how Innocn uses standard, square 100 x 100 VESA mounting holes instead of those silly circular 75 x 75 ones you see on a lot of other gaming monitors. This makes it incredibly easy to swap out the stand for any of the <a href="https://www.tomsguide.com/best-picks/best-monitor-arms">best monitor arms</a> since you won’t need to hunt for a proprietary adapter.</p><p>Looking at the back of the panel, the connectivity is split cleanly. The power port sits entirely on its own side, which highlights one of my favorite features: a built-in power supply. Just like the more expensive 40C1U, there is no bulky power brick to hide under your desk — just a single standard power cable. On the opposite side of the rear cutout, you'll find the main selection of ports, while the monitor’s physical OSD navigation buttons line the corresponding outer edge.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9ArrHAaRhZn5JUMkWDHdaW" name="Innocn 401CR-5" alt="A closeup shot of the Innocn 40C1R's rear ports" src="https://cdn.mos.cms.futurecdn.net/9ArrHAaRhZn5JUMkWDHdaW.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>As for those ports, you get a great selection of connection options, including dual HDMI 2.0 inputs, DisplayPort 1.4, USB-C, and a 3.5mm audio jack. While the 40C1R drops the built-in USB-A hub found on the premium 40C1U to save on cost, it oddly beats its more expensive sibling in utility: its USB-C port delivers a massive 90W of power delivery as opposed to just 60W.</p><p>After unboxing the 40C1R, I installed the included stand using a single built-in thumb screw. With the monitor securely set up and plugged in, it was finally time to see how it performs.</p><h2 id="laptop-power-with-gaming-pc-framerates">Laptop power with gaming PC framerates</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="VM35926LUe7iRxKUayjg4a" name="Innocn 401CR-3" alt="A MacBook Pro M5 16 inch connected to the Innocn 40C1R ultrawide monitor on a desk" src="https://cdn.mos.cms.futurecdn.net/VM35926LUe7iRxKUayjg4a.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>In order to test the 40C1R and make sure it was working properly, I first hooked it up to a <a href="https://www.tomsguide.com/computing/macbooks/macbook-pro-16-inch-m5-pro-review">MacBook Pro M5</a> I borrowed from work for another monitor review. Although 90W of power delivery is a bit less than the 140W provided by Apple's included charger, it is still more than enough juice to keep a 16-inch MacBook fully topped off even during heavy workloads. For the rest of the <a href="https://www.tomsguide.com/computing/laptops/best-laptops">best laptops</a>, 90W will be plenty to fast charge them while connected to this massive display.</p><p>With the MacBook Pro plugged into the 40C1R, the monitor’s IPS panel looked vibrant and crisp, with no dead pixels to speak of. While the 40C1R does come equipped with dual 5W built-in speakers, I ended up switching back to the ones on the MacBook Pro after a bit. Still, they are nice to have in a pinch, and they do sound much less tinny than the bottom-tier 2W speakers you find on a lot of other budget monitors.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9Fdd8h3QCxU444iuK58uce" name="Innocn 401CR-2" alt="The Innocn 40C1R ultrawide monitor with the Khadas Mind 2S attached to the Mind Graphics 2 GPU dock underneath it" src="https://cdn.mos.cms.futurecdn.net/9Fdd8h3QCxU444iuK58uce.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>Sadly, I no longer own a big, bulky gaming desktop anymore (as I’ve been using one of the <a href="https://www.tomsguide.com/us/best-mini-pc.html">best mini PCs</a> for both work and play for the past few years) but fortunately, my favorite pocketable mini PC — the <a href="https://www.tomsguide.com/computing/mini-pcs/khadas-mind-2s-review">Khadas Mind 2S</a> — can be instantly upgraded with an NVIDIA GeForce RTX 5060 Ti desktop GPU just by dropping it onto Khadas’ <a href="https://www.tomsguide.com/computing/mini-pcs/i-gave-my-favorite-pocketable-mini-pc-an-instant-upgrade-with-this-docking-station-and-now-its-a-full-fledged-gaming-rig">Mind Graphics 2</a> dock.</p><p>Now, I know what you might be thinking when looking at a compact setup like this: airflow. I too was worried about putting this docked mini PC directly underneath the 40C1R at first. However, after pushing the hardware and running a few demanding games on it, I didn’t run into any thermal throttling or heating issues at all. I chalk this up to Khadas' excellent internal cooling design and the fact that the dock's entire outer shell is machined from aluminum, which acts as a giant heatsink.</p><p>With the 40C1R confirmed to be fully operational and paired with a surprisingly powerful eGPU dock, it was time to see how this budget-friendly 40-inch ultrawide handles real-world productivity and immersive gaming.</p><h2 id="big-screen-on-a-budget">Big screen on a budget</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:4532px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="vVzs4Cc6V2BBm7REY9uQ2L" name="LucidSound LS500P" alt="A person playing Death Stranding 2 on the Innocn 40C1R ultrawide monitor" src="https://cdn.mos.cms.futurecdn.net/vVzs4Cc6V2BBm7REY9uQ2L.jpg" mos="" align="middle" fullscreen="" width="4532" height="2549" 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>Back when I tried out Innocn’s more premium 40-inch ultrawide, I did play a few games on it. However, with a massive resolution of 5120 x 2160, the <a href="https://www.tomsguide.com/computing/mini-pcs/framework-desktop-review">Framework Desktop</a> I was using at the time struggled to push smooth frame rates. With a lower — yet still reasonably high — resolution of 3440 x 1440, I knew that my mini PC with its desktop-grade <a href="https://www.tomsguide.com/computing/gpus/nvidia-geforce-rtx-5060-ti-review">RTX 5060 Ti</a> would have a much easier time keeping up. Likewise, given this is an outright gaming monitor instead of a productivity-first screen like the 40C1U, it actually features a much higher 144 Hz refresh rate.</p><p>For the past few months, I’ve been making my way through <a href="https://www.tomsguide.com/gaming/death-stranding-2-is-the-most-beautiful-game-ive-ever-played-and-its-everything-id-hope-for-in-a-sequel">Death Stranding 2</a>, and on an ultrawide display like this one with a 21:9 aspect ratio, it’s been an absolute joy to play. Not only was the game’s world wider than it was on my <a href="https://www.tomsguide.com/gaming/playstation/i-fixed-my-biggest-gripe-with-the-ps5-pro-with-these-unofficial-cover-plates-and-now-it-looks-and-feels-more-like-a-pc">PS5 Pro</a>, but I could crank the framerate past 60 fps all the way up to a buttery-smooth 144 fps. In fact, if you’re coming from a console and are playing on an ultrawide, you might end up double-dipping on a few titles just to experience them at full width without any distracting black bars on the sides.</p><p>In addition to Death Stranding 2, I also really enjoyed playing my go-to skateboarding game <a href="https://www.tomsguide.com/opinion/session-is-the-perfect-stopgap-until-skate-4-if-you-can-handle-the-learning-curve">Session</a> and <a href="https://www.tomsguide.com/reviews/ratchet-and-clank-rift-apart">Ratchet and Clank: Rift Apart</a> on this wider display. It also helps that the monitor comes equipped with AMD’s FreeSync Premium, so you can turn on VRR (variable refresh rate) for a tear-free experience. The 40C1R does have HDR support, but I preferred leaving it off since it's an HDR400 panel that tops out around 400 to 500 nits of brightness. Without local dimming, SDR content actually looks a lot punchier.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="gLCFQNJ85JYJAqsC9mGkji" name="Innocn 401CR" alt="The Innocn 40C1R ultrawide monitor playing a music video with a 21:9 aspect ratio" src="https://cdn.mos.cms.futurecdn.net/gLCFQNJ85JYJAqsC9mGkji.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>With an ultrawide display like the 40C1R, streaming content online can be awesome, too... if you find the right video. While most TV shows are locked to standard 16:9, you can find plenty of movies and even some music videos — like Drake’s "2 Hard 4 The Radio" pictured above — that are natively available with a cinematic 21:9 aspect ratio. After upgrading to an ultrawide, I highly recommend going to YouTube, searching for 21:9 trailers, and turning the resolution all the way up. You won’t be disappointed.</p><p>Overall, I’m quite impressed with the 40C1R, especially given the fact that it’s a four-year-old monitor design. While you might think you need the latest and greatest OLED display to upgrade your desk setup or battlestation, my experience with this monitor proves you definitely don’t.</p><h2 id="one-for-work-one-for-play">One for work, one for play</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:1985px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="2hEB2xyce6TZxirksW7w8n" name="work-vs-play-2" alt="A side by side shot showing the Innocn 40C1U on the left and the Innocn 40C1R on the right" src="https://cdn.mos.cms.futurecdn.net/2hEB2xyce6TZxirksW7w8n.jpg" mos="" align="middle" fullscreen="" width="1985" height="1117" 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’ll admit, I was lucky enough to experience Innocn’s latest and greatest 40-inch ultrawide before tying out this more budget-friendly model. However, after thoroughly testing both of them, they each clearly have their place depending on your use case and how much you’re willing to spend.</p><p>With its higher resolution and built-in USB hub, the Innocn 40C1U is a fantastic productivity monitor. You can see substantially more on the screen at the same time, and if you want to switch between two computers — say a Mac and a Windows machine like I’m doing here — you won’t need to buy a separate <a href="https://www.tomsguide.com/gaming/i-took-a-big-risk-on-this-open-box-gaming-monitor-and-it-actually-paid-off">KVM switch</a>. However, for gaming at that native 5K2K resolution, you’re going to need a really beefy graphics card with frame generation turned on for your favorite titles to truly shine.</p><div class="product"><a data-dimension112="77cdf817-e28a-4a93-acd8-73f210484641" data-action="Deal Block" data-label="This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens." data-dimension48="This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens." data-dimension25="$799" href="https://www.amazon.com/INNOCN-Inch-2160p-Ultrawide-Monitor/dp/B0D7Q8N64F" 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:61.07%;"><img id="BzCn3DiniFqNV4SefEPo3D" name="40C1U" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/BzCn3DiniFqNV4SefEPo3D.jpg" mos="" align="middle" fullscreen="" width="1500" height="916" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens. <a class="view-deal button" href="https://www.amazon.com/INNOCN-Inch-2160p-Ultrawide-Monitor/dp/B0D7Q8N64F" target="_blank" rel="nofollow" data-dimension112="77cdf817-e28a-4a93-acd8-73f210484641" data-action="Deal Block" data-label="This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens." data-dimension48="This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens." data-dimension25="$799">View Deal</a></p></div><p>Given its higher refresh rate and lower price, the Innocn 40C1R stands out as a fantastic ultrawide monitor for gaming, even if the underlying panel design is several years old now. While it comes equipped with legacy HDMI 2.0 ports instead of newer <a href="https://www.tomsguide.com/tvs/hdmi-2-1-vs-hdmi-2-2-biggest-differences-explained-and-when-you-should-upgrade">HDMI 2.1</a> ones, that won’t be a problem since you’re going to want to use a DisplayPort cable anyway to make full use of its faster 144 Hz refresh rate. Although a built-in USB-A hub would have been nice to see, I’m sure most people would rather have the massive 90W of power delivery over USB-C so they can fast charge a laptop and utilize it to its fullest potential at the same time.</p><p>Now, would I recommend either of these monitors for gaming on a console? Absolutely not, since even the more powerful PS5 Pro is still strictly locked to a standard 16:9 aspect ratio. That could very well change down the road with the <a href="https://www.tomsguide.com/gaming/playstation/sony-will-allegedly-launch-three-ps6-systems-including-two-consoles-and-a-handheld-claims-leaker">PS6</a> and Xbox’s upcoming <a href="https://www.tomsguide.com/gaming/xbox/next-xbox-will-play-your-xbox-and-pc-games-new-ceo-promises">Project Helix</a>, but for now, if you want to experience a wider, more immersive field of view while gaming, PC is your best and only option.</p><p>At the moment, I have the Innocn 40C1U set up as my dedicated work machine powered by the ultra-powerful <a href="https://www.tomsguide.com/computing/mini-pcs/geekom-a9-max-review">Geekom A9 Max 2026 Edition</a>, and I’m using the Innocn 40C1R right alongside it for gaming. If I was on a strict budget and had to pick one over the other, the 40C1R would easily be my choice because you’re getting a flat, massive 40-inch ultrawide with a high refresh rate and better power delivery over a single USB-C cable. That’s not to say the 40C1U is a bad monitor by any means, but at 100 Hz with a demanding 5K2K resolution, it’s simply much better suited for spreadsheets and content creation than it is for high-framerate gaming.</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/computing/i-built-the-ultimate-distraction-free-desk-setup-and-now-im-truly-locked-in">I built a completely distraction-free desk setup with these 10 gadgets and now I’m truly locked in</a></li><li><a href="https://www.tomsguide.com/computing/peripherals/monitor-stand-vs-monitor-arm-how-to-pick-the-right-one-for-your-display">Monitor stand vs monitor arm: how to pick the right one for your display</a></li><li><a href="https://www.tomsguide.com/computing/monitors/i-spent-a-week-with-dual-apple-studio-displays-and-realized-ive-been-lying-to-myself-about-glossy-screens-for-years">I spent a week with dual Apple Studio Displays and realized I’ve been lying to myself about glossy screens for years</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Steam Machine reviews are here: 'Even Valve is disappointed' ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/pc-gaming/steam-machine-reviews-are-here-even-valve-is-disappointed</link>
                                                                            <description>
                            <![CDATA[ The first Steam Machine reviews have gone live, and opinions are mixed. From price, performance, and convenience, here's what tech reviewers had to say. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">VpvwTpQjGAWPRqXYz3QuF7</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/EWEFvfXcTi2HKWLY5zAAck-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 22 Jun 2026 19:05:45 +0000</pubDate>                                                                                                                                <updated>Tue, 23 Jun 2026 01:06:07 +0000</updated>
                                                                                                                                            <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/EWEFvfXcTi2HKWLY5zAAck-1280-80.jpg">
                                                            <media:credit><![CDATA[Valve]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Valve Steam Machine ]]></media:description>                                                            <media:text><![CDATA[Valve Steam Machine ]]></media:text>
                                <media:title type="plain"><![CDATA[Valve Steam Machine ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/EWEFvfXcTi2HKWLY5zAAck-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The first reviews for the highly anticipated <a href="https://www.tomsguide.com/gaming/pc-gaming/valve-steam-machine-console-just-announced-6x-more-powerful-than-steam-deck">Steam Machine</a> have gone live… and the verdict is decidedly mixed.</p><p>The SteamOS-powered mini PC is Valve’s latest attempt to deliver a premium, console-like experience for your Steam library. It starts at $1,049 / £879 / AU$1,609 for the 512GB model and jumps to $1,428 / £1,208 / AU$2,228 for the 2TB model with a controller. Yes, this is one expensive piece of kit!</p><p><a href="https://www.tomsguide.com/gaming/pc-gaming/valves-steam-machine-is-ready-to-launch-starting-at-usd1-049-im-getting-one-to-review-and-im-taking-your-questions-live">We’ll be getting a Steam Machine in soon for review</a>, so for now, let’s take a look at what some prominent tech reviewers have to say about the Steam Machine.</p><h2 id="what-are-reviewers-saying-about-the-steam-machine">What are reviewers saying about the Steam Machine?</h2><p>One aspect that’s receiving consistent praise is the Steam Machine’s design. <a href="https://www.youtube.com/watch?v=WhWtLi_FqLo" target="_blank">Digital Foundry</a> calls it “<strong>beautiful hardware</strong>,” and the other outlets agree that the small cube form factor feels premium and fits a living room setup. Valve’s mini PC apparently runs cool and quiet, and the front-facing ports (such as a microSD reader) are well placed for easy access.</p><p>“<strong>Valve's beautifully tiny console-like PC is finally here</strong>," says Digital Foundry. "<strong>And from a form factor perspective, it's kind of irresistible. Imagine a taller Nintendo Gamecube, and you have some idea of how tiny this thing is</strong>.”</p><p>Another thing reviewers like is <a href="https://www.tomsguide.com/us/steamos-faq-machines,news-17614.html">SteamOS</a> itself, which I’ve praised on the Steam Deck. Digital Foundry says that SteamOS is “<strong>fantastic</strong>,” and <a href="https://www.youtube.com/watch?v=zXHHenUWxnQ" target="_blank">IGN</a> notes that the Steam Machine boots straight into big picture mode while still letting you drop into the Linux desktop mode for other tasks, if needed. Basically, you get the same basic UI experience as on the Steam Deck, which is great.</p><p>Things get more complicated when it comes to performance. <a href="https://www.youtube.com/watch?v=6tI1SoMj5vg" target="_blank">Linus Tech Tips</a>, in particular, noted some big swings in their benchmarks. For instance, Shadow of the Tomb Raider ran above 120 frames per second at 4K resolution, but Cyberpunk 2077, with ray tracing enabled, hobbled along at 15 fps at 1080p. However, without ray tracing and the frame-boosting FSR enabled, IGN got the latter to run at 42 fps.</p><h3 class="article-body__section" id="section-richard-leadbetter-digital-foundry"><span>Richard Leadbetter, Digital Foundry</span></h3><div><blockquote><p>Valve's beautifully tiny console-like PC is finally here. And from a form factor perspective, it's kind of irresistible. Imagine a taller Nintendo Gamecube, and you have some idea of how tiny this thing is.”</p></blockquote></div><h3 class="article-body__section" id="section-linus-sebastian-linus-tech-tips"><span>Linus Sebastian, Linus Tech Tips</span></h3><div><blockquote><p>“I was really hoping that this was going to bring PC gaming to the mainstream living room... But this is a premium price, even though I wouldn't say it's a premium product."</p></blockquote></div><h3 class="article-body__section" id="section-ign"><span>IGN</span></h3><div><blockquote><p>"It is easily the best living room PC our reviewer has ever used, despite being a bit weaker than either of the base consoles."</p></blockquote></div><p>Comparison-wise, Digital Foundry says the Steam Machine performs between an RX 6600 and RX 7600, which are GPUs that can deftly handle 1080p/1440p high settings. However, the Steam Machine's 8GB of VRAM becomes a limitation for gaming at 4K with ray tracing.</p><p>"It is easily the best living room PC our reviewer has ever used, despite being a bit weaker than either of the base consoles," says IGN.</p><p>Naturally, the thing all reviews keep coming back to is the Steam Machine’s price. IGN says the cost is “<strong>a major factor in who to recommend this to</strong>,” while Digital Foundry wonders if the hardware justifies the cost, given the performance level.</p><p>“<strong>It cost more than we hoped, and Valve confirmed they feel the same way</strong>,” said Linus Tech Tips, which is likely why their video is titled: "<strong>Even Valve is disappointed</strong>." Linus also said, “<strong>I was really hoping that this was going to bring PC gaming to the mainstream living room... But this is a premium price, even though I wouldn't say it's a premium product</strong>," says Linus Tech Tips.</p><p>Many of the comments across all three video reviews say they can build a strong PC for a similar price, and that it’s hard to justify Valve’s platform over a <a href="https://www.tomsguide.com/gaming/playstation/ps5-pro-review">PS5 Pro</a> (currently $899) or a proper desktop.</p><p>IGN had the most positive take, saying: “<strong>We love a lot about it, had some issues with it, but overall came away from our time with it feeling very positive</strong>.” The outlet specifically says it’s great if you have a large Steam library and want something that just works in the living room without any tinkering.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-exmj4W"></div>                            </div>                            <script src="https://kwizly.com/embed/exmj4W.js" async></script><h2 id="outlook-3">Outlook</h2><p>Overall, early reviews of the Steam Machine agree that it is a well-designed piece of hardware that delivers on the promise of a convenient SteamOS living room box. Of course, the main sticking point is whether the performance and convenience are enough to justify the lofty asking price.</p><p>Again, we’ll have a full review of the Steam Machine for you soon, so stay tuned for that and additional coverage on Valve’s latest gaming machine.</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/gaming/pc-gaming/i-might-ditch-my-gaming-pc-for-the-steam-machine-heres-why">I might ditch my gaming PC for the Steam Machine — here's why</a></li><li><a href="https://www.tomsguide.com/computing/virtual-reality/valve-announces-steam-frame-vr-headset-a-premium-standalone-rival-to-the-meta-quest-3">Valve announces Steam Frame VR headset</a></li><li><a href="https://www.tomsguide.com/gaming/i-made-steam-deck-even-better-thanks-to-this-new-update-heres-how">Here's how I made Steam Deck even better thanks to this update</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Valve's Steam Machine is ready to launch, starting at $1,049 — I'm getting one to review, and I'm taking your questions LIVE ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/pc-gaming/valves-steam-machine-is-ready-to-launch-starting-at-usd1-049-im-getting-one-to-review-and-im-taking-your-questions-live</link>
                                                                            <description>
                            <![CDATA[ The Steam Machine is ready to preorder right now, and I will be getting one to review soon. Here's how to order your own, and your chance to ask me any questions about it! ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">aukdWLSiernMAQh5MaRNy7</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/bwwoAnqrHxAbigpy8aiKhf-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 22 Jun 2026 17:02:43 +0000</pubDate>                                                                                                                                <updated>Tue, 23 Jun 2026 01:05:19 +0000</updated>
                                                                                                                                            <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                                    <dc:creator><![CDATA[ Jason England ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/v4fSq5U4uZUEtGY2BwNuJ6.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Jason brings a decade of tech and gaming journalism experience to his role as a Managing Editor of Computing at Tom&#039;s Guide. He has previously written for Laptop Mag, Tom&#039;s Hardware, Kotaku, Stuff and BBC Science Focus. In his spare time, you&#039;ll find Jason looking for good dogs to pet or thinking about eating pizza if he isn&#039;t already.&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/bwwoAnqrHxAbigpy8aiKhf-1280-80.jpg">
                                                            <media:credit><![CDATA[Valve]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Vale Steam Machine]]></media:description>                                                            <media:text><![CDATA[Vale Steam Machine]]></media:text>
                                <media:title type="plain"><![CDATA[Vale Steam Machine]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/bwwoAnqrHxAbigpy8aiKhf-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The <a href="https://www.tomsguide.com/gaming/pc-gaming/i-might-ditch-my-gaming-pc-for-the-steam-machine-heres-why">Steam Machine</a> is ready to preorder right now, and I will be getting one to review soon. But beyond my standard testing, I want to open the floor to any questions from you in a live Q&A.</p><p>Before we get to that, though, there are some other key questions we need to get to — namely, when you'll be able to buy one, and how much it will cost.</p><p>Spoiler alert on the latter: Steam Machine pricing starts at $1,049 (actually not as bad as I expected). But read on for all the information you need if you're keen to pick one up!</p><h2 id="when-is-the-steam-machine-launching">When is the Steam Machine launching?</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:3840px;"><p class="vanilla-image-block" style="padding-top:60.68%;"><img id="RzusMSoFqREVkoErH63pMN" name="SM_ledStrip" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/RzusMSoFqREVkoErH63pMN.jpg" mos="" align="middle" fullscreen="" width="3840" height="2330" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>Right now, you can <a href="https://store.steampowered.com/hardware/steammachine" target="_blank" rel="nofollow">sign up for the Steam Machine</a> model (or bundle) that you're interested in. You'll be placed into a reservation queue and notified via email when it's your turn to purchase — an action that looks set to stop bots and scalpers snagging them all.</p><p>The first batch of these emails will be sent starting <strong>Monday, June 29th.</strong></p><h2 id="how-much-will-steam-machine-cost">How much will Steam Machine cost?</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:970px;"><p class="vanilla-image-block" style="padding-top:56.19%;"><img id="MA5aScDQ8u3bGwd9LR6r2i" name="6n3Pfuz63A72YkUj99ydyd-970-80.pn" alt="Steam Machine seen by Tom's Hardware" src="https://cdn.mos.cms.futurecdn.net/MA5aScDQ8u3bGwd9LR6r2i.jpg" mos="" align="middle" fullscreen="" width="970" height="545" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Hardware)</span></figcaption></figure><p>This has been the big question here, and I've got all the details here. You'll be able to order the Steam Machine either on its own or as part of a bundle with the <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review">Steam Controller</a>.</p><ul><li><strong>Steam Machine 512GB: </strong>$1,049 / £879 / AU$1,609</li><li><strong>Steam Machine 512GB + Steam Controller: </strong>$1,128 / £938 / AU$ 1,728</li><li><strong>Steam Machine 2TB: </strong>$1,349 / £1,149 / AU$2,109</li><li><strong>Steam Machine 2TB + Steam Controller: </strong>$1,428 / £1,208 / AU$2,228</li></ul><p>It's also worth noting that the Steam Machine 2TB + Controller bundle also comes with two additional faceplates: red fabric and solid walnut.</p><h2 id="is-this-a-good-price-for-the-steam-machine">Is this a good price for the Steam Machine?</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:3840px;"><p class="vanilla-image-block" style="padding-top:60.68%;"><img id="KRxqrPisCWaFBibYdJNZCW" name="SM_powerButton" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/KRxqrPisCWaFBibYdJNZCW.jpg" mos="" align="middle" fullscreen="" width="3840" height="2330" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>Honestly, given the <a href="https://www.tomsguide.com/computing/ram-price-crisis-2026-everything-you-need-to-know">RAMageddon</a> fears we've all had, and how the <a href="https://www.tomsguide.com/gaming/handheld-gaming/steam-deck-oled-is-finally-back-in-stock-with-updated-pricing-you-are-not-going-to-like">huge Steam Deck price increase</a> terrified all of us, this price could have been a lot worse.</p><p>That being said, it's still pricey, and Valve is straight up about how this has "proven to be a weird time to launch hardware."</p><p>"We felt like we had a good understanding of how those costs might change over time when we first started sourcing them for Steam Machine back in 2023," Valve wrote in its blog post.</p><p>"Over the past year or so, that has changed quickly and significantly, most visibly for RAM and storage components." </p><p>Because of these, Valve confirms that the company's original price goal is "no longer viable," and that this total reflects "the price of components as we've secured them over the past 6 months."</p><p>That being said, though, they do also say that the availability of these precious components has "impacted the number of units" Valve has been able to produce for launch.</p><h2 id="any-further-questions">Any further questions?</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:3840px;"><p class="vanilla-image-block" style="padding-top:60.68%;"><img id="sJthZiHkM5CLN6Ur7BGtmE" name="SM_front_b" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/sJthZiHkM5CLN6Ur7BGtmE.jpg" mos="" align="middle" fullscreen="" width="3840" height="2330" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>So chances are, with that price, you've got some questions about whether it's worth it for you. I'm getting one to test (a 2TB model to be specific), and can answer any questions you have about the hardware.</p><p>I can run tests beyond any of our standard suite for you, give you general thoughts, or see how far I can push the hardware. Whatever you want me to do, just throw your questions in the Live Q&A box below, and I'll start responding after I've fully reviewed the hardware.</p><p>And of course, we want to keep this a friendly community chat with all the consumer advice you'll need. Please treat everyone (including yours truly) with respect and avoid any nasty language.</p><iframe class="position-center" data-lazy-priority="low" data-lazy-src=""></iframe><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/computing/hardware/no-one-has-a-crystal-ball-lexar-execs-have-a-plan-to-reduce-our-ram-dependency-if-the-ai-data-boom-lasts-for-years">'No one has a crystal ball': Lexar execs have a plan to reduce our RAM dependency if the AI data boom lasts 'for years'</a></li><li><a href="https://www.tomsguide.com/computing/laptops/i-just-held-the-future-of-laptop-memory-and-its-a-game-changer-i-traveled-to-china-to-see-how-its-made">I just held the future of laptop storage and it’s a game changer — I traveled to China to see how it's made</a></li><li><a href="https://www.tomsguide.com/gaming/handheld-gaming/i-did-not-say-its-coming-we-spoke-to-amd-vp-david-mcafee-about-bringing-fsr-4-to-ryzen-handhelds-to-catch-up-to-intel-arc-g3">'I did not say it's coming': We spoke to AMD VP David McAfee about bringing FSR 4.1 to Ryzen handhelds to catch up to Intel Arc G3</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Popular Steam app Wallpaper Engine hijacked to spread dangerous malware — how to stay safe ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/online-security/popular-steam-wallpaper-app-hijacked-to-spread-dangerous-malware-how-to-stay-safe</link>
                                                                            <description>
                            <![CDATA[ Hackers are exploiting Steam Workshop to hide malicious code inside community-made desktop themes for Wallpaper Engine, putting users at risk of account theft. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">FSnM8SDcLzFgRMCXHZ7K9K</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/fpSpYYb7kGr39ig4zytbaK-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 16 Jun 2026 22:17:10 +0000</pubDate>                                                                                                                                <updated>Thu, 18 Jun 2026 19:17:33 +0000</updated>
                                                                                                                                            <category><![CDATA[Online Security]]></category>
                                                    <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Internet]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ anthony.spadafora@futurenet.com (Anthony Spadafora) ]]></author>                    <dc:creator><![CDATA[ Anthony Spadafora ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/z73LEoj7FkUjNG85GcWHtH.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Anthony Spadafora is the managing editor for security and home office furniture at Tom’s Guide where he covers everything from data breaches and malware to password managers and the best way to cover your whole home or business with a strong Wi-Fi signal.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Before joining the team, he spent three years covering cybersecurity and B2B tech for ITProPortal while living in South Korea. After moving back to the US. Anthony joined the TechRadar Pro team where he covered these topics along with VPNs, web hosting, online collaboration software and video conferencing for four years. Anthony also has his ears to the ground and is on the lookout for the next major cyberattack or data breach.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Based in Houston, Texas, Anthony also handles VPN testing for both Tom’s Guide and TechRadar. As someone who has worked from home exclusively since 2018, he has reviewed dozens of standing desks as well as office chairs and has taken a closer look at other essential remote working accessories. As part of these reviews, Anthony frequently builds intricate desk setups which is why he’s such a big advocate for cable management and keeping things organized. When he’s not writing, he can be found tinkering with PCs and game consoles, managing cables and making upgrades to his smart home.&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/fpSpYYb7kGr39ig4zytbaK-1280-80.jpg">
                                                            <media:credit><![CDATA[Shutterstock]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A magnifying glass on top of the Steam logo in a web browser]]></media:description>                                                            <media:text><![CDATA[A magnifying glass on top of the Steam logo in a web browser]]></media:text>
                                <media:title type="plain"><![CDATA[A magnifying glass on top of the Steam logo in a web browser]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/fpSpYYb7kGr39ig4zytbaK-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Hackers are once again targeting gamers on Steam, but this time, instead of using <a href="https://www.tomsguide.com/computing/online-security/new-indie-game-found-spreading-malware-on-steam-how-to-see-if-your-pc-is-infected-and-what-to-do-next">malware-filled games</a> to do so, they’ve switched to hiding malicious code in desktop wallpapers.</p><p>As reported by <a href="https://www.bleepingcomputer.com/news/security/steam-workshop-abused-to-spread-malware-via-wallpaper-engine-app/" target="_blank">BleepingComputer</a>, these infected wallpapers can prove quite dangerous for unsuspecting gamers as they can provide an easy way to install a backdoor on one of the <a href="https://www.tomsguide.com/us/best-gaming-pc,review-2219.html">best gaming PCs</a> or even to hijack their Steam accounts.</p><p>Any image you download online could contain malware. However, the hackers behind this campaign are leveraging an incredibly popular Steam app to do so instead. With 20 to 50 million installs according to <a href="https://steamspy.com/dev/Wallpaper+Engine+Team" target="_blank">SteamSpy</a>, Wallpaper Engine is one of the most downloaded apps on the platform.</p><p>What makes <a href="https://www.tomsguide.com/opinion/i-test-oled-monitors-for-a-living-this-is-the-one-app-i-use-to-stop-burn-in">Wallpaper Engine</a> so popular, though, is that users can download hundreds of thousands of desktop wallpapers made by other users through Valve’s community hub, Steam Workshop. By abusing this feature, the hackers are easily able to disseminate their infected wallpapers.</p><p>Here’s everything you need to know about the latest malware threat on Steam and how you can keep your account — and your gaming PC — safe from hackers.</p><h2 id="malicious-application-wallpapers">Malicious application wallpapers</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="HCg23n6gHREqAwvUsogpeR" name="MSI MPG 321URXW QD-OLED-09" alt="Tilting the MSI MPG 321URXW QD-OLED monitor on its included stand" src="https://cdn.mos.cms.futurecdn.net/HCg23n6gHREqAwvUsogpeR.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>For those unfamiliar, in addition to static wallpapers, Wallpaper Engine also supports four dynamic wallpaper types that can render videos, interactive scenes, webpages with audio and video, and applications. That last one is incredibly important in this campaign.</p><p>Unlike a JPEG or PNG file, Wallpaper Engine’s application wallpapers are full-on Windows executables that run like any other program on your PC. According to researchers at the cybersecurity firm Kaspersky, not only do they pose a built-in security risk, but they’re also currently being used by hackers to deliver malware to unsuspecting Steam users.</p><p>In a <a href="https://securelist.com/dozens-of-malicious-wallpapers-found-on-steam-workshop/120186/" target="_blank">blog post</a>, Kaspersky’s researchers explained how they discovered dozens of malicious application wallpapers on Steam Workshop, many of which had been downloaded thousands or even tens of thousands of times. By analyzing the application wallpapers in question, the researchers found that the malware is either bundled directly into their installation packages or hidden inside password-protected archives that users are then tricked into opening. Unfortunately, the damage is done immediately after one of these compromised wallpapers is installed.</p><p>After a user installs one such asset posing as a game called NTRaholic, the wallpaper launches as expected. However, in the process, a <a href="https://www.tomsguide.com/computing/malware-adware/hackers-target-job-hunters-with-dangerous-new-windows-backdoor-how-to-stay-safe">backdoor file</a> belonging to the DarkKomet malware is also installed in the background. In order to search for and steal Steam credentials, a custom version of a system library called ‘AggregatorHost.dll’ is installed as well.</p><p>In addition to DarkKomet, Kaspersky’s researchers also found other malware families installed in these malicious wallpapers, like the <a href="https://www.tomsguide.com/news/hackers-are-tricking-discord-users-into-installing-malware-dont-fall-for-this">Lumma</a> and <a href="https://www.tomsguide.com/computing/malware-adware/12-million-people-fooled-by-fake-midjourney-facebook-page-used-to-spread-malware-dont-fall-for-this">Vidar</a> infostealers. They were even used to spread ransomware, too.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OzLJle"></div>                            </div>                            <script src="https://kwizly.com/embed/OzLJle.js" async></script><h2 id="how-to-stay-safe-from-malware">How to stay safe from malware</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="SS5Sx6xLmBVCxFLiCQytxQ" name="GettyImages-2160279257" alt="Computer security protection" src="https://cdn.mos.cms.futurecdn.net/SS5Sx6xLmBVCxFLiCQytxQ.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: Getty Images)</span></figcaption></figure><p>Fortunately, after Kaspersky alerted Valve about this campaign, all of the infected wallpapers in question were removed from the Steam Workshop. Still, this is an excellent reminder to always be careful when downloading files online, even if they come from a trusted platform.</p><p>In order to stay safe from any malware contained within desktop wallpapers, game mods, or games themselves, you definitely want to make sure your gaming PC is protected with the <a href="https://www.tomsguide.com/computing/antivirus/best-antivirus-software">best antivirus software</a>. If you want to be extra careful, you might also consider investing in one of the <a href="https://www.tomsguide.com/us/best-identity-theft-protection,review-2083.html">best identity theft protection services</a>. That way, if your credentials are compromised as a result of what you download online, you have a safety net to help monitor your data and recover financial losses from fraud.</p><p>When in doubt, stick to trusted creators when downloading new wallpapers and be extra cautious before running any executable on your gaming PC. This likely won’t be the last time hackers target Steam in their attacks, but Valve has an excellent track record of quickly responding to and dealing with malicious activity on its platform.</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/wellness/smart-rings/ultrahuman-data-breach-i-was-affected-and-here-is-exactly-what-hackers-stole-from-my-account">I just got hit by the Ultrahuman data breach — here's what hackers stole from my account</a></li><li><a href="https://www.tomsguide.com/computing/gpus/update-your-nvidia-gpu-drivers-now-to-protect-your-pc-from-9-high-severity-vulnerabilities-heres-whats-at-risk">Update your Nvidia GPU drivers now to protect your PC from 9 "high-severity" vulnerabilities — here's what's at risk</a></li><li><a href="https://www.tomsguide.com/gaming/handheld-gaming/asus-rog-xbox-ally-x20-hands-on-review">I just tried Asus’ upgraded Xbox Ally X20 for ROG’s 20th anniversary — and it isn’t just another special edition handheld</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Xbox Games Showcase 2026 — all the news, reveals, and announcements at Microsoft’s biggest gaming event of the year ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/news/live/xbox-games-showcase-2026-live-updates</link>
                                                                            <description>
                            <![CDATA[ Xbox Games Showcase returned for 2026, offering new reveals and trailers for some of the biggest upcoming games, including Fable 4, Gears of War: E-Day, Call of Duty Modern Warfare 4 and more. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">pxx48BQrf8Q9VvzdcApkMY</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ZG3KHPUnLcUkqhGjJpVBkB-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 07 Jun 2026 12:21:27 +0000</pubDate>                                                                                                                                <updated>Sun, 07 Jun 2026 18:46:11 +0000</updated>
                                                                                                                                            <category><![CDATA[Xbox]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                                    <dc:creator><![CDATA[ Alyse Stanley ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/BxNnQuBWRHqkv5xWZsjrjc.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Alyse Stanley is a news editor at Tom’s Guide, overseeing weekend coverage and writing about the latest in tech, gaming, and entertainment. Before Tom’s Guide, Alyse worked as an editor for the Washington Post’s sunsetted video game section, Launcher, where she also wrote about indie games you shouldn’t miss, how to tackle your gaming backlog, and all things Nintendo. She previously led Gizmodo’s weekend news desk covering breaking tech news and has written game reviews and features for outlets like Polygon, Unwinnable, and Rock, Paper, Shotgun. A recent Chicago-area transplant born and raised in Virginia, Alyse is a big fan of horror movies, cartoons, and roller skating. She&#039;s also a puzzle fan and can often be found contributing to the NYT Connections coverage on Tom&#039;s Guide &lt;/p&gt; ]]></dc:description>
                                                                                                        <dc:contributor><![CDATA[ Rory Mellon ]]></dc:contributor>
                                                                    <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/ZG3KHPUnLcUkqhGjJpVBkB-1280-80.jpg">
                                                            <media:credit><![CDATA[Microsoft]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Xbox Games Showcase keyart image with a &quot;Live&quot; badge underneath Xbox logo]]></media:description>                                                            <media:text><![CDATA[Xbox Games Showcase keyart image with a &quot;Live&quot; badge underneath Xbox logo]]></media:text>
                                <media:title type="plain"><![CDATA[Xbox Games Showcase keyart image with a &quot;Live&quot; badge underneath Xbox logo]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ZG3KHPUnLcUkqhGjJpVBkB-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>PlayStation has had its turn, and this weekend was time for Microsoft’s Xbox to take the spotlight. The Xbox Game Showcase 2026 promises the latest looks at upcoming games from Xbox Game Studios, alongside new reveals and trailers from some of the biggest franchises around. </p><p>The live-streamed event kicked off Sunday at <strong>10 a.m. PT / 1 p.m. ET / 6 p.m. BST</strong>, and if one Xbox gaming showcase wasn’t enough, it was immediately followed by the Gears of War: E-Day Direct, with plenty of new information on the upcoming shooter, which is set to release on October 6. Don’t worry if you couldn't watch; you can check out all the biggest announcements and reveal below. </p><p>Alongside Gears, we saw more from the new Fable game, a teaser for Persona 5, and Call of Duty: Modern Warfare 4 had a presence in a big way, as well as the Halo 1 remake. </p><h3 class="article-body__section" id="section-how-to-watch-xbox-games-showcase-2026"><span>How to watch Xbox Games Showcase 2026</span></h3><p><strong>Xbox Games Showcase 2026 + Gears of War: E-Day Direct takes place today (Sunday, June 7) at 10 a.m. PT / 1 p.m. ET / 6 p.m. BST</strong>. </p><p>You can watch the recording via <a href="https://www.youtube.com/user/xbox/hub" target="_blank" rel="nofollow">YouTube</a> or <a href="https://www.twitch.tv/xbox" target="_blank" rel="nofollow">Twitch</a>. </p><h3 class="article-body__section" id="section-live-updates"><span>LIVE UPDATES</span></h3><h2 id="welcome">Welcome!</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:809px;"><p class="vanilla-image-block" style="padding-top:56.37%;"><img id="ztD9L9fCjfUCfPmL5bJ3qd" name="xbox-logo-2" alt="Xbox logo" src="https://cdn.mos.cms.futurecdn.net/ztD9L9fCjfUCfPmL5bJ3qd.jpg" mos="" align="middle" fullscreen="" width="809" height="456" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Microsoft)</span></figcaption></figure><p>Good morning! Welcome to Tom's Guide's coverage of the Xbox Games Showcase 2026 + Gears of War: E-Day Direct (that's quite a mouthful). We'll have live updates covering all the new reveals and trailers in this live blog. If you're a passionate Xbox gamer, you won't want to miss this mammoth-sized live showcase. </p><h2 id="halo-campaign-evolved-screenshots-leaked">Halo: Campaign Evolved screenshots leaked</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:1591px;"><p class="vanilla-image-block" style="padding-top:56.00%;"><img id="EezZR3qYmZupsaCqA5mFCC" name="Screenshot 2026-06-07 074733" alt="A potential screenshot of Halo Campaign Evolved purportedly uploaded onto the Official Xbox Store page before it was taken down" src="https://cdn.mos.cms.futurecdn.net/EezZR3qYmZupsaCqA5mFCC.png" mos="" align="middle" fullscreen="" width="1591" height="891" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Reddit - tman2damax11)</span></figcaption></figure><p>There's been a surprising lack of leaks ahead of today's Xbox Games Showcase, but several screenshots of Halo: Campaign Evolved were captured on Xbox's official store page by some <a href="https://www.reddit.com/r/halo/comments/1txz5p3/new_campaign_evolved_screenshots_on_offical_xbox/" target="_blank" rel="nofollow">eagle-eyed Redditors</a> before being taken down. The screenshots give us a glimpse at Cortana's redesign, along with battles in space and redesigned brutes with beards. </p><h2 id="persona-6-debut">Persona 6 debut?</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="nd9dJHAZ725XoXfj3n7XtW" name="persona-4-golden-switch-key-art.jpg" alt="Persona 4 Golden keyart" src="https://cdn.mos.cms.futurecdn.net/nd9dJHAZ725XoXfj3n7XtW.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: Sega/Atlus)</span></figcaption></figure><p>Several leakers have suggested we could get a look at Persona 6 today, though with Atlus also expected to reveal a release date for Persona 4 Revival at the Xbox Games Showcase, I'm not too optimistic. Then again, that would be peak Atlus. </p><h2 id="don-t-expect-any-next-gen-console-news">Don't expect any next-gen console news</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="9CrPEvWMT7uSo2Df8jLCb4" name="TG_Xbox-Series-S_6.jpg" alt="Xbox Series S review" src="https://cdn.mos.cms.futurecdn.net/9CrPEvWMT7uSo2Df8jLCb4.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>Games will be front and center at today's presentation (it is all called the Xbox Games Showcase, after all). But if you were getting your hopes up about new details on Xbox's next-gen console, codenamed Project Helix, I'm here to dash those. </p><p>"The focus here is on the games," Microsoft Studios boss Matt Booty said on the latest Xbox podcast (h/t <a href="https://www.gamespot.com/articles/xbox-showcase-wont-have-next-gen-helix-news/" target="_blank">Gamespot</a>). "There won’t be Helix news. Helix will not be in this showcase. We want to get everything about that right."</p><h2 id="a-new-era-for-xbox">A new era for Xbox</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:66.67%;"><img id="4TEfwqu9hSy4uToJ2pRoDT" name="asha-sharma-matt-booty" alt="Asha Sharma, Xbox CEO" src="https://cdn.mos.cms.futurecdn.net/4TEfwqu9hSy4uToJ2pRoDT.jpg" mos="" align="middle" fullscreen="" width="1920" height="1280" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Microsoft)</span></figcaption></figure><p>The showcase will be the first under new CEO of Microsoft Gaming Asha Sharma, who took over for now-retired Xbox boss Phil Spencer in February. Though I don't have high hopes given the show's focus on games, I'd love to see her outline a clearer picture on Xbox's future. </p><p>Phil's vision of Xbox's next-gen console as a powerful PC-like machine for your living room sounds tailored toward a pretty niche audience, but with rising costs of, well, everything these days, more and more gamers are getting priced out. Will Xbox pivot to court a broader crowd or double down on what's rumors suggest could be a pricey next-gen console? </p><h2 id="viva-pinata-revival">Viva Piñata revival?</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="MfzFH53Lyf9DmE3VBYQ4f4" name="viva_pinata.jpg" alt="viva pinata" src="https://cdn.mos.cms.futurecdn.net/MfzFH53Lyf9DmE3VBYQ4f4.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: Rare)</span></figcaption></figure><p>It's a long shot, but given the recent success of <a href="https://www.tomsguide.com/gaming/pokemon-pokopia-review">Pokopia</a>, I'd love to see Xbox revive its Viva Piñata series. We haven't gotten a new game since Viva Piñata: Trouble in Paradise way back in 2008. Cozy games have only gotten more popular since then, and I say it's time to bring it back with more piñatas, bigger gardens, and modern controls. </p><h2 id="just-an-hour-to-go">Just an hour to go...</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:1463px;"><p class="vanilla-image-block" style="padding-top:56.19%;"><img id="BPMCHeUyeiLboyrWPkycAh" name="shutterstock_200244203.jpg" alt="Xbox press conference" src="https://cdn.mos.cms.futurecdn.net/BPMCHeUyeiLboyrWPkycAh.jpg" mos="" align="middle" fullscreen="" width="1463" height="822" 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>The Xbox Games Showcase is almost here! In a little over an hour, the livestreamed event will kick off, giving us our first look at games like State of Decay 3, Halo: Campaign Evolved, and new Fable and Call of Duty games. </p><h2 id="the-red-room-of-death">The red room of death</h2><div class="see-more see-more--clipped"><blockquote class="twitter-tweet hawk-ignore" data-lang="en"><p lang="en" dir="ltr">Tomorrow pic.twitter.com/yo7ITz5Bce<a href="https://twitter.com/cantworkitout/status/2063436867564184038">June 7, 2026</a></p></blockquote><div class="see-more__filter"></div></div><p>Yesterday Xbox CEO Asha Sharma <a href="https://x.com/asha_shar/status/2063436867564184038" target="_blank">shared a snapshot on X</a> of the in-person venue this year's showcase will take place at. It's giving off big "Twin Peaks" vibes to me. </p><h2 id="here-we-go">Here we go!</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:66.69%;"><img id="LJXjiq3GAJFvKccxRwNHmB" name="Xbox Games Showcase 26_BLOGHERO" alt="Xbox Games Showcase keyart image with a "Live" badge underneath Xbox logo" src="https://cdn.mos.cms.futurecdn.net/LJXjiq3GAJFvKccxRwNHmB.jpg" mos="" align="middle" fullscreen="" width="1600" height="1067" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Microsoft)</span></figcaption></figure><p>The Xbox Games Showcase is about to kick off! As a refresher for anyone just joining us, you can watch along via <a href="https://www.youtube.com/user/xbox/hub" target="_blank" rel="nofollow">YouTube</a> or <a href="https://www.twitch.tv/xbox" target="_blank" rel="nofollow">Twitch</a> when the event kicks off at the top of the hour. Gears of War: E-day will front and center, with its own Direct immediately following the showcase. Also expect to hear more about RPGs like Fable, Clockwork Revolution, and the Persona series as well as a statement of intent from Xbox's new leadership.</p><h2 id="new-gameplay-trailer-for-gears-of-war-e-day">New gameplay trailer for Gears of War: E Day</h2><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/y85lNvF3kVQ" allowfullscreen></iframe></div></div><p>I'm not surprised to see Xbox kick things off with gameplay footage of today's main event: Gears of War: E-Day. A lengthy shot of gameplay showed off combat as chaos erupts through the street. The carnage is every bit as gritty and bloody as expected of the series, complete with chainsaws galore. </p><h2 id="the-age-of-xbox-exclusives-continues">The age of Xbox exclusives continues</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:1024px;"><p class="vanilla-image-block" style="padding-top:66.70%;"><img id="kwJBZ2i4EdEyxmKQhN5hcS" name="asha-sharma-1024x683" alt="Asha Sharma, Xbox CEO" src="https://cdn.mos.cms.futurecdn.net/kwJBZ2i4EdEyxmKQhN5hcS.jpg" mos="" align="middle" fullscreen="" width="1024" height="683" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Microsoft)</span></figcaption></figure><p>The new CEO of Microsoft Gaming Asha Sharma revealed Xbox isn't done with console exclusives quite yet. After showing off some gameplay footage of Gears of War: E-Day, the exec announced it would be an Xbox exclusive when it comes out on October 6, 2026. Considering how many previously exclusive Xbox games have made their way to other consoles, it was unclear whether Xbox would continue making them or instead pivot to hedging its bets with wider releases. </p><h2 id="fable-revival-looks-promising">Fable revival looks promising</h2><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/3iW1i78zFvk" allowfullscreen></iframe></div></div><p>I love RPGs, but somehow never played the original Fable games so I wasn't too hyped for the series revival. After seeing the trailer, though, I'm excited. The writing made me laugh out loud, landing somewhere between Baldur's Gate 3 and Vox Machina with some well-placed F-bombs that actually landed rather than feeling forced. The combat looks stellar as well, with a weight that reminds me of the newer God of War games. Fable will hit store shelves on February 23, 2027. </p><h2 id="halo-gets-space-battles">Halo gets space battles</h2><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/G4sUx2nX5EQ" allowfullscreen></iframe></div></div><p>Three new missions are coming to Halo Campaign Evolved, the big remake of the first Halo, and Xbox showed off an exciting new addition in today's showcase: space flying missions and combat. The missions seem to be prequels to the original's campaign, with the voiceover promising a story "we haven't heard yet" that takes place "one year before the ring." Halo Campaign Evolved releases July 28, 2026. </p><h2 id="resonance-a-plague-tale-legacy-up-next">Resonance: A Plague Tale Legacy up next</h2><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/r0ufgnb1hWc" allowfullscreen></iframe></div></div><p>Resonance: A Plague Tale Legacy shifts the spotlight to Sophia in a prequel adventure. The combat and gameplay seems less horror and more Tomb Raider/Uncharted vibes with some of the ancient temples she's seen running through. It comes out August 27 across multiple platforms.</p><h2 id="persona-4-revival-takes-the-stage">Persona 4 Revival takes the stage</h2><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/1osdiOAkBKc" allowfullscreen></iframe></div></div><p>Take a trip to The Midnight Channel with our first real look at Persona 4 Revival. In the same vein as the Persona 3 Reload remake, the PS2 original looks way more detailed this time around with animated cut scenes, vibrant colors, and more detailed models. Atlus is also bringing over the Baton Pass mechanic from P3R for flashy, Persona 5-esque battles.</p><p>It's out Feb 18, 2027!</p><h2 id="build-your-cult-in-join-us">Build your cult in Join Us</h2><p>Join Us from Wolf Haus Games has the graphics and multiplayer havoc of GTA 6 with the premise of Cult of the Lamb, and I'm here for it. In either single player and 4-person co-op you build your cult and convert followers to your cause while surviving giant tentacle monsters emerging from the Earth and other apocalyptic scenarios. The voice acting is on point too: "You better evaluate your life choices." </p><h2 id="a-new-senua-game-on-the-horizon">A new Senua game on the horizon</h2><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/91LAY9B6lUc" allowfullscreen></iframe></div></div><p>We got a look at some of the combat and gameplay for the third game in the Senua series, simply titled Senua, that's coming out next year. The combat has always been on the floaty side, but her hits landed with a satisfying weight and there seems to be plenty of environmental tools you can use in group fights. The trailer showed her kicking over a burning effigy to scatter her opponents.  </p><h2 id="fallout-76-gets-some-new-goodies">Fallout 76 gets some new goodies</h2><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/sRra38_3WC8" allowfullscreen></iframe></div></div><p>Bethesda up now with a Fallout 76 update with a seriously catchy jingle. The new Infestations update, which is available now, adds plenty of new baddies to mow through with your friends. And is that new power armor I see? Nice!</p><h2 id="sega-s-crazy-taxi-revival-looks-sick">Sega's Crazy Taxi revival looks sick</h2><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/ePi8tDdKuWw" allowfullscreen></iframe></div></div><p>As soon as I heard that "yeah, yeah, yeah, yeah, yeah" I was sat up. Sega's long in development Crazy Taxi revival finally has a name and a slick new trailer. The gameplay footage showed off even more insane antics as players pick up customers and zip around the city. Crazy Taxi World Tour comes out in 2027 across PS5, Xbox, and PC. </p><h2 id="y-all-we-are-so-back">Y'all we are so back</h2><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/1-INYU6FLgI" allowfullscreen></iframe></div></div><p>Xbox showed off a new Xbox model for the company's 25th anniversary, with a Y2K style I've been chomping at the bit to come back: Those colored see-through casings that were everywhere in the early aughts. The limited edition Xbox Series X25 comes out in November 2026, and while it's not clear if it'll sport any new specs, they nailed the design. </p><h2 id="minecraft-dungeons-ii-gets-a-new-trailer">Minecraft Dungeons II gets a new trailer</h2><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/VyZKYhM0Kv4" allowfullscreen></iframe></div></div><p>Mojang Studios returns with its next Minecraft thing, showing off players fighting through dungeons together in a world of blocky, Minecraft-style visuals. Minecraft Dungeons 2 is coming September 29.</p><h2 id="the-thieves-guild-is-back">The Thieves Guild is back</h2><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/3uFptAC22iQ" allowfullscreen></iframe></div></div><p>Some Elder Scrolls news, though not Elder Scrolls 6. Rather, the series' MMORPG entry, The Elder Scrolls Online, is getting a thieves guild expansion that takes players to the high seas and underwater in a hunt for glorious loot. Also making an appearance was Sheogorath, the Daedric prince of madness, and it sure looks like he got transported to Skyrim. The update is coming out July 8. </p><h2 id="genderbent-castlevania-yes-please">Genderbent Castlevania, yes please</h2><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/I1YYTbciSD8" allowfullscreen></iframe></div></div><p>To celebrate Castlevania's 40th anniversary, we got a new look at Castlevania: Belmont's Curse, a new 2D entry in the series. It looks to be a substantial entry in the series, complete with a sprawling castle map and powers like gravity-flipping and jumping inside a painting. It's coming out October 15, 2026. </p><h2 id="persona-6-got-something">Persona 6 got...something</h2><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/9lwef2jan-Q" allowfullscreen></iframe></div></div><p>Persona 6 made an appearance at today's showcase, though hardly a substantial one. Instead of any gameplay or a look at the new cast of characters, we got another green-tinged teaser, this time of a graveyard and a couple of collages of people with cut-up pictures. I'm sure it'll all make more sense once Atlus releases the first batch of trailers, which may not be for a while considering we still don't have a release date. </p><h2 id="spyro-my-boy">Spyro, my boy!</h2><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/vHFW16_mDbo" allowfullscreen></iframe></div></div><p>Would you look at that, Spyro's getting a revival! I loved the games as a kid, and the trailer showed off the iconic purple dragon and some new flight-based gameplay. Spyro: A Realm Beyond takes flight in spring 2027. </p><h2 id="clockwork-revolution-confirmed-for-2027">Clockwork Revolution confirmed for 2027</h2><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/6B5NUd6B9I4" allowfullscreen></iframe></div></div><p>inXile's steampunk RPG Clockwork Revolution finally has a release window, and it's 2027. In today's showcase, we got a look at some of the game's core characters and first-person environments. Also: a heist plot! All signs point to it being another Xbox exclusive. </p><h2 id="new-look-at-cod-mw4">New look at CoD MW4</h2><p>Call of Duty Modern Warfare 4's new DMZ looks tense as hell, and the sound design is entirely too real in replicating bullets whizzing by your head. "Extract or die trying," we're reminded. CoD MW4 is out October 23 with an upcoming playtest set for July.</p><h2 id="onto-the-gears-of-war-e-day-direct">Onto the Gears of War: E-Day Direct</h2><p>Studio head Mike Crump welcomes us to the Coalition as the Gears of War presentation kicks off with a bloody countdown. So stay tuned to learn more about the long-awaited prequel. </p><h2 id="the-most-brutally-satisfying-gears-yet">'The most brutally satisfying Gears yet'</h2><p>The prequel heads back to Emergence Date, the catastrophic event that forever altered humanity’s fate and set the stage for the war-torn world players first encountered in the original game back in 2006. </p><p>Crump promises "the most brutally satisfying Gears yet." With the series leap to Unreal Engine 5, developer The Coalition revisited what made the series resonate in the first place. The team looked back to the iconic "Mad World" trailer for inspiration, seeing in it many of the themes that define the franchise. With the E-Day story, they saw it as the perfect chance to recapture that atmosphere with modern tech that finally allowed them to realize it on the scale they originally envisioned.</p><p>Built from the ground up, the game showcases seamless large-scale environments, ray-traced lighting, and real-time destruction for a dramatically reimagined look at the Gears universe while staying true to its roots.</p><h2 id="reimagined-combat-and-movement">Reimagined combat and movement</h2><p>The team overhauled the game's movement with smoother transitions, a larger range of cover, and the ability to jump to open up the citywide battleground. You have more choice than ever to tackle each combat puzzle, which can take place across neighborhoods and through multiple floors of buildings. The team built out an extensive tool set for making the world feel lived in too. </p><h2 id="e-holes-are-back">E holes are back</h2><p>The iconic emergence loop for spawning enemies, a core part of the Gears of War combat flow, returns in Gears of War: E-Day. Chippable cover across a range of textures also makes you feel like you're influencing the world. You'll watch "the fall of Kalona" in real time, and The Coalition demonstrated this with before and after shots of the destruction as the Locus overrun the city. </p><h2 id="a-look-at-gears-co-op">A look at Gears co-op</h2><p>All four characters are playable, with two-player split-screen available locally. In PvP, maps are designed to feel like classic battles, with the added bonus of new traversal modes to build on the game's revamped movement system. There's also Foreword siege, a 12-player mode that focuses on defending Kalona co-operatively.</p><h2 id="that-s-a-wrap">That's a wrap!</h2><p>The Xbox Games Showcase ended with a reel of everything we've seen throughout the show. What was your favorite announcement? Let us know in the comments!</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 'My wallet gonna cry': Valve gives official update on Steam Machine and Steam Frame launch, but still won't tell us the price ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/pc-gaming/my-wallet-gonna-cry-valve-gives-official-update-on-steam-machine-and-steam-frame-launch-but-still-wont-tell-us-the-price</link>
                                                                            <description>
                            <![CDATA[ Valve announces a Steam Machine and Steam Frame launch update the week of Summer Games Fest but neglects to mention pricing. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">nmB3gxrcjPTu36RNpVRkZ8</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/djtjcDyxp27vCNuxWeTJ8B-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 05 Jun 2026 10:12:50 +0000</pubDate>                                                                                                                                <updated>Fri, 05 Jun 2026 10:12:54 +0000</updated>
                                                                                                                                            <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></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.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/djtjcDyxp27vCNuxWeTJ8B-1280-80.jpg">
                                                            <media:credit><![CDATA[Valve]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Steam Machine ]]></media:description>                                                            <media:text><![CDATA[Steam Machine ]]></media:text>
                                <media:title type="plain"><![CDATA[Steam Machine ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/djtjcDyxp27vCNuxWeTJ8B-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Valve has officially confirmed the Steam Machine and Steam Frame devices will ship this summer, zeroing in on the launch of the highly-anticipated devices that has been <a href="https://www.tomsguide.com/gaming/valve-hope-to-ship-steam-machines-in-2026-but-memory-shortages-could-cause-delays">in flux since the start of the year</a>.</p><p>The company made the reveal in a <a href="https://steamcommunity.com/groups/steamworks/announcements/detail/716780409378048028" target="_blank">Steamworks post </a>saying it was expanding its Verified program to include the two upcoming devices.</p><p>"Today we are expanding the Verified program to include Steam Machine and Steam Frame, both of which are shipping this summer," the company wrote. </p><p>"As with Steam Deck Verified, the goal is to help customers understand the out-of-box experience for a given title on these new devices, and how smoothly a game will run with no user work or configuration required."</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="6xBrL6Zv4c8cVa3fWMuZtQ" name="image (1)" alt="Valve Steam Machine, Steam Frame, and Steam Controller devices" src="https://cdn.mos.cms.futurecdn.net/6xBrL6Zv4c8cVa3fWMuZtQ.png" 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: Valve)</span></figcaption></figure><p>Valve confirmed that Steam Machine's requirements are nearly identical to those of the Steam Deck, whilst the Steam Frame criteria is also similar. When it comes to Steam Frame, the "default graphics configuration needs to perform well, text and UI elements need to be clear and legible on the built-in display, and the default controller configuration needs to work well with the Steam Frame Controllers."</p><div class="product"><a data-dimension112="36a4cf01-8b79-4f12-8daf-bd701eab4d84" data-action="Deal Block" data-label="The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life." data-dimension48="The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life." data-dimension25="$99" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1232px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="p4kRCykqzQRFswEntyNcUE" name="Steam Controller" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/p4kRCykqzQRFswEntyNcUE.jpg" mos="" align="middle" fullscreen="" width="1232" height="1232" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life. <a class="view-deal button" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow" data-dimension112="36a4cf01-8b79-4f12-8daf-bd701eab4d84" data-action="Deal Block" data-label="The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life." data-dimension48="The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life." data-dimension25="$99">View Deal</a></p></div><p>Valve also said that games will be checked for Steam Machine and Steam Frame compatibility and both platforms will use a badge system similar to the Steam Deck. Gamers will be able to see at-a-glance if titles will run smoothly on each device. </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XYx9mO"></div>                            </div>                            <script src="https://kwizly.com/embed/XYx9mO.js" async></script><h2 id="the-question-remains-how-much-are-these-devices-going-to-cost">The question remains: how much are these devices going to cost?</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:2126px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="VN3tt97dHc9e3Hfpka2w7" name="Valve Steam FrameValve Steam Frame" alt="Person using Valve Steam Frame" src="https://cdn.mos.cms.futurecdn.net/VN3tt97dHc9e3Hfpka2w7.jpg" mos="" align="middle" fullscreen="" width="2126" height="1196" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>Valve may have confirmed we'll be getting these devices in the next couple of months, but the company still hasn't revealed just how much they'll cost. With the <a href="https://www.tomsguide.com/gaming/handheld-gaming/the-steam-deck-price-hike-and-msis-new-claw-8-ex-ai-best-buy-leak-are-just-more-evidence-that-handheld-pc-prices-are-out-of-control">current prices of PC gaming devices skyrocketing</a> due to the RAM crisis, it's probably the thing gamers want to know the most.</p><p>Some <a href="https://www.tomsguide.com/gaming/steam-machine-pricing-may-have-just-leaked-by-retailer-and-its-not-cheap">price leaks back in January</a> suggested between $900 and $1,100 for the different configurations of Steam Machine which would be a tough pill to swallow for a machine designed to compete with the Xbox and PS5. Costs have only gone up since January and Valve recently <a href="https://www.tomsguide.com/gaming/handheld-gaming/steam-deck-oled-is-finally-back-in-stock-with-updated-pricing-you-are-not-going-to-like">raised the price of the Steam Deck to compensate</a>.</p><p>Over on Reddit, the discussion over Valve's lack of clarity on the pricing is in full swing.</p><p>"Anything but release the prices," wrote Reddit user u/jjj44j, while others were under no illusion it's going to be costly. Redditor u/KingoKings365 wrote simply: "my wallet gonna cry" while user u/yeaaahwehere summed it up nicely: "just dipped into my child’s college fund 🙏 can’t wait for this"</p><blockquote class="reddit-card"  ><a href="https://www.reddit.com/r/steammachine/comments/1tx2ylh/steam_machine_and_frame_are_set_to_be_released">Steam Machine and Frame are set to be released this summer, Valve report today</a> from <a href="https://www.reddit.com/r/steammachine">r/steammachine</a></blockquote><script async src="//embed.redditmedia.com/widgets/platform.js" charset="UTF-8"></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/gaming/valve-hope-to-ship-steam-machines-in-2026-but-memory-shortages-could-cause-delays">Valve "hopes to ship" Steam Machines in 2026 but memory shortages could cause delays</a></li><li><a href="https://www.tomsguide.com/computing/peripherals/i-just-spent-48-hours-with-the-steam-controller-heres-my-honest-verdict">I just spent 48 hours with the Steam Controller — here's my honest verdict</a></li><li><a href="https://www.tomsguide.com/gaming/pc-gaming/i-might-ditch-my-gaming-pc-for-the-steam-machine-heres-why">I might ditch my gaming PC for the Steam Machine</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The MSI Claw 8 EX AI+ is the gaming handheld I’ve been waiting for — here’s why ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/handheld-gaming/the-msi-claw-8-ex-ai-is-the-gaming-handheld-ive-been-waiting-for-heres-why</link>
                                                                            <description>
                            <![CDATA[ Computex 2026 had a nice showing of upcoming gaming handhelds. While they were all great, this one stood out as the best of the best. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">j6g4xYfBXqkRbKS5KF33VP</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/4EcE3wi48qZ49YUev7cr2N-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 04 Jun 2026 11:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Handheld Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/4EcE3wi48qZ49YUev7cr2N-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Paul Antill holding the MSI Claw 8 EX AI+ up for the camera at Computex 2026]]></media:description>                                                            <media:text><![CDATA[Paul Antill holding the MSI Claw 8 EX AI+ up for the camera at Computex 2026]]></media:text>
                                <media:title type="plain"><![CDATA[Paul Antill holding the MSI Claw 8 EX AI+ up for the camera at Computex 2026]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/4EcE3wi48qZ49YUev7cr2N-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Despite the <a href="https://www.tomsguide.com/computing/ram-price-crisis-2026-everything-you-need-to-know">RAM crisis</a> driving up electronics prices, I’m still excited about the next generation of gaming handhelds. That’s especially true now, as <a href="https://www.tomsguide.com/computing/best-of-computex-2026">Computex 2026</a> has seen the announcement of three machines. I’m sure these systems will be expensive, especially as the <a href="https://www.tomsguide.com/opinion/steam-deck-oled-is-the-must-buy-handheld-of-2023-and-the-perfect-holiday-gift-for-gamers">Steam Deck OLED</a> now costs over $200 more than its original price. Still, I’m pretty stoked about what’s coming.</p><p>The headline systems are the <a href="https://www.tomsguide.com/gaming/handheld-gaming/msi-claw-8-ex-ai-plus-hands-on-review">MSI Claw 8 EX AI+</a> and the <a href="https://www.tomsguide.com/gaming/handheld-gaming/acer-predator-atlas-8-hands-on-review">Acer Predator Atlas 8</a>, both powered by the new <a href="https://www.tomsguide.com/gaming/handheld-gaming/intel-arc-g3-is-here-to-shake-up-handheld-gaming-and-amd-should-be-terrified-acer-predator-atlas-8-is-the-first-out-the-gate">Intel Arc G3</a> mobile chip. The <a href="https://www.tomsguide.com/gaming/handheld-gaming/asus-rog-xbox-ally-x20-hands-on-review">ROG Xbox Ally X20</a> is only a superficial upgrade, but a nice one regardless. While each system offers something different, there’s one that’s piqued my interest more than the others.</p><p>And which one is that? It’s the MSI Claw 8 EX AI+. Here’s why.</p><figure class="inline-layout"><fw-embed-feed channel="toms_guide" playlist="5qk1l7" mode="row" player_placement="bottom-right"></fw-embed-feed></figure><h2 id="smooth-performance">Smooth performance</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="36Gq3h5no9PDYNJSTBrGLc" name="MSI Claw 8 EX AI+" alt="MSI Claw 8 EX AI+" src="https://cdn.mos.cms.futurecdn.net/36Gq3h5no9PDYNJSTBrGLc.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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 original <a href="https://www.tomsguide.com/gaming/handheld-gaming/i-wanted-to-like-the-msi-claw-and-then-i-tested-it">MSI Claw 7</a> was the first modern gaming handheld to feature an Intel CPU rather than an AMD chip, so it’s good to see the latest iteration pack the new Intel Arc G3 processor.</p><p>This silicon is tailor-made for gaming, with fewer CPU cores but the same Arc B390 integrated GPU with 12 XeS cores. In short, it’s a serious gaming powerhouse.</p><div ><table><thead><tr><th class="firstcol " ><p>Game</p></th><th  ><p>Settings</p></th><th  ><p>Frames per second</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Hogwarts Legacy</strong></p></td><td  ><p>1200p Medium w/ray tracing - XeSS 3 balanced with MFG 4x</p></td><td  ><p>160 FPS</p></td></tr><tr><td class="firstcol " ><p><strong>Battlefield 6</strong></p></td><td  ><p>1080p High - XeSS 3 performance no MFG</p></td><td  ><p>65 FPS</p></td></tr><tr><td class="firstcol " ><p><strong>F1 25</strong></p></td><td  ><p>1200p High w/ ray tracing - XeSS 3 auto with MFG 4x</p></td><td  ><p>180 FPS</p></td></tr></tbody></table></div><p>We tested three games, and the results were impressive, to say the least. The frame boosting XeSS 3 is the key to fluid gameplay, as you can see above.</p><p>I’m eager to test demanding games like <a href="https://www.tomsguide.com/opinion/now-is-the-best-time-to-play-cyberpunk-2077">Cyberpunk 2077</a> to see how they run with XeSS on and off. Based on what we saw at Computex, I don’t expect to be disappointed.</p><h2 id="lovely-design">Lovely design</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ZwZTnFJaJabpwnJQBhKKV3" name="MSI Claw 8 EX AI+" alt="MSI Claw 8 EX AI+" src="https://cdn.mos.cms.futurecdn.net/ZwZTnFJaJabpwnJQBhKKV3.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>Based on what I’ve seen and what my colleagues have said, the MSI Claw 8 EX AI+ seems to nail the basics for handheld design. The main thing that stands out is that the new Claw is more rounded than its boxier predecessors, which should make it easier to hold. The Xbox controller-like texture should also help with sweaty hands from prolonged gaming sessions.</p><p>One major update is that the triggers and analog sticks all use Hall effect technology, which should make them more responsive and longer-lasting. There’s even a new 6-axis vibration motor that gives the device the same kind of rumble support you’d find on gaming controllers. As with the <a href="https://www.tomsguide.com/news/ps5-dualsense-controller">PS5 DualSense controller</a>, you’ll feel it when you walk on different surfaces. This is arguably the feature I want to experience most.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="EGbA6ZGrzCNRCp773Rci7c" name="MSI Claw 8 EX AI+" alt="MSI Claw 8 EX AI+" src="https://cdn.mos.cms.futurecdn.net/EGbA6ZGrzCNRCp773Rci7c.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>There’s no OLED panel, but the 8-inch 1200p IPS touch display with its up to 120Hz refresh rate should be great for just about any game. Eight inches is also a good spot that’s higher than the 7-inch display of a Steam Deck but not as gargantuan as the 8.8-inch panel of a <a href="https://www.tomsguide.com/gaming/handheld-gaming/lenovos-legion-go-2-is-my-most-anticipated-gaming-handheld-of-2025-but-this-one-thing-has-me-worried">Lenovo Legion Go</a>.</p><p>Lastly, the Claw 8 EX AI+ looks absolutely stunning in that Void Purple finish. I don’t typically care for purple, so this is high praise coming from me.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-O6jYVO"></div>                            </div>                            <script src="https://kwizly.com/embed/O6jYVO.js" async></script><h2 id="outlook-4">Outlook</h2><p>How much will the MSI Claw 8 EX AI+ cost? The good news is that it won’t be $2,000 as rumors have suggested. The bad news is that MSI says it is targeting $1,500. Sure, that’s not as expensive as two grand, but it would still make it as pricey as a desktop PC. Even if the price is worth it, that’s still a bitter pill to swallow.</p><p>Potential sticker shock aside, I like what I’ve seen of the MSI Claw 8 EX AI+ and am eager to test it out.</p><p>The MSI Claw series had a bumpy start with its first handheld, but each subsequent release has made major improvements, and the Claw 8 EX AI+ appears to be the culmination of the company’s persistence in delivering a truly stellar gaming device. If this handheld lives up to the hype, it should be worth considering, even if it costs a pretty penny.</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/computing/i-spoke-to-nvidia-ceo-jensen-huang-about-rtx-spark-he-is-willing-to-work-on-an-rtx-gaming-handheld-n2x-and-n3x-are-already-planned-and-the-chip-is-more-like-r2d2-than-a-laptop-cpu">I spoke to Nvidia CEO Jensen Huang about RTX Spark</a></li><li><a href="https://www.tomsguide.com/computing/laptops/nvidia-rtx-spark-hands-on-review">I just tested Nvidia RTX Spark laptops for video editing, gaming and AI</a></li><li><a href="https://www.tomsguide.com/computing/gaming-laptops/all-8-laptops-launching-with-nvidia-rtx-spark-this-fall-and-what-they-can-do">All 8 laptops launching with Nvidia RTX Spark this fall</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tried Asus’ upgraded Xbox Ally X20 for ROG’s 20th anniversary — and it isn’t just another special edition handheld ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/handheld-gaming/asus-rog-xbox-ally-x20-hands-on-review</link>
                                                                            <description>
                            <![CDATA[ Asus is celebrating the 20th anniversary of its gaming brand ROG in style with a special edition handheld and smart glasses. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">MJK3DRyiPsVJBYqSbRUK36</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Aaua9vNUGnxdB7TmiPFigZ-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 01 Jun 2026 09:59:52 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Handheld Gaming]]></category>
                                                    <category><![CDATA[Smart Glasses]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[VR &amp; AR]]></category>
                                                                                                <author><![CDATA[ anthony.spadafora@futurenet.com (Anthony Spadafora) ]]></author>                    <dc:creator><![CDATA[ Anthony Spadafora ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/z73LEoj7FkUjNG85GcWHtH.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Anthony Spadafora is the managing editor for security and home office furniture at Tom’s Guide where he covers everything from data breaches and malware to password managers and the best way to cover your whole home or business with a strong Wi-Fi signal.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Before joining the team, he spent three years covering cybersecurity and B2B tech for ITProPortal while living in South Korea. After moving back to the US. Anthony joined the TechRadar Pro team where he covered these topics along with VPNs, web hosting, online collaboration software and video conferencing for four years. Anthony also has his ears to the ground and is on the lookout for the next major cyberattack or data breach.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Based in Houston, Texas, Anthony also handles VPN testing for both Tom’s Guide and TechRadar. As someone who has worked from home exclusively since 2018, he has reviewed dozens of standing desks as well as office chairs and has taken a closer look at other essential remote working accessories. As part of these reviews, Anthony frequently builds intricate desk setups which is why he’s such a big advocate for cable management and keeping things organized. When he’s not writing, he can be found tinkering with PCs and game consoles, managing cables and making upgrades to his smart home.&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/Aaua9vNUGnxdB7TmiPFigZ-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Asus ROG Xbox Ally X20 with the special edition ROG Xreal R1 smart glasses]]></media:description>                                                            <media:text><![CDATA[The Asus ROG Xbox Ally X20 with the special edition ROG Xreal R1 smart glasses]]></media:text>
                                <media:title type="plain"><![CDATA[The Asus ROG Xbox Ally X20 with the special edition ROG Xreal R1 smart glasses]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Aaua9vNUGnxdB7TmiPFigZ-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>We’ve already seen a ton of new handheld gaming PCs here at <a href="https://www.tomsguide.com/tag/computex-2026">Computex 2026</a> but, instead of going that route, Asus has decided to commemorate the 20th anniversary of its Republic of Gamers (ROG) subbrand with a special edition of the <a href="https://www.tomsguide.com/gaming/handheld-gaming/rog-xbox-ally-x-review">ROG Xbox Ally X</a>.</p><p>Dubbed the ROG Xbox Ally X20, this new device uses (mostly) the same hardware as last year’s Xbox-themed handheld. You still get the powerful performance of AMD’s Ryzen AI Z2 Extreme chip with 24GB of RAM and a 1TB SSD. While not technically an entirely new device, Asus has made some fundamental changes under the hood and has also given the handheld a regal makeover with hints of gold throughout its design.</p><p>Asus definitely could have stopped there and called it a day. However, given the recent launch of its new <a href="https://www.tomsguide.com/computing/smart-glasses/asus-rog-xreal-r1-smart-glasses-hands-on">ROG XREAL R1 AR glasses</a>, the company decided to give them the same ROG 20th anniversary treatment too. They’re the same glasses more or less but since they’re intended to be used alongside the ROG Xbox Ally X20, they won’t ship with Asus’ <a href="https://www.tomsguide.com/computing/smart-glasses/asus-rog-xreal-r1-ar-glasses-hands-on-review">ROG Control Dock</a>.</p><p>After going hands-on with the new ROG Xbox Ally X20 and ROG Xreal R1 Edition 20 here in Taipei, I’m quite impressed by how all the little changes Asus made to its handheld make for an even better experience. However, are they enough to justify a bundle that will likely cost a hefty sum once it releases later this year? Find out in my full hands-on review.</p><h2 id="asus-rog-xbox-ally-x20-specs">Asus ROG Xbox Ally X20 specs</h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>11.5 x 4.8 x 2 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>1.66 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>CPU</strong></p></td><td  ><p>AMD Ryzen AI Z2 Extreme</p></td></tr><tr><td class="firstcol " ><p><strong>RAM</strong></p></td><td  ><p>24GB LPDDR5X</p></td></tr><tr><td class="firstcol " ><p><strong>Storage</strong></p></td><td  ><p>1TB PCIe Gen 4x4 SSD (upgradeable)</p></td></tr><tr><td class="firstcol " ><p><strong>Battery</strong></p></td><td  ><p>80 Wh</p></td></tr><tr><td class="firstcol " ><p><strong>Display</strong></p></td><td  ><p>7.4-inch FHD, 16:9, 120Hz refresh rate OLED panel with HDR1000 and AMD Fresync Premium Pro</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>1 x USB 4 Type-C, 1 x USB 3.2 Gen 2 Type-C, 1 x 3.5mm audio jack, 1 x microSD Express card reader slot</p></td></tr><tr><td class="firstcol " ><p><strong>Wireless connectivity</strong></p></td><td  ><p>Wi-Fi 6E, Bluetooth 5.4</p></td></tr></tbody></table></div><h2 id="fit-for-an-anniversary">Fit for an anniversary</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="4EYMPe4juaACZo4YVjzoVi" name="DSC05571.JPG" alt="The Asus ROG Xbox Ally X20 with the ROG Xbox Ally X behind it" src="https://cdn.mos.cms.futurecdn.net/4EYMPe4juaACZo4YVjzoVi.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>Just like Microsoft did with its 20th anniversary Xbox Controller, Asus has also given the ROG Xbox Ally X20 a transparent front shell. It looks even better in person and when seeing it side by side with the original Xbox Ally X, this small tweak really makes the upgraded handheld stand out. If that wasn’t enough though, the View, Command Center, Menu and Library buttons now feature gold accents.</p><p>In another nod to the Xbox brand, the Xbox button to the left of ROG Xbox Ally X20’s side buttons now lights up green too. Within Asus’ Armory Crate software, you can also tweak its brightness and lighting effects as well. Seeing the Xbox button pulse green was especially cool while trying out the new handheld.</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="j2pE8ByeyNxiVc4nD7gRb3" name="DSC05578.JPG" alt="The top ports on the Asus ROG Xbox Ally X20" src="https://cdn.mos.cms.futurecdn.net/j2pE8ByeyNxiVc4nD7gRb3.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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 the top edge of the ROG Xbox Ally X20, you still get two USB-C ports — one USB 4 one and one USB 3.2 one — along with a power button and a 3.5mm headphone jack. If you look closely though, you might notice an extra cooling vent between the main two on the left and right side. Asus reworked the cooling for the ROG Xbox Ally X20 to improve airflow which is why we now have four instead of three vents like on the Xbox Ally X.</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="LipeAVaKzAxMNcfRmNbXrB" name="DSC05589.JPG" alt="The backside of the Asus ROG Xbox Ally X20" src="https://cdn.mos.cms.futurecdn.net/LipeAVaKzAxMNcfRmNbXrB.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>Around back is where the ROG 20th Anniversary design changes are the most apparent on the Xbox Ally X20. In addition to a gold badge underneath the right fan, the diagonal line with “Republic of Gamers” written out is now gold too with the letters in a vibrant red. The top half of the back panel is transparent too which lets you see how Asus went to the extra trouble of making the ROG Xbox Ally X20’s fans and heatsink gold too.</p><p>Besides these aesthetic changes, the handheld’s grips are now wrapped in a grippy, rubber-like plastic too just like on the <a href="https://www.tomsguide.com/reviews/xbox-elite-wireless-controller-series-2">Xbox Elite Series 2 Controller</a>. This is another one of those small but very noticeable differences with the Xbox Ally X20. The upgraded handheld felt even better to hold in my hands, speaking of which…..</p><h2 id="upgrades-you-can-feel">Upgrades you can feel</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="gHGFeCcQosipdtARzmdJ4J" name="DSC05609.JPG" alt="A person playing the Asus ROG Xbox Ally X20" src="https://cdn.mos.cms.futurecdn.net/gHGFeCcQosipdtARzmdJ4J.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>As I’ve mentioned, small but noticeable improvements with a touch of gold throughout seems to be the big theme of the ROG Xbox Ally X20. This is also the case with the handheld’s bumpers and triggers. </p><p>Asus actually moved the position of the bumper buttons on the device’s motherboard to make them easier and more comfortable to press. While they used to sit on the top edge, they’re now positioned diagonally on the left and right side of the motherboard. This is a small change I know, but having tested the bumpers on both the Xbox Ally X and the ROG Xbox Ally X20 side by side, this tweak is noticeable.</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="maE5jXB7iaoLb5nfzZbFYQ" name="DSC05587.JPG" alt="A closeup shot of the buttons and joysticks on the Asus ROG Xbox Ally X20" src="https://cdn.mos.cms.futurecdn.net/maE5jXB7iaoLb5nfzZbFYQ.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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 shape and feel of the ROG Xbox Ally X20’s ABXY buttons are different too and they now feature a slightly more rounded profile. As you might have guessed, this is another nod back to the Xbox controller. One area where Asus is pushing ahead of Xbox though is with the joysticks on this handheld.</p><p>Although a lot of people kept asking about Hall Effect joysticks coming to its handhelds, Asus wasn’t quite happy with the tradeoffs that would come with adopting them. So instead, the company went with <a href="https://www.tomsguide.com/gaming/gaming-peripherals/so-long-hall-effect-im-only-using-controllers-with-tmr-sensors-from-now-on">TMR joysticks</a> on the ROG Xbox Ally X20. In my testing, they were incredibly smooth and responsive which makes me hope this will become the norm with PC gaming handhelds going forward.</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="M4uoajvNf4w88SMjXaWmTY" name="DSC05595.JPG" alt="A closeup shot of the bumpers, triggers and microSD Express card slot on the Asus ROG Xbox Ally X20" src="https://cdn.mos.cms.futurecdn.net/M4uoajvNf4w88SMjXaWmTY.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>Now you might have realized I skipped over the microSD card slot before when discussing the ports on the back of the ROG Xbox Ally X20. Well, that was intentional. You see, this is actually a <a href="https://www.tomsguide.com/gaming/nintendo/i-doubled-my-nintendo-switch-2-storage-for-just-usd36-all-thanks-to-this-budget-microsd-express-card">microSD Express</a> card slot like the one found on the Nintendo Switch 2. While you can upgrade the handheld’s internal storage, if you don’t want to open it up, you can always pop in a microSD Express card to get some more storage space and thanks to its faster speeds, you shouldn’t have any trouble playing even more demanding games off of it.</p><h2 id="transforming-with-a-twist">Transforming with a twist</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="qztehMTLF6kuqEukYP7u5i" name="DSC05556.JPG" alt="A peson using the new d-pad on the Asus ROG Xbox Ally X20" src="https://cdn.mos.cms.futurecdn.net/qztehMTLF6kuqEukYP7u5i.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>Now this next upgrade is one that both fighting game and Xbox 360 fans will instantly appreciate. While a 4-way d-pad is perfect for platformers and retro games, it isn’t ideal for 2D fighting titles like Street Fighter. With the ROG Xbox Ally X20, Asus said why not both. So just like on the wireless controller that was released quite late in the Xbox 360 era, this handheld also has a transforming d-pad. </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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="wDxMbH7UNbDXTiArGgXRK3" name="DSC05555.JPG" alt="Twisting the d-pad to change it from 4-way to 8-way on the Asus ROG Xbox Ally X20" src="https://cdn.mos.cms.futurecdn.net/wDxMbH7UNbDXTiArGgXRK3.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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 switch between the two modes, you just pinch both sides of the d-pad, pull up and give it a quick turn. This lets you go from a 4-way to an 8-way d-pad that feels almost identical to the one on the Xbox Series controller in the best way possible.</p><p>In case you pull up but don’t quite turn the d-pad all the way, you won’t be able to press it down at all which lets you know you did something wrong. Likewise, the d-pad spins all the way around, so you aren’t stuck going in one direction or the other.</p><h2 id="the-oled-we-ve-been-waiting-for">The OLED we’ve been waiting for</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="DYcwgJuAAN4jGeQjnxunp9" name="DSC05585.JPG" alt="Playing Cronos: The New Dawn on the Asus ROG Xbox Ally X20" src="https://cdn.mos.cms.futurecdn.net/DYcwgJuAAN4jGeQjnxunp9.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>Back when my colleague Jason England wrote his <a href="https://www.tomsguide.com/gaming/handheld-gaming/rog-xbox-ally-x-review#section-rog-xbox-ally-x-the-downs">ROG Xbox Ally X review</a>, one of his biggest gripes was that it didn’t have an OLED display. Well, Asus must have been listening as the ROG Xbox Ally X20 does and it’s a full-featured one at that. The handheld’s OLED features HDR 1000, comes equipped with VRR thanks to AMD FreeSync Premium Pro and can reach a max peak brightness of 1,400 Nits.</p><p>While we’ll have to get one into our testing lab to see for sure, in person, I noticed a stark difference between the brightness of the Xbox Ally X and the ROG Xbox Ally X20 with the two handhelds next to each other. When playing <a href="https://www.tomsguide.com/gaming/control-ultimate-edition-is-finally-coming-to-mac-and-i-couldnt-be-more-excited">Control </a>and <a href="https://www.tomsguide.com/gaming/cronos-the-new-dawn-is-the-spiritual-successor-to-dead-space-i-needed-this-halloween">Chronos: The New Dawn</a>, the blacks were quite deep and the colors really popped. However, it wasn’t until I saw the driving game <a href="https://www.tomsguide.com/gaming/this-racing-sim-rig-upgrade-has-saved-my-living-room-heres-how">Assetto Corsa</a> running on two devices side by side — one with HDR on and one with it off — that it really hit me.</p><p>Speaking of small but noticeable improvements once again, Asus actually managed to fit a larger 7.4-inch OLED screen here without increasing the overall size of the handheld. On the original Xbox Ally X, the bottom and top bezels were the same size. That isn’t the case with the ROG Xbox Ally X20 as Asus shrunk the top bezel to make room for the bigger display, making it smaller than the bezels on either side.</p><p>Personally, this was a huge improvement and quite noticeable during my hands on time with the device. For the most part when playing games on a handheld like this, you’re looking up at the top of the device and not the bottom, so the screen feels a lot larger even though the panel is still technically the same size.</p><h2 id="even-better-together">Even better together</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="eLeexSZGUhn6S5GFUfCmuX" name="DSC05582.JPG" alt="The Asus ROG Xbox Ally X20 with the ROG Xreal R1 special edition glasses" src="https://cdn.mos.cms.futurecdn.net/eLeexSZGUhn6S5GFUfCmuX.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>Now I know most people haven’t tried gaming while wearing a pair of the <a href="https://www.tomsguide.com/computing/vr-ar/best-smart-glasses">best smart glasses</a> but if you haven’t yet, it’s an awesome experience. Instead of a 7-inch display — or 7.4-inch one here — by plugging in a single USB-C cable, you instantly get a massive, movie theater-like screen right in front of you. </p><p>Asus and I must be on the same page which is why the company plans on releasing the ROG Xbox Ally X20 in a bundle with a special edition pair of its ROG Xreal R1 smart glasses. They’re mostly the same minus the dock and like the handheld, they have some gold accents on the sides. </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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="CdbwKeLURKUsyaMHKP7NZh" name="DSC05600.JPG" alt="A person playing the Asus ROG Xbox Ally X20 while wearing smart glasses" src="https://cdn.mos.cms.futurecdn.net/CdbwKeLURKUsyaMHKP7NZh.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>For those unfamiliar, using these — or any other AR glasses — with the ROG Xbox Ally X20 is about as plug and play of an experience as you can get. You just plug in the glasses on one of the top USB-C ports, put them on and you’re good to go. One cool use case a few of Asus’ staff and I discussed is wearing them while lying back in one of the <a href="https://www.tomsguide.com/best-picks/best-gaming-chairs">best gaming chairs</a> so you don’t run the risk of dropping a handheld on your face. I’ve played this way at home and trust me, it’s as comfortable as it is plain cool.</p><p>One neat difference here is that when you pair the ROG Xreal R1 X20 glasses with the ROG Xbox Ally X20 is that you don’t have to press the buttons on their sides to tweak picture settings. You absolutely can if you want to though. However, settings like screen size, transparency and even enabling real-time 3D conversion on the glasses are available right within Asus’ Armory Crate software. </p><p>I have to admit I stuck to making most of my adjustments on the glasses themselves as I’m quite familiar with Xreal’s AR glasses after I <a href="https://www.tomsguide.com/computing/i-ditched-my-laptop-for-a-pocketable-mini-pc-and-a-pair-of-ar-glasses-heres-what-happened">paired them with a portable mini PC</a> for a truly unique setup. However, if this is your first time using them, it will probably be easier making adjustments right on the handheld itself.</p><h2 id="this-bundle-won-t-come-cheap">This bundle won’t come cheap</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:6000px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="mzGWRxjFEyMo7UNPnXJTfM" name="DSC05575.JPG" alt="The Asus ROG Xbox Ally X20 with the special edition ROG R1 smart glasses" src="https://cdn.mos.cms.futurecdn.net/mzGWRxjFEyMo7UNPnXJTfM.jpg" mos="" align="middle" fullscreen="" width="6000" height="3376" 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>Asus gave myself and the rest of the Tom’s Guide computing team a sneak peak at the ROG Xbox Ally X20 at its HQ here in Taipei, with more details likely to come at Gamescom this summer. While we don’t know the official price yet, the ROG Xbox Ally X20 and ROG Xreal R1 X20 will likely be available ahead of the holidays later this year. </p><p>The other big news we got out of Asus is that the two will come as a bundle. Given the original ROG Xbox Ally X costs $999 on its own and the ROG Xreal R1 glasses are available now for $849, I doubt this special edition bundle will cost less than $2,000. However, since you aren’t getting the ROG Control Dock with the glasses, that could bring down the price slightly.</p><p>We’ll have the full pricing and release details soon enough but after spending an afternoon with the ROG Xbox Ally X20 and the ROG Xreal R1 X20, Asus went above and beyond here for sure. Just changing the color of the handheld’s shell and some of its buttons definitely would have been enough. However, Asus’ engineers went back to the drawing board and made seemingly small but very noticeable changes to the Xbox Ally X. </p><p>Now I wouldn’t recommend rushing out to get this bundle if you already have an Xbox Ally X unless you’re a really big ROG fan. Personally though, these improvements and tweaks have me really excited for what Asus will eventually do with its followup to the Xbox Ally and Xbox Ally X.</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/computing/keyboards/i-used-keychrons-new-split-mechanical-keyboard-for-a-week-and-its-tether-free-design-is-a-complete-game-changer">I used Keychron’s new split mechanical keyboard for a week and its tether-free design is a complete game changer</a></li><li><a href="https://www.tomsguide.com/computing/gpus/best-graphics-cards">Best graphics cards in 2026: I've tested every GPU to find the best bang for your buck</a></li><li><a href="https://www.tomsguide.com/gaming/playstation/i-fixed-my-biggest-gripe-with-the-ps5-pro-with-these-unofficial-cover-plates-and-now-it-looks-and-feels-more-like-a-pc">I fixed my biggest gripe with the PS5 Pro with these unofficial cover plates and now it looks and feels more like a PC</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tried the new Alienware 34 280Hz QD-OLED — and my favorite gaming monitor is better than ever ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/alienware-34-280hz-qd-oled-hands-on</link>
                                                                            <description>
                            <![CDATA[ The new Alienware 34 280Hz QD-OLED (AW3426DW) is an excellent upgrade to an already brilliant gaming monitor. Here are our hands-on impressions. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">BLikPLLU4eeHJzgyQ5ejSF</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/82cSzcb2sG9f78SSyKcF56-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 31 May 2026 23:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/82cSzcb2sG9f78SSyKcF56-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Alienware 34 AW3426DW]]></media:description>                                                            <media:text><![CDATA[Alienware 34 AW3426DW]]></media:text>
                                <media:title type="plain"><![CDATA[Alienware 34 AW3426DW]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/82cSzcb2sG9f78SSyKcF56-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Alienware 34 QD-OLED gaming monitor series has been my favorite ever since the first model launched in 2022. Now, it’s set to receive a new model later this year. While the Alienware AW3426DW isn’t a radical change from the past, it delivers meaningful upgrades for an even richer gaming experience.</p><p>Some enhancements include a higher refresh rate of 280Hz, up from the previous 240Hz. The display’s new 5-stack Penta Tandem tech helps deliver darker blacks in bright environments, higher peak brightness, and sharper text with no fringing. As before, the 34-inch curved display does an excellent job of immersing you in games.</p><p>The Alienware 34 AW3426DW has debuted at Computex, but I’m currently testing it at the office. My full review will come in due course, but for now, I want to outline the basics of what has a good shot at making our <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html">best gaming monitors</a> list. Here’s what I think of the AW3426DW.</p><h2 id="alienware-34-280hz-qd-oled-hands-on-specs">Alienware 34 280Hz QD-OLED hands-on: Specs</h2><div ><table><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>Alienware AW3426DW</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p>TBD</p></td></tr><tr><td class="firstcol " ><p><strong>Display</strong></p></td><td  ><p>34 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Resolution</strong></p></td><td  ><p>3440 x 1440</p></td></tr><tr><td class="firstcol " ><p><strong>Aspect ratio</strong></p></td><td  ><p>21:9</p></td></tr><tr><td class="firstcol " ><p><strong>Refresh rate</strong></p></td><td  ><p>280Hz</p></td></tr><tr><td class="firstcol " ><p><strong>Response time</strong></p></td><td  ><p>0.03ms</p></td></tr><tr><td class="firstcol " ><p><strong>Panel type</strong></p></td><td  ><p>QD-OLED</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>1x DisplayPort, 2x HDMI, 1x USB-A, 1x USB-B, 1x USB-C</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>32.05 x 14.23 x 4.38 inches (without stand)</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>17.95 pounds (with stand)</p></td></tr></tbody></table></div><h2 id="alienware-34-280hz-qd-oled-hands-on-display">Alienware 34 280Hz QD-OLED hands-on: Display</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:5326px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="yqhBJPXYWF2FT5LtiLHtye" name="Alienware 34 QD-OLED 2026-3" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/yqhBJPXYWF2FT5LtiLHtye.jpg" mos="" align="middle" fullscreen="" width="5326" height="2996" 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>Like previous models, the AW3426DW has an immersive 1800R curvature and a sharp 3,440 x 1,440 resolution. Yes, it’s not a 4K OLED panel, but everything looks bright and vibrant. And thanks to the cinematic 21:9 aspect ratio. If you’ll pardon the pun, it’s a sight to behold.</p><p>I tested <a href="https://www.tomsguide.com/reviews/cyberpunk-2077">Cyberpunk 2077</a> on the AW3426DW and was impressed by the rich picture quality. The greater contrast between dark and light elements is noticeable and makes colors feel more vibrant. That said, the standard picture mode isn’t as oversaturated as on other gaming monitors, which helps everything feel more realistic.</p><p>Naturally, I’ll need to test more games, and we need to run our display benchmarks to see what the AW3426DW can really do, but for now, I can say it delivers a superlative gaming experience.</p><h2 id="alienware-34-280hz-qd-oled-hands-on-design">Alienware 34 280Hz QD-OLED hands-on: Design</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:5609px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="mQXGfUW2X6zxSANXfyvZYR" name="Alienware 34 QD-OLED 2026-2" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/mQXGfUW2X6zxSANXfyvZYR.jpg" mos="" align="middle" fullscreen="" width="5609" height="3155" 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 Alienware AW3426DW has the same design as before, which I certainly won’t complain about because it’s both lovely and practical.</p><p>With its panel measuring 32.05 x 14.23 x 4.38 inches, you’ll need a decent-sized table for this beauty, but nothing overly large. The flat stand is pretty unintrusive, so it’s unlikely to get in the way of peripherals like your keyboard and mouse. The cutaway on the stand’s shaft makes cable management easy, and you can raise or lower the monitor to your desired height.</p><p>Again, I’m glad Alienware didn’t change the AW3426DW’s design, since it’s about as perfect as you can get. It might not immediately scream “gaming monitor,” but it keeps the focus on the display and, thus, on whatever game you’re currently playing.</p><h2 id="alienware-34-280hz-qd-oled-hands-on-performance">Alienware 34 280Hz QD-OLED hands-on: Performance</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:3632px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="TFv3c7xBzm337tLujZ4pRE" name="Alienware 34 QD-OLED 2026-1" alt="Alienware 34 AW3426DW" src="https://cdn.mos.cms.futurecdn.net/TFv3c7xBzm337tLujZ4pRE.jpg" mos="" align="middle" fullscreen="" width="3632" height="2043" 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>Performance gets a nice boost thanks to the higher 280Hz refresh rate and lower 0.03ms response time. And as before, compatibility with Nvidia G-Sync and AMD FreeSync also helps deliver a smooth gaming experience.</p><p>To test the AW3426DW, I connected it to the new <a href="https://www.tomsguide.com/computing/gaming-laptops/alienware-16-area-51-gaming-laptop-review">Alienware 16 Area-51</a> gaming laptop, which packs an Intel Core Ultra 9 290HX CPU, an Nvidia RTX 5080 GPU, and 32GB RAM. You won’t need such a beastly rig for this monitor, but it certainly helps.</p><p>Thanks to the high refresh rate and low latency, I had a smooth time playing Cyberpunk 2077. I couldn’t get the frame rate anywhere near the refresh rate, but having all that extra headroom effectively eliminated any choppiness. I also didn’t notice any input lag.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Wl3MDe"></div>                            </div>                            <script src="https://kwizly.com/embed/Wl3MDe.js" async></script><h2 id="alienware-34-280hz-qd-oled-hands-on-outlook">Alienware 34 280Hz QD-OLED hands-on: Outlook</h2><p>I’ll need more hands-on time with the Alienware AW3426DW, but for now, I can say it brings meaningful updates to an already fantastic gaming monitor.</p><p>Even if it gets outclassed by the new Alienware 39 5K OLED, it should still be an excellent option for those who want a smaller monitor with excellent features. Stay tuned for my 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/computing/monitors/i-checked-out-the-worlds-first-6k-gaming-monitor-and-its-a-sight-to-behold">I checked out the world’s first 6K gaming monitor — and it's a sight to behold</a></li><li><a href="https://www.tomsguide.com/computing/monitors/i-just-saw-lgs-worlds-first-1-000hz-gaming-monitor-in-person-and-my-eyes-couldnt-keep-up">I just saw LG’s 'world's first' 1,000Hz gaming monitor in person — and my eyes couldn’t keep up</a></li><li><a href="https://www.tomsguide.com/computing/microsoft-build-2026-preview">Microsoft Build 2026 preview — all the big announcements to expect</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 007 First Light is the best Bond game ever made — sorry, GoldenEye ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/007-first-light-review</link>
                                                                            <description>
                            <![CDATA[ In 007 First Light, IO Interactive has crafted a cinematic and thrilling espionage experience that stands as the best Bond release in almost two decades. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">UVM28tusL8fxYiG3vFZps</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/8xpj9DsBgYsZePPw5hMKWY-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 26 May 2026 20:10:57 +0000</pubDate>                                                                                                                                <updated>Tue, 26 May 2026 20:24:25 +0000</updated>
                                                                                                                                            <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ rory.mellon@futurenet.com (Rory Mellon) ]]></author>                    <dc:creator><![CDATA[ Rory Mellon ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/5Rv6LtQXMj5JB4Eu8Lt4Sn.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/8xpj9DsBgYsZePPw5hMKWY-1280-80.jpg">
                                                            <media:credit><![CDATA[IO Interactive]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[007 First Light]]></media:description>                                                            <media:text><![CDATA[007 First Light]]></media:text>
                                <media:title type="plain"><![CDATA[007 First Light]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/8xpj9DsBgYsZePPw5hMKWY-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <div  class="fancy-box"><div class="fancy_box-title">007 First Light review: Specs</div><div class="fancy_box_body"><p class="fancy-box__body-text"><strong>Platforms: </strong>PC, PS5 (reviewed), Xbox Series X/S<br><strong>Price: </strong>$69 / £59 / AU$99<br><strong>Release Date: </strong>May 27, 2026<br><strong>Genre:</strong> Action-adventure</p></div></div><p>007 First Light is a rare game that had me thinking, “I cannot wait to replay this” before my first run was even over. Developer IO Interactive has created the best James Bond game of all time. And yes, I’m fully aware that N64’s GoldenEye is a juggernaut of the shooter genre.</p><p>Anchored by a younger Bond, brilliantly brought to life by Patrick Gibson, First Light is the most essential piece of 007 media in two decades. Not since Daniel Craig first donned the tuxedo in 2006’s “Casino Royale” have I been this enamored with the spy espionage series. </p><p>By combining the blockbuster spectacle of games like <a href="https://www.tomsguide.com/reviews/nda-jan-26-10-am-est-uncharted-legacy-of-thieves-collection-review-the-first-must-own-ps5-game-of-2022">Uncharted</a> and the Tomb Raider reboot trilogy with the player freedom found in IO’s own <a href="https://www.tomsguide.com/gaming/nintendo/ive-played-8-nintendo-switch-2-launch-games-heres-the-best-one-you-probably-skipped-but-really-should-buy-now">Hitman: World of Assassination</a> series, 007 First Light offers a cinematic and gripping globe-trotting adventure. And while it modernizes the character in smart ways, it never loses classic James Bond’s soul in the process.</p><p>007 First Light is everything a Bond fan could want, and as somebody who has <a href="https://www.tomsguide.com/entertainment/netflix/netflix-just-added-all-26-bond-movies-heres-each-007s-best-film">seen all 26 of 007’s big-screen outings</a>, it’s something of a dream game for a longtime fan like me. There’s no question it’s a Game of the Year 2026 contender, and a game worth experiencing whether you’re a Bond veteran or a newcomer to the suave spy. Read on for my full 007 First Light review.</p><h2 id="007-first-light-the-basics">007 First Light: The Basics</h2><ul><li><strong>What is it?</strong> 007 First Light is a third-person action-adventure title that sees you play a young James Bond taking his first steps into the world of spycraft and international espionage.</li><li><strong>Who is it for? </strong>Bond fans couldn’t ask for more, but even newcomers looking for a thrilling and cinematic gaming experience will find themselves swept up in 007 First Light.</li><li><strong>What's the price? </strong><a href="https://www.amazon.com/007-First-Light-Specialist-PlayStation-5/dp/B0FBHCYKXX/" target="_blank" rel="nofollow">007 First Light costs $69 at Amazon</a>. Or you can spring for the pricy <a href="https://www.amazon.com/007-First-Light-Legacy-PlayStation-5/dp/B0FN6HPVRH" target="_blank" rel="nofollow">$299 Legacy Edition</a>, which includes a prop replica of the series iconic Golden Gun and some DLC goodies.</li><li><strong>What other games has the developer made?</strong> 007 First Light comes from IO Interactive, the creators of the popular Hitman series. The Danish developer also made Kane & Lynch and Mini Ninjas.</li><li><strong>What games is this similar to? </strong>Comparison to Uncharted is obvious, but 007 First Light also takes DNA from IO’s Hitman: World of Assassination series, combining the two into a supremely strong mix.</li></ul><h2 id="becoming-james-bond">Becoming James Bond</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:1024px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="AEzSaTkaXpfRFkwn4XhHbj" name="007 First Light" alt="007 First Light" src="https://cdn.mos.cms.futurecdn.net/AEzSaTkaXpfRFkwn4XhHbj.jpg" mos="" align="middle" fullscreen="" width="1024" height="576" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: IO Interactive)</span></figcaption></figure><p>Unlike the recent Daniel Craig-fronted movies, which largely presented Bond as a grizzled veteran, 007 First Light casts players as a fresh-faced spy. In fact, this spin on Ian Fleming’s character is so new to the world of espionage that he hasn’t even earned the 007 title yet.</p><p>The <a href="https://www.tomsguide.com/entertainment/movies/james-bond-casting-is-underway-but-who-do-you-think-should-play-the-next-007">search for the next big-screen Bond is underway</a>, but in the gaming space, IO has nailed the casting with Patrick Gibson, who provides his voice and mocaps the protagonist. Gibson’s Bond has all the hallmarks of the character — he’s charming, headstrong, and the right amount of arrogant — but he’s also a little naive and prone to overestimating his abilities.</p><p>The narrative setup is classic Bond fiction, with rogue agents, shadowy organizations, and world-ending stakes. Plus, 007 First Light’s 15-hour campaign takes you all over the world, from Slovakia to Malta, Iceland to Mauritania, and naturally, there are several levels set in London, England. This strong diversity of locales keeps the campaign exciting throughout.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="bSj9Dci8XztAKmNPsWEXob" name="007-first-light-screenshot-ps5-pro-08.JPG" alt="007 First Light screenshot taken on PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/bSj9Dci8XztAKmNPsWEXob.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: IO Interactive)</span></figcaption></figure><p>No Bond story would be complete without a suitably menacing villain, and while to reveal the ultimate big bad would be a spoiler, I’ll say First Light’s foe(s) are also excellent. Smartly, the story keeps these cards close to the chest, with the antagonist often shrouded in shadows. This makes the reveal of who is behind the conspiracy at the story's heart very satisfying.</p><p>First Light dedicates a surprising amount of time to scene-setting. After an exhilarating opening mission, you’ll spend a couple of hours with Bond in MI6 training. Rather than sap momentum, these intro sequences flesh out the supporting players (including Q, M, and Moneypenny), making me actually care about the larger cast, not just the star.</p><h2 id="tricks-of-the-spy-trade">Tricks of the spy trade</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5d6mLCJTRcwqbtn3rVmpTG" name="007 First Light" alt="007 First Light" src="https://cdn.mos.cms.futurecdn.net/5d6mLCJTRcwqbtn3rVmpTG.png" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>Actually playing 007 First Light is a joy. Levels typically see you starting in a larger hub-style area, looking to gain the intel necessary to enter restricted zones, where you need to sneak past hordes of guards. If you’re spotted? Time to break out the fists, or if the situation is truly dire (and Bond’s life is threatened), whip out a firearm, as you’re granted a License to Kill.</p><p>It’s no surprise that the stealth gameplay is superb. 007 First Light comes from the developer of Hitman, after all. You’re given plenty of options to avoid detention. Whether it’s using your Q-Watch to make a laptop short circuit, drawing attention away from your position, or making use of nausea-inducing darts hidden within a power bank.</p><p>Before each mission, you must select your gadgets, and while I did find a few more useful than others, it’s fun to experiment with the on-brand gizmos at your disposal.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="mk5qhJCfY5bcA9dtUDE4BD" name="007-first-light-screenshot-ps5-pro-04.JPG" alt="007 First Light screenshot taken on a PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/mk5qhJCfY5bcA9dtUDE4BD.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: IO Interactive)</span></figcaption></figure><p>As noted, when a fight breaks out, Bond first relies on his fists, and the brawls are a blast. The combat system takes inspiration from the Batman: Arkham series, with a focus on single-button counters, and the creative ways you can use your environment never get old. For example, if you’re fighting a thug next to a glass cabinet, Bond will smash the goon into it, dealing extra damage, and maybe even making you wince just a little bit.</p><p>Firefights are no less thrilling. Ammo counts are sparse, forcing you to move around the battlefield to pick up new weapons or gain a positional advantage. Each shootout feels like a real battle for survival. And it’s a small thing in the grand scheme, but 007 First Light has some of the most satisfying headshots in any third-person action game in recent memory. </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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="KsXZJ92oExYKsiq8qETudG" name="007 First Light" alt="007 First Light" src="https://cdn.mos.cms.futurecdn.net/KsXZJ92oExYKsiq8qETudG.png" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>007 First Light truly comes into its own when it combines these three gameplay states across levels. You’ll leap between stealth, hand-to-hand combat, and intense shootouts in a matter of minutes, and when you survive intact, you really do feel like a world-class superspy. Throw in a few high-speed car chases and a handful of fun but simplistic boss battles, and 007 First Light plays as good as it looks. And it looks pretty darn incredible!</p><h2 id="james-bond-crossed-with-agent-47">James Bond crossed with Agent 47</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="JzBNYmud4Ss7DjSRnDMhUD" name="007-first-light-screenshot-ps5-pro-05.JPG" alt="007 First Light screenshot taken on a PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/JzBNYmud4Ss7DjSRnDMhUD.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: IO Interactive)</span></figcaption></figure><p>While 007 First Light often funnels you down linear paths or into restrictive cinematic set pieces, IO Interactive hasn’t abandoned the open approach to level design seen in Hitman. This spin on Bond appears to have taken a leaf out of Agent 47's book!</p><p>Throughout the campaign, you are regularly dropped into small but dense sandboxes, given a task to complete, and it’s your job, as Bond, to figure out the best route forward. These include amassing enough money to buy your way into a criminal auction at a seedy market in Mauritania or gaining access to a locked CCTV room during a swanky gala at a London museum.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="usJtsoa8K7z7zREccxvjFD" name="007-first-light-screenshot-ps5-pro-01.JPG" alt="007 First Light screenshot taken on a PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/usJtsoa8K7z7zREccxvjFD.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: IO Interactive)</span></figcaption></figure><p>Objectives can be completed in multiple ways. Take, for example, the museum instance mentioned above. You could pose as a photographer to gain access to the upper balcony, or convince the security personnel you’re their no-show colleague, or you can just opt to pickpocket a keycard and sneak in via the back door. The choice is yours, and having so many options has me already itching to replay several levels to try different strategies.</p><p>These sections allow IO to flex some of its crowd technology muscles. The first open level is set in a dingy nightclub, and I spent several minutes marveling at how many NPCs were crammed onto the dance floor. I was even more impressed when I moved across the room, and each clubber responded with vague annoyance when my Bond bumped into them. </p><h2 id="more-cinematic-than-a-bond-movie">More cinematic than a Bond movie</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="R4HybTUdjTwwW5gLw3FBDD" name="007-first-light-screenshot-ps5-pro-02.JPG" alt="007 First Light screenshot taken on a PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/R4HybTUdjTwwW5gLw3FBDD.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: IO Interactive)</span></figcaption></figure><p>There’s no better way to describe 007 First Light than cinematic. Some levels ramp up the Blockbuster action to such a degree that they put Uncharted 2: Among Thieves to shame. One of my favorites feels like a winking tribute to “Casino Royale” as Bond runs along a skyscraper-sized construction crane while a rooftop sniper takes shots from down below.</p><p>Even when you think you’ve experienced the game’s biggest and best set-piece moment, another one comes along soon after. I must have declared “okay, <em>this </em>is my favorite level” more than half a dozen times across my playthrough. Ask me to pick the very best one, and I'd be here all day.</p><p>The game’s cinematic quality extends beyond set pieces as well. The appropriate mood is set right out of the gate with a phenomenal Bond theme performed by American singer Lana Del Rey, and that’s just the start of the epic musical score. Even the main menu gets you right into the Bond mood, with a bombastic orchestral track that is simply note-perfect.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="S3ChoHntMJWqM7f2arTqjb" name="007-first-light-screenshot-ps5-pro-07.JPG" alt="007 First Light screenshot taken on PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/S3ChoHntMJWqM7f2arTqjb.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: IO Interactive)</span></figcaption></figure><p>In fact, 007 First Light is so slick that the very few clumsy moments stick all the more. Transitions between cutscenes and gameplay don’t always flow smoothly, and there are a couple of needlessly harsh cuts, like a scene where Bond is being slowly lowered into a pit of man-eating crocodiles. An awkward cut to black sucks all the tension from this particular moment.</p><p>Nevertheless, these never amount to more than extremely minor blemishes. Overall, 007 First Light looks and sounds incredible with phenomenal visuals on <a href="https://www.tomsguide.com/gaming/playstation/ps5-pro-review">PS5 Pro</a> and first-class audio design throughout. </p><h2 id="007-first-light-review-verdict">007 First Light review: Verdict</h2><p>We’re currently enjoying an era of excellent licensed games, from <a href="https://www.tomsguide.com/reviews/hogwarts-legacy">Hogwarts Legacy</a> to <a href="https://www.tomsguide.com/gaming/indiana-jones-and-the-great-circle-review">Indiana Jones and the Great Circle</a>. Even with this strong competition raising the bar, 007 First Light stands out as perhaps <em>the</em> finest example of a popular movie series being converted into a video game.</p><p>Almost 30 years after the release of GoldenEye on the Nintendo 64, there is finally a James Bond game to rival that legendary title. 007 First Light is a first-class spy adventure with a gripping espionage story, cinematic gameplay, and a commitment to authenticity that will delight superfans. 007 First Light might just be the best Bond has ever been.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 7 Memorial Day gaming monitor deals worth your hard-earned cash ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/7-memorial-day-gaming-monitor-deals-worth-your-hard-earned-cash</link>
                                                                            <description>
                            <![CDATA[ Memorial Day is a perfect time to shop for a new gaming monitor. Here are some of the best deals we recommend right now. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">5DJyLFCxneswXWxjMwhich</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/xEQcVcLUZFuDGodzeeyFNX-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 25 May 2026 12:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/xEQcVcLUZFuDGodzeeyFNX-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Alienware AW3425DW deal]]></media:description>                                                            <media:text><![CDATA[Alienware AW3425DW deal]]></media:text>
                                <media:title type="plain"><![CDATA[Alienware AW3425DW deal]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/xEQcVcLUZFuDGodzeeyFNX-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>If you’re looking to upgrade your current gaming setup, you’re in luck, as <a href="https://www.tomsguide.com/sales-events/memorial-day-sales-2026">Memorial Day sales</a> are slashing prices on some of the best gaming monitors. Whether you’re looking for something compact or gargantuan, I’ve got you covered.</p><p>Some of the best deals I’ve found include the <a href="https://www.amazon.com/SAMSUNG-Adjustable-Equalizer-Flicker-Free-LS24DG302ENXZA/dp/B0D5ZKSR9C?tag=ftr-tomsguide-us-20&ascsubtag=tomsguide-us-1223270938789044487-20&geniuslink=true&th=1" target="_blank" rel="nofollow">Samsung 27-Inch Odyssey G3 for $189 at Amazon</a>, which is both affordable and great. The incredible <a href="https://www.amazon.com/Alienware-QD-OLED-Curved-Gaming-Monitor/dp/B0F6724X5N?th=1" target="_blank" rel="nofollow">Alienware 34-inch AW3425DW is currently $749</a>. If you want to go big, you can’t go wrong with the monstrous 49-inch <a href="https://www.amazon.com/dp/B0DHJBWY52?th=1" target="_blank" rel="nofollow">Samsung Odyssey OLED G9, which is on sale for $849</a>!</p><p>Here are the best gaming monitors I’d buy with my own money during Memorial Day. Also, be sure to check out our <a href="https://www.tomsguide.com/live/news/best-memorial-day-deals-2026-running-shoes-patio-furniture-tvs">Memorial Day sales live blog</a> to save on a variety of products.</p><h3 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h3><ul><li><strong></strong><a href="https://www.amazon.com/events/memorialdaysale" target="_blank" rel="nofollow"><strong>shop all Memorial Day sales at Amazon</strong></a><strong></strong></li><li><strong>Samsung 27" Odyssey G3: </strong><a href="https://www.amazon.com/SAMSUNG-Adjustable-Equalizer-Flicker-Free-LS24DG302ENXZA/dp/B0D5ZKSR9C" target="_blank" rel="nofollow"><strong>was $229 now $189 @ Amazon</strong></a></li><li><strong>Samsung 34" Odyssey G5: </strong><a href="https://www.amazon.com/SAMSUNG-34-Inch-Ultra-Wide-FreeSync-LC34G55TWWNXZA/dp/B08MVBYWGQ" target="_blank" rel="nofollow"><strong>was $399 now $279 at Amazon</strong></a></li><li><strong>Alienware 27" AW2725QF: </strong><a href="https://www.amazon.com/Alienware-AW2725QF-Monitor-27-Inch-3840x2160/dp/B0C1SDSYV6" target="_blank" rel="nofollow"><strong>was $589 now $431 @ Amazon</strong></a></li><li><strong>Alienware 34" AW3425DW: </strong><a href="https://www.amazon.com/Alienware-QD-OLED-Curved-Gaming-Monitor/dp/B0F6724X5N" target="_blank" rel="nofollow"><strong>was $799 now $749 @ Amazon</strong></a></li><li><strong>Samsung 49" Odyssey G9: </strong><a href="https://www.amazon.com/dp/B0DHJBWY52" target="_blank" rel="nofollow"><strong>was $999 now $849 @ Amazon</strong></a></li><li><strong>MSI 27" MPG 272URX QD-OLED: </strong><a href="https://www.amazon.com/MSI-MPG-272URX-QD-OLED-Adaptive-Synch/dp/B0DWYC5S8X" target="_blank" rel="nofollow"><strong>was $1,099 now $899 @ Amazon</strong></a></li><li><strong>Sony 27" Inzone M10S: </strong><a href="https://www.amazon.com/Sony-Compatible-DisplayHDR-Anti-Glare-DisplayPort/dp/B0D9R7HCVG" target="_blank" rel="nofollow"><strong>was $1,199 now $1,098 @ Amazon</strong></a></li></ul><h3 class="article-body__section" id="section-memorial-day-gaming-monitor-deals"><span>Memorial Day gaming monitor deals</span></h3><div class="product"><a data-dimension112="11db3247-3912-4038-bd83-fa106fb47936" data-action="Deal Block" data-label="This 27-inch Samsung monitor packs a lot of gamer-friendly features. You get AMD FreeSync support, 180Hz refresh rate, a response time of only 1ms and a “Virtual Aim Point” all make this extremely affordable monitor an enticing prospect for first-person shooter fans." data-dimension48="This 27-inch Samsung monitor packs a lot of gamer-friendly features. You get AMD FreeSync support, 180Hz refresh rate, a response time of only 1ms and a “Virtual Aim Point” all make this extremely affordable monitor an enticing prospect for first-person shooter fans." data-dimension25="$189" href="https://www.amazon.com/SAMSUNG-Adjustable-Equalizer-Flicker-Free-LS24DG302ENXZA/dp/B0D5ZKSR9C" 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="CKXyc9SjUi4eWWdakrzvt7" name="Samsung_Odyssey_G3.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CKXyc9SjUi4eWWdakrzvt7.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>This 27-inch Samsung monitor packs a lot of gamer-friendly features. You get AMD FreeSync support, 180Hz refresh rate, a response time of only 1ms and a “Virtual Aim Point” all make this extremely affordable monitor an enticing prospect for first-person shooter fans.<a class="view-deal button" href="https://www.amazon.com/SAMSUNG-Adjustable-Equalizer-Flicker-Free-LS24DG302ENXZA/dp/B0D5ZKSR9C" target="_blank" rel="nofollow" data-dimension112="11db3247-3912-4038-bd83-fa106fb47936" data-action="Deal Block" data-label="This 27-inch Samsung monitor packs a lot of gamer-friendly features. You get AMD FreeSync support, 180Hz refresh rate, a response time of only 1ms and a “Virtual Aim Point” all make this extremely affordable monitor an enticing prospect for first-person shooter fans." data-dimension48="This 27-inch Samsung monitor packs a lot of gamer-friendly features. You get AMD FreeSync support, 180Hz refresh rate, a response time of only 1ms and a “Virtual Aim Point” all make this extremely affordable monitor an enticing prospect for first-person shooter fans." data-dimension25="$189">View Deal</a></p></div><div class="product"><a data-dimension112="82739b57-7f0b-4475-bbd2-161a18c88605" data-action="Deal Block" data-label="It's hard to miss this ultra-wide curved Samsung Odyssey G5. It delivers a QHD (2560 x 1440) curved display with a 165Hz refresh rate and 1ms response time. For competitive shooters and graphically demanding games, this monitor will shine for its price." data-dimension48="It's hard to miss this ultra-wide curved Samsung Odyssey G5. It delivers a QHD (2560 x 1440) curved display with a 165Hz refresh rate and 1ms response time. For competitive shooters and graphically demanding games, this monitor will shine for its price." data-dimension25="$279" href="https://www.amazon.com/SAMSUNG-34-Inch-Ultra-Wide-FreeSync-LC34G55TWWNXZA/dp/B08MVBYWGQ" 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="5WBZ6LZzXByGrAmG4ycxhT" name="Samsung Odyssey G5 deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/5WBZ6LZzXByGrAmG4ycxhT.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>It's hard to miss this ultra-wide curved Samsung Odyssey G5. It delivers a QHD (2560 x 1440) curved display with a 165Hz refresh rate and 1ms response time. For competitive shooters and graphically demanding games, this monitor will shine for its price.<a class="view-deal button" href="https://www.amazon.com/SAMSUNG-34-Inch-Ultra-Wide-FreeSync-LC34G55TWWNXZA/dp/B08MVBYWGQ" target="_blank" rel="nofollow" data-dimension112="82739b57-7f0b-4475-bbd2-161a18c88605" data-action="Deal Block" data-label="It's hard to miss this ultra-wide curved Samsung Odyssey G5. It delivers a QHD (2560 x 1440) curved display with a 165Hz refresh rate and 1ms response time. For competitive shooters and graphically demanding games, this monitor will shine for its price." data-dimension48="It's hard to miss this ultra-wide curved Samsung Odyssey G5. It delivers a QHD (2560 x 1440) curved display with a 165Hz refresh rate and 1ms response time. For competitive shooters and graphically demanding games, this monitor will shine for its price." data-dimension25="$279">View Deal</a></p></div><div class="product"><a data-dimension112="7ffbc619-12f7-441a-a008-b6b4c16c07d4" data-action="Deal Block" data-label="Alienware AW2725QF review" data-dimension48="Alienware AW2725QF review" data-dimension25="$431" href="https://www.amazon.com/Alienware-AW2725QF-Monitor-27-Inch-3840x2160/dp/B0C1SDSYV6" 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="vZjj8V3h6yCS5Yqj57o3oj" name="Alienware AW2725QF deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/vZjj8V3h6yCS5Yqj57o3oj.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Here's an amazing 27-inch display from Alienware with dual resolutions! The AW2725QF offers 4K (3840 x 2160) with a 180Hz refresh rate and a FHD (1920 x 1080) mode with a whopping 360Hz refresh rate. That's hugely beneficial for fast-paced multiplayer titles<em> and </em>heavy-duty AAA PC games alike. We adored a similar monitor in our <a href="https://www.tomsguide.com/computing/monitors/alienware-27-4k-dual-resolution-gaming-monitor" data-dimension112="7ffbc619-12f7-441a-a008-b6b4c16c07d4" data-action="Deal Block" data-label="Alienware AW2725QF review" data-dimension48="Alienware AW2725QF review" data-dimension25="$431">Alienware AW2725QF review</a>, just be aware that there isn't an OLED option and this monitor will shine on your desk!<a class="view-deal button" href="https://www.amazon.com/Alienware-AW2725QF-Monitor-27-Inch-3840x2160/dp/B0C1SDSYV6" target="_blank" rel="nofollow" data-dimension112="7ffbc619-12f7-441a-a008-b6b4c16c07d4" data-action="Deal Block" data-label="Alienware AW2725QF review" data-dimension48="Alienware AW2725QF review" data-dimension25="$431">View Deal</a></p></div><div class="product"><a data-dimension112="91332206-17db-4e6a-860f-218a0ec4c039" data-action="Deal Block" data-label="Alienware AW3425DW" data-dimension48="Alienware AW3425DW" data-dimension25="$749" href="https://www.amazon.com/Alienware-QD-OLED-Curved-Gaming-Monitor/dp/B0F6724X5N" 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="38jxz6P5FvkBge6KVCnNNm" name="Alienware AW3425DW deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/38jxz6P5FvkBge6KVCnNNm.jpg" mos="" align="middle" fullscreen="" width="1500" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Any discount on the <a href="https://www.tomsguide.com/computing/monitors/alienware-aw3425dw-review" data-dimension112="91332206-17db-4e6a-860f-218a0ec4c039" data-action="Deal Block" data-label="Alienware AW3425DW" data-dimension48="Alienware AW3425DW" data-dimension25="$749">Alienware AW3425DW</a> is welcome, as it's just about one of the best curved gaming monitors we've tested. With its 34.2-inch WQHD (3440 x 1440) display with a 1800R curvature, 240Hz refresh rate and 0.03ms response time, you can expect streamlined design, vibrant image quality and ultra-smooth performance in any of the latest PC games around. <a class="view-deal button" href="https://www.amazon.com/Alienware-QD-OLED-Curved-Gaming-Monitor/dp/B0F6724X5N" target="_blank" rel="nofollow" data-dimension112="91332206-17db-4e6a-860f-218a0ec4c039" data-action="Deal Block" data-label="Alienware AW3425DW" data-dimension48="Alienware AW3425DW" data-dimension25="$749">View Deal</a></p></div><div class="product"><a data-dimension112="e43777c1-a643-4ae1-b528-9efab5b7971e" data-action="Deal Block" data-label="Samsung's amazing Odyssey OLED G9 curved gaming monitor extends 49 inches, taking your peripheral vision in games to a whole new level. It boasts G-Sync and AMD FreeSync Premium Pro compatibility, along with a 240Hz refresh rate." data-dimension48="Samsung's amazing Odyssey OLED G9 curved gaming monitor extends 49 inches, taking your peripheral vision in games to a whole new level. It boasts G-Sync and AMD FreeSync Premium Pro compatibility, along with a 240Hz refresh rate." data-dimension25="$849" href="https://www.amazon.com/dp/B0DHJBWY52" 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="QyY2MsHPmrHAqLMKX6mcPP" name="71s2+AY8C-L._AC_SL1500_" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/QyY2MsHPmrHAqLMKX6mcPP.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Samsung's amazing Odyssey OLED G9 curved gaming monitor extends 49 inches, taking your peripheral vision in games to a whole new level. It boasts G-Sync and AMD FreeSync Premium Pro compatibility, along with a 240Hz refresh rate.<a class="view-deal button" href="https://www.amazon.com/dp/B0DHJBWY52" target="_blank" rel="nofollow" data-dimension112="e43777c1-a643-4ae1-b528-9efab5b7971e" data-action="Deal Block" data-label="Samsung's amazing Odyssey OLED G9 curved gaming monitor extends 49 inches, taking your peripheral vision in games to a whole new level. It boasts G-Sync and AMD FreeSync Premium Pro compatibility, along with a 240Hz refresh rate." data-dimension48="Samsung's amazing Odyssey OLED G9 curved gaming monitor extends 49 inches, taking your peripheral vision in games to a whole new level. It boasts G-Sync and AMD FreeSync Premium Pro compatibility, along with a 240Hz refresh rate." data-dimension25="$849">View Deal</a></p></div><div class="product"><a data-dimension112="8eeca527-a800-48a4-9ad0-ef0c8acc23da" data-action="Deal Block" data-label="MSI MPG 272URX review" data-dimension48="MSI MPG 272URX review" data-dimension25="$899" href="https://www.amazon.com/MSI-MPG-272URX-QD-OLED-Adaptive-Synch/dp/B0DWYC5S8X" 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="rFrCdYdcaTzPfcK67PTWt8" name="MSI MPG 272URX QD-OLED" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/rFrCdYdcaTzPfcK67PTWt8.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>One of our favorite monitors we've tested, this 27-inch MSI MPG 272URX may be quite the mouthful, but it boasts some of the best visuals for productivity and gaming thanks to its QD-OLED panel. In our <a href="https://www.tomsguide.com/computing/monitors/msi-mpg-272urx-qd-oled-monitor-review" data-dimension112="8eeca527-a800-48a4-9ad0-ef0c8acc23da" data-action="Deal Block" data-label="MSI MPG 272URX review" data-dimension48="MSI MPG 272URX review" data-dimension25="$899">MSI MPG 272URX review</a>, we stated that we were mightily impressed with every color accuracy and its 4K resolution <em>with </em>a 240Hz refresh rate and 0.03 response rate. <a class="view-deal button" href="https://www.amazon.com/MSI-MPG-272URX-QD-OLED-Adaptive-Synch/dp/B0DWYC5S8X" target="_blank" rel="nofollow" data-dimension112="8eeca527-a800-48a4-9ad0-ef0c8acc23da" data-action="Deal Block" data-label="MSI MPG 272URX review" data-dimension48="MSI MPG 272URX review" data-dimension25="$899">View Deal</a></p></div><div class="product"><a data-dimension112="a03019bc-e9bc-4ab5-be16-60fdf6b8242d" data-action="Deal Block" data-label="The Sony Inzone M10S is Sony's elite-tier gaming monitor, aimed at aspiring or current esports players. It features a whopping 480Hz refresh rate, a 27-inch 1440p OLED panel, and a raft of features designed to help competitive players keep their edge." data-dimension48="The Sony Inzone M10S is Sony's elite-tier gaming monitor, aimed at aspiring or current esports players. It features a whopping 480Hz refresh rate, a 27-inch 1440p OLED panel, and a raft of features designed to help competitive players keep their edge." data-dimension25="$1098" href="https://www.amazon.com/Sony-Compatible-DisplayHDR-Anti-Glare-DisplayPort/dp/B0D9R7HCVG" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:466px;"><p class="vanilla-image-block" style="padding-top:69.53%;"><img id="ipW2NMKdzAC22GfziFNEiR" name="Inzone M10S" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ipW2NMKdzAC22GfziFNEiR.jpg" mos="" align="middle" fullscreen="" width="466" height="324" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Sony Inzone M10S is Sony's elite-tier gaming monitor, aimed at aspiring or current esports players. It features a whopping 480Hz refresh rate, a 27-inch 1440p OLED panel, and a raft of features designed to help competitive players keep their edge.<a class="view-deal button" href="https://www.amazon.com/Sony-Compatible-DisplayHDR-Anti-Glare-DisplayPort/dp/B0D9R7HCVG" target="_blank" rel="nofollow" data-dimension112="a03019bc-e9bc-4ab5-be16-60fdf6b8242d" data-action="Deal Block" data-label="The Sony Inzone M10S is Sony's elite-tier gaming monitor, aimed at aspiring or current esports players. It features a whopping 480Hz refresh rate, a 27-inch 1440p OLED panel, and a raft of features designed to help competitive players keep their edge." data-dimension48="The Sony Inzone M10S is Sony's elite-tier gaming monitor, aimed at aspiring or current esports players. It features a whopping 480Hz refresh rate, a 27-inch 1440p OLED panel, and a raft of features designed to help competitive players keep their edge." data-dimension25="$1098">View Deal</a></p></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just saw LG’s 'world's first' 1,000Hz gaming monitor in person — and my eyes couldn’t keep up ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/i-just-saw-lgs-worlds-first-1-000hz-gaming-monitor-in-person-and-my-eyes-couldnt-keep-up</link>
                                                                            <description>
                            <![CDATA[ I recently checked out the LG UltraGear 25G590B, which is marketed as the world's first native 1,000Hz FHD gaming monitor. Here are my initial impressions. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">WHstD6mUFtoJKhexLCKLaZ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/oeUdpUKDDWUdYWknBvHiJV-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 23 May 2026 06:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/oeUdpUKDDWUdYWknBvHiJV-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[LG UltraGear 25G590B]]></media:description>                                                            <media:text><![CDATA[LG UltraGear 25G590B]]></media:text>
                                <media:title type="plain"><![CDATA[LG UltraGear 25G590B]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/oeUdpUKDDWUdYWknBvHiJV-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I recently reviewed the <a href="https://www.tomsguide.com/computing/monitors/lg-ultragear-27gx790b-b-review">LG UltraGear 27GX790B-B</a>, which can hit a 720Hz refresh rate. I thought we couldn’t get higher than that, but LG decided that wasn’t enough and has now unveiled what it claims is the world’s first native 1,000Hz Full HD gaming monitor. No, that’s not a typo, my friends.</p><p>During a recent LG event, I got to see the new LG UltraGear 25G590B first-hand. While I wasn’t able to test any games on the prototype model, I did see a test pattern that demonstrated how much smoother things can run at 1,000Hz compared to lower refresh rates. I also learned about some of the AI features meant to provide a more immersive experience.</p><p>While I’m not the competitive gamer this monitor is designed for, I’m still impressed that it can hit such a lofty refresh rate. Here are my eyes-on impressions of the LG 25G590B.</p><h2 id="lg-ultragear-25g590b-hands-on-display-performance">LG UltraGear 25G590B hands-on: Display & performance</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:4285px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="FL3uQ9DoriFtRNSM92oLif" name="LG UltraGear 1000Hz gaming monitor-2" alt="LG UltraGear 25G590B" src="https://cdn.mos.cms.futurecdn.net/FL3uQ9DoriFtRNSM92oLif.jpg" mos="" align="middle" fullscreen="" width="4285" height="2410" 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>Most of LG’s recent UltraGear lineup comprises dual-mode monitors, but the 25G590B is 1,000Hz by default. The company told me that this lets players play (and compete) under consistent visual conditions. I take that to mean you won’t have to worry about the monitor's refresh rate when you're using it.</p><div><blockquote><p>I’m sure a eagle-eyed esports player could tell the difference between 1,000Hz and 720Hz, but I sure couldn’t. </p></blockquote></div><p>The test pattern I saw showed several slides running at different refresh rates. Naturally, 30Hz to 120Hz looked the choppiest compared to the higher refresh rates. However, all the slides moved very smoothly at 240Hz and up. I’m sure a eagle-eyed esports player could tell the difference between 1,000Hz and 720Hz, but I sure couldn’t. Regardless, I could still see that the 25G590B does indeed offer buttery smooth movement.</p><p>This monitor is best suited for first-person shooters like Counter-Strike and Call of Duty, where you need ultra-fast response times to survive. Despite the 1080p resolution, everything from in-game menus to interfaces comes through clearly, even if you’re moving fast in a game. That’s thanks to a new Motion Blur Reduction Pro technology (as LG calls it) that ensures fast-moving objects are sharp and easy to track.</p><p>LG says the 25G590B’s IPS panel has a low-reflection film meant to offer consistent color reproduction while reducing glare. There was a light directly above the monitor I was viewing, and I can confirm it didn’t significantly degrade the image quality. This is all meant to increase visibility across various in-game environments.</p><h2 id="lg-ultragear-25g590b-hands-on-design">LG UltraGear 25G590B hands-on: Design</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:5047px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="YU9NuG2AttaNzfK9JiWP34" name="LG UltraGear 1000Hz gaming monitor-LIST" alt="LG UltraGear 25G590B" src="https://cdn.mos.cms.futurecdn.net/YU9NuG2AttaNzfK9JiWP34.jpg" mos="" align="middle" fullscreen="" width="5047" height="2839" 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 25G590B has a 24.5-inch FHD panel. As I was told, this is the size professional gamers prefer because it lets them see everything on the screen without moving their heads.</p><p>Design-wise, LG has kept things simple and efficient. For instance, the stand’s base has a small footprint, so you have more room to move your mouse. There are even calibration indicators on the stand to let you adjust the height, swivel, and tilt settings. This way, you can achieve an optimal viewing angle.</p><p>The main embellishment is on the back, with a nifty UltraGear Logo that creates ambient illumination. I wasn’t able to test this at the event, but if this is like other UltraGear monitors I’ve reviewed, you’ll be able to customize the RGB lighting to your liking.</p><h2 id="lg-ultragear-25g590b-hands-on-ai-features">LG UltraGear 25G590B hands-on: AI features</h2><p>The LG 25G590B boasts AI features, such as AI Scene Optimization, which adjusts picture quality to suit different game genres. We didn’t get to see this feature in action, but one of the slides showed how AI is used to improve image quality and clarity. Given how this is a 1080p display, this seems like a smart feature.</p><p>Then there’s AI Sound, which will apparently create spatial audio and deliver clearer in-game communications when used with compatible headsets. Sound is almost as important as visuals in fast-paced first-person shooting games, so it’s good to know LG has taken that into account for a competitive-focused gaming monitor.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Wl3Nje"></div>                            </div>                            <script src="https://kwizly.com/embed/Wl3Nje.js" async></script><h2 id="lg-ultragear-25g590b-hands-on-outlook">LG UltraGear 25G590B hands-on: Outlook</h2><p>I’ll need to test the LG UltraGear 25G590B myself to see if the insane 1,000Hz is more than just tech flexing. Now that LG has taken the refresh rate wars to literal new heights, it’ll be interesting to see if competitors follow suit.</p><p>The LG UltraGear 25G590B should launch in the second half of 2026 in select markets. Let us know in the comments if you would want a 1,000Hz monitor or if you think it's overkill. </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/computing/macbooks/i-was-worried-the-macbook-pro-oled-might-get-delayed-but-a-new-report-gives-me-hope-for-a-timely-release">New report gives me hope that the MacBook OLED won't get delayed</a></li><li><a href="https://www.tomsguide.com/gaming/assassins-creed-black-flag-resynced-hands-on-preview">I played 3 hours of Assassin's Creed Black Flag Resynced</a></li><li><a href="https://www.tomsguide.com/computing/monitors/i-checked-out-the-worlds-first-6k-gaming-monitor-and-its-a-sight-to-behold">I checked out the world’s first 6K gaming monitor — and it's a sight to behold</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I checked out the world’s first 6K gaming monitor — and it's a sight to behold ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/i-checked-out-the-worlds-first-6k-gaming-monitor-and-its-a-sight-to-behold</link>
                                                                            <description>
                            <![CDATA[ The 32-inch Samsung Odyssey G8 (G80HS) impresses with its vibrant, sharp 6K resolution and fluid performance. Here are our initial hands-on thoughts. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">pjCafWXTFm8k8fTxTjsEra</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/p7yT4HB4XVZUYPhDXaS4th-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 21 May 2026 11:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/p7yT4HB4XVZUYPhDXaS4th-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Samsung Odyssey G8 (G80HS)]]></media:description>                                                            <media:text><![CDATA[Samsung Odyssey G8 (G80HS)]]></media:text>
                                <media:title type="plain"><![CDATA[Samsung Odyssey G8 (G80HS)]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/p7yT4HB4XVZUYPhDXaS4th-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Samsung Odyssey G8 (G80HS) is the world’s first 6K gaming monitor, according to Samsung. While this 32-inch monitor focuses on high pixel counts, it also has two refresh rates that favor cinematic or competitive gaming.</p><p>I recently went hands-on with the G80HS at a Samsung event, and was stunned by the sharp picture quality it delivered in both its 6K 165Hz and 3K 330Hz display modes. Not only that, but the vibrant colors and smooth performance made me demo the monitor longer than I typically would. It’s a thing of beauty.</p><p>Though it doesn’t have an OLED panel, its ultra-sharp resolution and immersive 32-inch canvas make for a fun gaming experience. Here’s what I think of the Samsung Odyssey G8 (G80HS).</p><h2 id="samsung-odyssey-g8-g80hs-hands-on-display">Samsung Odyssey G8 (G80HS) hands-on: Display</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="VfU7Epbsk6PSKUQCHbcp3o" name="Samsung Odyssey G8 (G80HS) 6K gaming monitor-6" alt="Samsung Odyssey G8 (G80HS)" src="https://cdn.mos.cms.futurecdn.net/VfU7Epbsk6PSKUQCHbcp3o.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>Naturally, the 6K resolution is the main draw here. And I have to say, it’s not just number-flexing.</p><p>When I played <a href="https://www.tomsguide.com/opinion/now-is-the-best-time-to-play-cyberpunk-2077">Cyberpunk 2077</a> on the Odyssey G8, I purposely focused on buildings in the distance. Despite being so far away, I could make out the individual windows and even the dirt around the building’s facade. Of course, objects in the foreground, like the car and the grimy streets I rode across, also came to life in stunning detail.</p><p>3K resolution is just slightly less detailed than 6K, but no less stunning. I’m used to 1440p monitors, so the step up from that is noticeable, even if it's not as sharp as 4K. I could tell the immediate difference when I switched between 3K and 6K modes. However, you’re not getting a diminished viewing experience with either mode.</p><p>We’d need to get the Odyssey G8 in for testing, but to my eyes, everything looked bright and colorful on the 32-inch display. I don’t know which display mode it was set to, but the colors didn’t appear overly saturated. Despite this not being an OLED panel, you still get excellent overall picture quality.</p><h2 id="samsung-odyssey-g8-g80hs-hands-on-performance">Samsung Odyssey G8 (G80HS) hands-on: Performance</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="36ftcppXcJ29QHwYACuxV7" name="Samsung Odyssey G8 (G80HS) 6K gaming monitor-3" alt="Samsung Odyssey G8 (G80HS)" src="https://cdn.mos.cms.futurecdn.net/36ftcppXcJ29QHwYACuxV7.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><a href="https://www.tomsguide.com/computing/monitors/at-this-level-those-numbers-arent-for-us-gamers-why-720hz-gaming-monitors-might-be-overkill">Dual-mode gaming monitors</a> are all the rage these days, and the Odyssey G8 follows suit with its two refresh rates.</p><p>6K resolution gives you 165Hz, while 3K mode bumps that to 330Hz. 6K 165Hz mode is ostensibly for “cinematic” games like Cyberpunk 2077 and <a href="https://www.tomsguide.com/reviews/ghost-of-tsushima">Ghost of Tsushima</a>, where you’d want the very best picture quality. Conversely, competitive gamers who need faster performance can flip over to 3K 330Hz. In this way, the G80HS is basically two gaming monitors in one.</p><p>Since I’m not a competitive gamer, I couldn’t notice a huge difference between the modes in terms of performance. However, I’m sure hawk-eyed Esports players will notice the difference right away. Regardless, both modes feel incredibly smooth and responsive.</p><h2 id="samsung-odyssey-g8-g80hs-hands-on-design">Samsung Odyssey G8 (G80HS) hands-on: Design</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="FMkdn9jVegX8jXpKvL38gC" name="Samsung Odyssey G8 (G80HS) 6K gaming monitor-5" alt="Samsung Odyssey G8 (G80HS)" src="https://cdn.mos.cms.futurecdn.net/FMkdn9jVegX8jXpKvL38gC.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 G80HS has the familiar design of the Odyssey series, with its sharp angles and relatively dark color way. Besides the display, the only other light source is the RGB ring around the monitor stand, which creates a nice glow when the monitor is close to a wall.</p><p>Other features include a flat stand that doesn’t get in the way of your peripherals, and easy access to the ports on the back. I was also able to raise, lower, and tilt the monitor to my liking.</p><p>Overall, this is a nice and practical design that keeps the focus on the game you’re playing.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-e4MwbW"></div>                            </div>                            <script src="https://kwizly.com/embed/e4MwbW.js" async></script><h2 id="samsung-odyssey-g8-g80hs-hands-on-outlook">Samsung Odyssey G8 (G80HS) hands-on: Outlook</h2><p>Right now, the Samsung Odyssey G8 (G80HS) isn't yet available to purchase. However, it should cost around $1,600 on <a href="https://www.samsung.com/latin_en/monitors/gaming/odyssey-g8-g80hs-32-inch-dual-mode-6k-165hz-3k-330hz-ls32hg802esxza/" target="_blank" rel="nofollow">Samsung's online store</a>. That's not cheap, but for what it offers, it could be worth it for you.</p><p>I’ve tested a lot of the <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html">best gaming monitors</a> over the years, so it’s nice to have the Samsung Odyssey G8 G80HS flip the script by featuring a 6K resolution. That might sound ludicrous (and perhaps it is), but there’s no denying that it can offer a truly rich viewing experience.</p><p>I can’t yet say whether this should be the new standard, but it’s certainly impressive. I should have a full review of the Samsung Odyssey G8 (G80HS) soon, so stay tuned for more!</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/computing/laptops/the-new-microsoft-surface-laptop-8-is-great-but-its-hard-to-recommend-to-most-people">The new Microsoft Surface Laptop 8 is great but it's hard to recommend</a></li><li><a href="https://www.tomsguide.com/gaming/lego-batman-legacy-of-the-dark-knight-review">Lego Batman: Legacy of the Dark Knight is my new favorite Lego game</a></li><li><a href="https://www.tomsguide.com/computing/laptops/googlebooks-vs-chromebooks">Googlebooks vs. Chromebooks: Biggest differences explained</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I found 12 must-have PC gaming accessories for building the ultimate setup ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/pc-gaming/i-found-12-must-have-pc-gaming-accessories-for-building-the-ultimate-setup</link>
                                                                            <description>
                            <![CDATA[ It's all fair and well buying the PC to game on, but what about the accessories? Here's my top 12 picks I recommend for creating your at-home setup. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">9HoYWiBuh8GeDpPCXK8LgA</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ezJYEgtPHyyW4UoGnTvu43-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 19 May 2026 11:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                                    <dc:creator><![CDATA[ Grace Dean ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oxXqkks7wgxZkPiyYY2n6H.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/ezJYEgtPHyyW4UoGnTvu43-1280-80.jpg">
                                                            <media:credit><![CDATA[Amazon / Edited by Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A gaming chair, keyboard and pair of headphones on a purple background]]></media:description>                                                            <media:text><![CDATA[A gaming chair, keyboard and pair of headphones on a purple background]]></media:text>
                                <media:title type="plain"><![CDATA[A gaming chair, keyboard and pair of headphones on a purple background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ezJYEgtPHyyW4UoGnTvu43-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>This year, I bought a new PC, specifically for gaming. A huge investment and one that took <em>a lot</em> of extensive research because, quite honestly, I didn't know what I needed. I didn't want to build it myself, but I also wanted to make sure it had the power behind it to run triple-A titles, like Crimson Desert and, eventually, GTA 6. </p><p>But, while choosing my PC was one critical part of the process, choosing the must-have accessories is a totally different quest. Fortunately, it's also one that I reckon I can help you with. While the PC itself is personal to you, depending on what you're after, PC gaming extras are a little more fluid. Here's the 12 PC gaming accessories I consider to be top picks for an epic at-home setup. </p>        <div class="featured_product_block featured_block_hero" data-id="3d96566a-4655-49ea-94e3-c904cc30c74c">            <a href="https://www.amazon.com/Galdas-Background-Extended-Mousepad-31-5x11-8x0-08/dp/B07GV78VT7" data-model-name="Galdas XL Mouse Pad" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/PuwJPEPyMYTUkpqb9WCjTW.jpg" alt="Galdas Mouse Pad for Gaming,forest Background Pattern Xxl Xl Large Mouse Mat Long Extended Mousepad Desk Mat Non-Slip Rubber Mice Pads Stitched Edges Thin (31.5 X 11.8 X 0.12 Inches) Tree"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Galdas</div>                                        <div class="featured__title">Galdas XL Mouse Pad</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="b24b9ab6-271f-406c-8609-30e6fdaa7da7">            <a href="https://www.amazon.com/dp/B0F1R9WVGN" data-model-name="Turtle Beach Wired Gaming Controller" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:89.60%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/fwq3qVL8H6jZDXmi3EXakY.jpg" alt="Turtle Beach Rematch Core Wired Gaming Controller - Licensed for Xbox Series X|s, Xbox One & Windows Pcs - Audio Controls, Rumble Motors & Impulse Triggers, Companion App - Ghost Black Camo/green"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Turtle Beach</div>                                        <div class="featured__title">Turtle Beach Wired Gaming Controller</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="18d397bf-a326-4962-a47c-508035d56fb4">            <a href="https://www.amazon.com/Razer-Basilisk-Customizable-Ergonomic-Gaming/dp/B09C13PZX7" data-model-name="Razer Basilisk V3  Gaming Mouse" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/mzQGEoBtjuAyXjFkfbksbZ.jpg" alt="Razer Basilisk V3 Customizable Ergonomic Gaming Mouse: Fastest Gaming Mouse Switch - Chroma Rgb Lighting - 26k Dpi Optical Sensor - 11 Programmable Buttons - Hyperscroll Tilt Wheel - Classic Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Razer</div>                                        <div class="featured__title">Razer Basilisk V3  Gaming Mouse</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="bfc11c0d-7504-41ea-acfe-089b5b2b9478">            <a href="https://www.amazon.com/HOTO-Compressed-Vacuuming-Inflating-Brushless/dp/B0C9HPLTX5" data-model-name="Hoto Handheld Vacuum Cleaner" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:125.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/BjkefZtn485L6rEcPs86Sa.jpg" alt="Hoto Handheld Vacuum Cleaner Cordless, Desk Vacuum Cleaner Compressed Electric Air Duster 15000pa Suction, 4-In-1 Portable Vortex Vacuum Dust Buster Air Blower for Computer, Keyboard, Coffee Grounds"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>HOTO</div>                                        <div class="featured__title">Hoto Handheld Vacuum Cleaner</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="f2a36af4-0708-4843-a682-c35af62760ee">            <a href="https://www.amazon.com/SteelSeries-Apex-RGB-Gaming-Keyboard/dp/B07ZGDPT4M" data-model-name="Steelseries Apex 3 Rgb Gaming Keyboard" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/buqoEAMWWnqjym8jA9fgXb.jpg" alt="Steelseries Apex 3 Rgb Gaming Keyboard – 10-Zone Rgb Illumination – Ip32 Water Resistant – Premium Magnetic Wrist Rest (whisper Quiet Gaming Switch)"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>SteelSeries</div>                                        <div class="featured__title">Steelseries Apex 3 Rgb Gaming Keyboard</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="4af3aea8-f815-47b8-bb66-bef7814cb1fd">            <a href="https://www.amazon.com/VSDINSIDE-Controller-Streaming-Programmable-Customizable-Soundboard/dp/B0F59WH24Y" data-model-name="Vsdinside Stream Controller Deck" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/8FGLy7MThGseddEfuTqLLc.jpg" alt="Vsdinside Macro Keypad, Stream Controller Deck Gaming Streaming Shortcut Keyboard, 18 Programmable Keys Customizable Visual Ai Pad Usb Soundboard for Obs, Youtube, Desk Office Setup, Laptop, Pc, Mac"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>VSDINSIDE</div>                                        <div class="featured__title">Vsdinside Stream Controller Deck</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="504836b5-893b-4e90-8555-94be562530d2">            <a href="https://www.amazon.com/HyperX-Cloud-Gaming-Headset-KHX-HSCP-RD/dp/B00SAYCXWG" data-model-name="Hyperx Cloud Ii Gaming Headset" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/FCdjyD3tySsG7At56gGgAd.jpg" alt="Hyperx Cloud Ii Gaming Headset - 7.1 Surround Sound - Memory Foam Ear Pads - Durable Aluminum Frame - Multi Platform Headset - Works With Pc, Ps4, Ps4 Pro, Xbox One, Xbox One S - Red (khx-Hscp-Rd)"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>HyperX</div>                                        <div class="featured__title">Hyperx Cloud Ii Gaming Headset</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="deaea394-6fa6-426d-b9f6-4dc9d13559a5">            <a href="https://www.amazon.com/Lenovo-Legion-Mechanical-Gaming-Keyboard/dp/B0D96H4TSK" data-model-name="Lenovo Legion K510 Mini Pro Wired Mechanical Gaming Keyboard" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/b7XhHMA3MDcRQVJjSw9mpd.jpg" alt="Lenovo Legion K510 Mini Pro Wired Mechanical Gaming Keyboard - 75% Compact Design, Rgb Illumination, Hot-Swappable Mechanical Switches, Programable Keys"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Lenovo</div>                                        <div class="featured__title">Lenovo Legion K510 Mini Pro Wired Mechanical Gaming Keyboard</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="64ebbb19-7b11-4e6c-b210-d6fdac0eb896">            <a href="https://www.amazon.com/dp/B0FD41XC3P" data-model-name="Gamesir G7 Pro Wired Controller" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/h85qBdU7noiKCj396hQfce.jpg" alt="Gamesir G7 Pro Wired Controller for Xbox Series X|s, Xbox One, Wireless Gamepad for Pc&android With Tmr Sticks, Hall Effect Analog Triggers, 1000hz Polling Rate, 3.5mm Audio Jack - White"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>GameSir</div>                                        <div class="featured__title">Gamesir G7 Pro Wired Controller</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="c7d5c53d-a45a-4146-a6e3-2f4c675c7302">            <a href="https://www.amazon.com/GTPLAYER-Computer-Footrest-Adjustable-360%C2%B0-Swivel/dp/B0FVXRZJ12" data-model-name="Gtplayer Gaming Chair" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:122.25%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/GhDYtmpSiAXsTburt3NUwf.jpg" alt="Gtplayer Gaming Chair, Computer Chair With Footrest and Lumbar Support, Height Adjustable Game Chair With 360°-Swivel Seat and Headrest and for Office or Gaming (pearl White)"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>GTPLAYER</div>                                        <div class="featured__title">Gtplayer Gaming Chair</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="0f49315b-c3d1-4506-8832-1fe0fb65399c">            <a href="https://www.amazon.com/SteelSeries-Arctis-Wireless-Multi-System-Headset/dp/B0D2YBQQ1P" data-model-name="Steelseries Arctis Nova 5 Wireless Gaming Headset " data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/KXZWc2ZdM9jV9eeoesRCdg.jpg" alt="Steelseries Arctis Nova 5 Wireless Multi-System Gaming Headset — Neodymium Magnetic Drivers — 100+ Audio Presets — 60 Hr Battery — 2.4ghz or Bt — Clearcast Gen2.x Mic — Pc, Ps5, Ps4, Switch, Mobile"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>SteelSeries</div>                                        <div class="featured__title">Steelseries Arctis Nova 5 Wireless Gaming Headset </div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="5d5be04b-9618-4f55-86e8-e5911182ac7d">            <a href="https://www.amazon.com/Razer-Iskur-Ergonomic-Gaming-Built/dp/B0DP5SY554/" data-model-name="Razer Iskur V2 X Ergonomic Gaming Chair" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/EsaSo9AsDeE9bXDKhx58ah.jpg" alt="Razer Iskur V2 X Ergonomic Gaming Chair: Built-In Lumbar Support - Widened Seat Base - High Density Foam Cushions - Adjustable 152 Degree Recline - 2d Armrests - Plush Fabric Finish - Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Razer</div>                                        <div class="featured__title">Razer Iskur V2 X Ergonomic Gaming Chair</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested the HyperX QD-OLED gaming monitor — and it's a pretty sweet deal for under $500 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/hyperx-omen-oled-27q-review</link>
                                                                            <description>
                            <![CDATA[ The HyperX Omen OLED 27q is a solid gaming monitor with super-fast response times and a smooth 240Hz refresh rate for esports titles. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">gyS9FBKVfaGaJg2xkkordc</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/jMhwHfrysg5jaojm3bgPVE-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 17 May 2026 11:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ imad.khan@futurenet.com (Imad Khan) ]]></author>                    <dc:creator><![CDATA[ Imad Khan ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/XH7W5t3Kwp9nRYWBA7RoSR.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/jMhwHfrysg5jaojm3bgPVE-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[HyperX Omen OLED 27q]]></media:description>                                                            <media:text><![CDATA[HyperX Omen OLED 27q]]></media:text>
                                <media:title type="plain"><![CDATA[HyperX Omen OLED 27q]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/jMhwHfrysg5jaojm3bgPVE-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>At $499, the HyperX Omen OLED 27q is arguably a lot to spend on a 1440p 240Hz gaming monitor. That’s especially true when you compare it to the wide selection of 1440p monitors on Amazon, most of which sit under $200. Some of those sub-$200 monitors even have higher refresh rates than the HyperX Omen. However, compared to pricier competitors offering similar specs, it's a great deal.</p><p>Considering that four of the five displays on our <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html">best gaming monitors</a> list have OLED panels, there’s a reason critics keep turning back to the technology, even as more competitive miniLED panels are hitting the market.</p><p>OLED has benefits that standard IPS displays have yet to match. From vivid colors to eerily dark blacks, the richness on display is hard to match. OLED does suffer from lower peak brightness, but given that most people sit inches from their monitors, it should still be bright enough for most.</p><p>If budget is a concern, then it ultimately comes down to the type of work you’ll need the monitor for outside of gaming. For creatives who need the color accuracy of OLED, the 27q is an easy choice. For everyone else, there might be more to consider. Still, if you've eyed a more expensive monitor at $1,000+, this one is a steal.</p><p>Here's my full HyperX Omen OLED 27q review.</p><h3 class="article-body__section" id="section-hyperx-omen-oled-27q-review-specs"><span>HyperX Omen OLED 27q review: Specs</span></h3><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>HyperX Omen OLED 27q</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p>$499</p></td></tr><tr><td class="firstcol " ><p><strong>Display</strong></p></td><td  ><p>27-inch</p></td></tr><tr><td class="firstcol " ><p><strong>Resolution</strong></p></td><td  ><p>2560 x 1440</p></td></tr><tr><td class="firstcol " ><p><strong>Aspect ratio</strong></p></td><td  ><p>16:9</p></td></tr><tr><td class="firstcol " ><p><strong>Refresh rate</strong></p></td><td  ><p>240Hz</p></td></tr><tr><td class="firstcol " ><p><strong>Response time</strong></p></td><td  ><p>0.03ms</p></td></tr><tr><td class="firstcol " ><p><strong>Panel type</strong></p></td><td  ><p>QD-OLED</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>2x HDMI 2.1, 1x DisplayPort 1.4, 1x 3.5mm audio jack</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>23.99 x 1.89 x 13.95 in (without stand)</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>4.82 lb (with stand); 8.82 lb (without stand)</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-hyperx-omen-oled-27q-review-cheat-sheet"><span>HyperX Omen OLED 27q review: Cheat sheet</span></h3><ul><li><strong>What is it?</strong> A flat 27-inch 2560 x 1440 QD-OLED monitor with a 0.03ms response time and 240Hz refresh rate.</li><li><strong>Who is it for?</strong> Creatives and enthusiast gamers who want the richest colors and top gaming performance.</li><li><strong>How much does it cost?</strong> It’s marketed at $499, but at time of writing, <a href="https://www.hp.com/us-en/shop/pdp/hyperx-omen-oled-27-inch-qhd-240hz-gaming-monitor-omen-oled-27q" target="_blank" rel="nofollow">it's $399 on HP's website.</a></li><li><strong>What do we like?</strong> It’s hard to match OLED's vividness, and the 240Hz refresh rate makes it a top performer for gaming.</li><li><strong>What don’t we like?</strong> There’s no forward tilt, so the display looks like it’s leaning back slightly when on its stand.</li></ul><h3 class="article-body__section" id="section-hyperx-omen-oled-27q-review-the-ups"><span>HyperX Omen OLED 27q review: The ups</span></h3><p>The HyperX Omen OLED 27q delivers the good thanks to its vivid picture quality and fast performance.</p><h2 id="oled-or-nothing">OLED or nothing</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="WCry2tAeexco489ypRAKae" name="HyperX-Omen-OLED-27q--3" alt="HyperX Omen OLED 27q" src="https://cdn.mos.cms.futurecdn.net/WCry2tAeexco489ypRAKae.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>Fans online jest that once you go OLED, you never go back. That’s the case with the HyperX Omen OLED 27q, or any other OLED gaming monitor on the market.</p><p>Given the richness of color and the near-instantaneous response time, jumping to an IPS display can feel like a significant downgrade. Although miniLED monitors are starting to hit the market, the gap in color contrast is closing.</p><div ><table><caption>Display benchmark results (native/default)</caption><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>HyperX Omen OLED 27q</strong></p></td><td  ><p><strong>Alienware 2726DM</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Nits (brightness)</strong></p></td><td  ><p>195 (SDR) | 369 (HDR for 10% of display)</p></td><td  ><p>181 (SDR) | 340 (HDR, 10% of display)</p></td></tr><tr><td class="firstcol " ><p><strong>sRGB</strong></p></td><td  ><p>201.5%</p></td><td  ><p>190%</p></td></tr><tr><td class="firstcol " ><p><strong>DCI-P3</strong></p></td><td  ><p>142.7%</p></td><td  ><p>140.9%</p></td></tr><tr><td class="firstcol " ><p><strong>Delta-E</strong></p></td><td  ><p>0.33</p></td><td  ><p>0.24</p></td></tr></tbody></table></div><p>At a 2560 x 1440 resolution, it won’t take the highest-end graphics cards to push this monitor. However, getting all 240Hz out of a game like <a href="https://www.tomsguide.com/reviews/cyberpunk-2077">Cyberpunk 2077</a> or <a href="https://www.tomsguide.com/reviews/alan-wake-2">Alan Wake 2</a> will require an Nvidia RTX 5080 or above. Actually, when testing Cyberpunk 2077 on my gaming rig, which is equipped with an RTX 5090, it struggled to maintain a consistent 240 fps. Granted, that framerate is totally overkill for this type of game.</p><p>The HyperX Omen OLED 27q has eight display modes, with some dedicated to genres like RTS, RPG, and FPS. There are also some creator-centric modes, such as Display P3 and sRGB. These modes are the same as you'd get on similar monitors, albeit with more balance between gaming and creativity.</p><p>For creative work, that’s where color accuracy and brightness come into play. In our testing, the 27q spanned 116% of the sRGB and 82% of the DCI-P3 color gamuts in the monitor's sRGB display setting. For creatives, the 27q will likely suffice for photo editing and other use cases.</p><p>Like all OLED gaming monitors. HDR brightness isn't exactly impressive. This is a small knock, but not out of the ordinary for similar monitors.</p><h2 id="esports-performance">Esports performance</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="RBHaaie2GmMe6maj3Y3kSn" name="HyperX-Omen-OLED-27q--14" alt="HyperX Omen OLED 27q ports" src="https://cdn.mos.cms.futurecdn.net/RBHaaie2GmMe6maj3Y3kSn.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>My competitive game of choice on PC is <a href="https://www.tomsguide.com/gaming/ive-been-playing-overwatch-since-day-1-heres-why-overwatch-classic-isnt-working">Overwatch</a>. My personal monitor is a Samsung Odyssey G9 OLED, a 49” behemoth of a display with an absurdly wide 32:9 aspect ratio. When playing Overwatch, however, it crops down to a 21:9 aspect ratio. It’s also a 240Hz panel, making it a fair comparison to the 27q.</p><p>While playing Overwatch, I noticed no difference between the two displays aside from their aspect ratios. I was still able to land headshots with Kiriko’s kunai as efficiently as I always do, depending on how sharp my mind feels at the moment.</p><p>That’s the thing with OLED. The technology is rather standardized, meaning the colors, depth, and response times will feel very similar across similarly spec'd monitors. So, if you’ve decided to take the plunge on an OLED gaming monitor, it simply comes down to the size you want and how much you’re willing to pay, in my opinion.</p><p>For competitive gamers, the 27q features a crosshair, which places a reticule at the center of your display to make aiming easier. I personally don’t use this function, so I can’t speak to it at greater length. But if it’s a feature you prefer in your gaming displays, know that it’s here.</p><p>The 27q also includes a speedrun and countdown timer, which is handy when trying to run through Super Mario Bros. or Sonic Adventure 2 as quickly as possible. I’m not a speedrunner, so this is less useful to me, but I’m sure those in the speedrunning community might find this to be a valuable add-on.</p><p>More importantly, the 27q does feature both Nvidia G-Sync and AMD FreeSync Premium. While on HP’s website and on the monitor's box, only G-Sync is advertised, in the settings, you can enable FreeSync.</p><h3 class="article-body__section" id="section-hyperx-omen-oled-27q-review-the-downs"><span>HyperX Omen OLED 27q review: The downs</span></h3><p>As a gaming monitor, there really isn't much to ding the 27q on. It delivers the performance advertised on the box.</p><h2 id="bland-design">Bland design</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="rsJJMhk3vks3sGu8bipNm6" name="HyperX-Omen-OLED-27q--5" alt="HyperX Omen OLED 27q" src="https://cdn.mos.cms.futurecdn.net/rsJJMhk3vks3sGu8bipNm6.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 also noticed that the 27q, while being able to tilt backward or turn 90 degrees, had limited forward tilt when affixed to the included stand. As a result, the monitor leans back slightly, making it a bit awkward to look at it directly. Although I did have the monitor rather close to me when it was on my desk. If you move the monitor a few inches back, it should make for a better experience.</p><p>The number of ports is also rather limited. It only sports two HDMI 2.1 ports, a DisplayPort 1.4, and a 3.5mm audio jack. Granted, given that this monitor is relatively small at 27 inches, it’s not like you’d be using a KVM switch to use two computers on it simultaneously.</p><p>The monitor's design is kind of boring. There also aren’t any fancy RGB lights on the back, although some may prefer that. But other than that, there really aren’t many demerits to throw at the 27q.</p><h2 id="good-enough-but-not-standout">Good enough but not standout</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="Ho6W5omHHmu5HJnjWaPe3D" name="HyperX-Omen-OLED-27q--6" alt="HyperX Omen OLED 27q" src="https://cdn.mos.cms.futurecdn.net/Ho6W5omHHmu5HJnjWaPe3D.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>There are certainly faster OLED monitors on the market, such as the<a href="http://www.tomsguide.com/computing/monitors/msi-mpg-341cqr-qd-oled-x36-review"><u> MSI MPG 341CQR QD-OLED X36</u></a>. But at $870, it's more than double the price of the 27q.</p><p>And honestly, at that price, I feel it might be better to opt for a super ultrawide monitor, like the <a href="https://www.tomsguide.com/reviews/samsung-odyssey-oled-g9">Samsung Odyssey G9 OLED</a>, which is also around the $900 range, depending on sales. That's also assuming your desk can accommodate it.</p><h3 class="article-body__section" id="section-hyperx-omen-oled-27q-review-verdict"><span>HyperX Omen OLED 27q review: Verdict</span></h3><p>The HyperX Omen OLED 27q is a solid monitor at a competitive price, but it doesn’t do much to set itself apart. That isn’t necessarily a bad thing, as most OLED displays on the market are rather standardized, meaning that manufacturers don’t have incredible leeway in making their displays more unique. At most, consumers are faced with choosing between higher refresh rates, wide aspect ratios, and sometimes gimmicky AI features.</p><p>But this is good for consumers, in my opinion. The commodification of OLED technology means it can reach more people at a wider range of price points. The fact that someone can walk into a Best Buy and pick up a 27-inch OLED monitor with a 240Hz refresh rate would have been unheard of a decade prior. After some online research, I found that 1440p IPS monitors with a 144Hz refresh rate from 2016 were over $700.</p><p>Ultimately, I recommend the 27q. I would tell someone with a $200 budget to consider saving up for the 27q. Also, yes. Would I personally opt for the 27q when there are 21:9 and 32:9 ultrawide OLED monitors available on the market? No. But that’s me. For many, a 27-inch display is the perfect sweet spot. It’s compact and is ideal for esports titles like Counter-Strike 2 and Overwatch.</p><p>If you’ve been in the market for an OLED display and have the cash to spend, go for it.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ AMD is bringing FSR 4.1 upscaling to older Radeon RX GPUs — this is huge ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/amd-is-bringing-fsr-4-1-upscaling-to-older-radeon-rx-gpus-this-is-huge</link>
                                                                            <description>
                            <![CDATA[ AMD just revealed its plan to bring FSR Upscaling 4.1 to its Radeon RX 7000 in July and to RX 6000 early in 2027. Here's why this is a big deal for gamers. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">keZS5EaiCubkHkUpjU7HZe</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Km8fMdg6qyuFzqjCsGEfSC-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 14 May 2026 15:48:50 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/Km8fMdg6qyuFzqjCsGEfSC-1280-80.jpg">
                                                            <media:credit><![CDATA[AMD]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[AMD Radeon RX 6000]]></media:description>                                                            <media:text><![CDATA[AMD Radeon RX 6000]]></media:text>
                                <media:title type="plain"><![CDATA[AMD Radeon RX 6000]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Km8fMdg6qyuFzqjCsGEfSC-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>AMD just lit a beacon of hope for gamers with older Radeon RX graphics cards. As <a href="https://videocardz.com/newz/amd-fsr-upscaling-4-1-officially-coming-to-radeon-rx-7000-gpus-in-july-rx-6000-in-2027" target="_blank">VideoCardz</a> reports, Jack Huynh, AMD Senior Vice President and General Manager of Computing and Graphics, says the company is bringing its FSR Upscaling 4.1 support to RDNA 3 GPUs this July.</p><p>Currently, FSR 4.1 (AMD’s answer to Nvidia’s DLSS) is only available for Radeon RX 9000 cards featuring the latest RDNA 4 technology. When this update goes live in July, Radeon RX 7000 can get in on the upscaling action. Best of all, over 300 games will be supported at launch.</p><div class="see-more see-more--clipped"><blockquote class="twitter-tweet hawk-ignore" data-lang="en"><p lang="en" dir="ltr">As a lifelong gamer, I spend a lot of time thinking about how to push gaming experiences forward across CPUs, GPUs, software, and games.My team and I have been working hard to evolve @AMD FSR 4 and bring it to more cards.We power over 1 billion gaming devices worldwide. It’s… pic.twitter.com/91Z3vXpQap<a href="https://twitter.com/cantworkitout/status/2054904153013387273">May 14, 2026</a></p></blockquote><div class="see-more__filter"></div></div><p>AMD hasn’t forgotten about folks using older RDNA 2 GPUs, as FSR 4.1 will be coming to those cards sometime in early 2027. We don’t yet have a full compatibility list, but this should see support for the Radeon RX 6000 series of desktop and mobile GPUs. That last one is especially worth noting for anyone using one of the <a href="https://www.tomsguide.com/best-picks/best-gaming-laptops" target="_blank">best gaming laptops</a> with an AMD Radeon RX 6000 chip.</p><p>ML upscaling tech allows low- to mid-range graphics cards to punch above their weight, delivering smoother frame rates and sharper visuals. Nvidia’s DLSS is still the undisputed king of AI upscaling, but AMD has been catching up and is doing admirable work. It was always a shame that FSR 4 was only for newer cards, so it’s great that folks with older Radeon GPUs won’t miss out on the action.</p><p>AMD hasn’t said exactly when in July this update will go live for RDNA 3 cards. Still, that’s not too far in the future, so we should soon know how much better games perform and look on those older cards. I’m also curious to see whether this update translates to the best gaming handhelds with RNDA 3 GPUs, like the Asus ROG Ally and Lenovo Legion Go 2.</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/computing/gaming-laptops/alienware-15-2026-hands-on-preview">I just tested the new Alienware 15 — and it’s almost right</a></li><li><a href="https://www.tomsguide.com/computing/laptops/googlebooks-vs-chromebooks">Googlebooks vs. Chromebooks: Biggest differences explained</a></li><li><a href="https://www.tomsguide.com/gaming/ps5-pro-vs-gaming-pc-which-one-is-the-best-bang-for-your-buck-right-now">PS5 Pro vs gaming PC: Which one is the best bang for your buck right now?</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested the new Alienware 15 — and it’s almost right ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/gaming-laptops/alienware-15-2026-hands-on-preview</link>
                                                                            <description>
                            <![CDATA[ The Alienware 15 gaming laptop is a relatively affordable machine that delivers a smooth gaming experience with some necessary compromises. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">j5re7yWPu9fqVA57NHRgfR</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Jo3PfSDo5UDoJ3JDcXCPgh-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 14 May 2026 13:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gaming Laptops]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Laptops]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/Jo3PfSDo5UDoJ3JDcXCPgh-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Alienware 15 (20226)]]></media:description>                                                            <media:text><![CDATA[Alienware 15 (20226)]]></media:text>
                                <media:title type="plain"><![CDATA[Alienware 15 (20226)]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Jo3PfSDo5UDoJ3JDcXCPgh-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Alienware's notebooks are among the <a href="https://www.tomsguide.com/best-picks/best-gaming-laptops">best gaming laptops</a> available, but they can be pricey for most folks. This is especially true now, thanks to <a href="https://www.tomsguide.com/computing/ram-price-crisis-2026-everything-you-need-to-know">RAMageddon</a>. Thankfully, the company isn’t ignoring the current reality and has just launched a more affordable gaming laptop for PC gamers. Meet the new Alienware 15 (2026) gaming laptop.</p><p>Starting at $1,299, this 15-inch laptop packs up to an AMD Ryzen 7 CPU and up to an Nvidia RTX 5060 GPU. Couple with 16GB of RAM and up to 1TB of SSD storage, and you have the basics for playing the <a href="https://www.tomsguide.com/best-picks/best-PC-games">best PC games</a> at 1080p resolution and medium to high graphics. While the asking price is still above $1,000, it’s not terrible given current conditions.</p><p>I tested a pre-production model of the Alienware 15 gaming laptop and found it delivers a solid experience for those who don’t want to break the bank. Given its price, you’re not getting a premium display or chassis, but if you just want to play your PC games on something reliable, you won’t go wrong here.</p><h2 id="alienware-15-2026-hands-on-specs">Alienware 15 (2026) hands-on: Specs</h2><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Alienware 15 (2026)</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Price (starting)</strong></p></td><td  ><p>$1,299</p></td></tr><tr><td class="firstcol " ><p><strong>Display</strong></p></td><td  ><p>15.3 inch (1920 x 1200) | 16:10| 165Hz</p></td></tr><tr><td class="firstcol " ><p><strong>CPU</strong></p></td><td  ><p>Up to AMD Ryzen 7</p></td></tr><tr><td class="firstcol " ><p><strong>GPU</strong></p></td><td  ><p>Up to Nvidia GeForce RTX 5060 </p></td></tr><tr><td class="firstcol " ><p><strong>RAM</strong></p></td><td  ><p>16GB</p></td></tr><tr><td class="firstcol " ><p><strong>Storage</strong></p></td><td  ><p>Up to 1TB</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Wi-Fi 6, Bluetooth 5.2</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>2x USB-C, 2x USB-A, 1x HDMI, 1x Ethernet</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>13.76 x 9.85 x 0.81 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>4.96 pounds</p></td></tr></tbody></table></div><h2 id="alienware-15-2026-hands-on-design">Alienware 15 (2026) hands-on: Design</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:4735px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="uiHuuAw3svX9YjpWkbqZj9" name="Alienware 15 2026-5" alt="Alienware 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/uiHuuAw3svX9YjpWkbqZj9.jpg" mos="" align="middle" fullscreen="" width="4735" height="2663" 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 first glance, the Alienware 15 certainly has the iconic look of the company’s laptops, with its all-black shell and Alienware logo on the lid. However, picking it up instantly makes it clear this isn’t just any Alienware product.</p><p>The polycarbonate resin lid and bottom have a plastic-like feel that’s a departure from the aluminum casings of higher-end Alienware laptops. While that’s jarring at first, the smooth, contoured lines and overall sleek design help offset that.</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:5712px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="yKG3iMgc5ikoQLVYwjjLAc" name="Alienware 15 2026-3" alt="Alienware 15 (2026)" src="https://cdn.mos.cms.futurecdn.net/yKG3iMgc5ikoQLVYwjjLAc.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="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Unlike the Alienware 16 Area-51, the Alienware 15 has a full keyboard, which should make number pad users very happy. I don’t fall into that camp, so having the keys I actually mostly located on the left-hand side made it tricky to find my stride when typing. That said, the thick keys and their satisfying travel distance do make this a good laptop for writing.</p><p>The lion’s share of the ports is on the left-hand side. This includes two USB-A ports, an Ethernet port, a USB-C port, and an HDMI port. On the left are a lone USB-C port and a headphone jack. Port placement is generally fine if that’s the side you prefer to connect peripherals to, but it could be burdensome if you would have preferred them on the right side or on the back.</p><h2 id="alienware-15-2026-hands-on-display">Alienware 15 (2026) hands-on: Display</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:4086px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="PrCmjZ4jDdW8gby9YiHP7J" name="Alienware 15 2026-2" alt="Alienware 15 (2026)" src="https://cdn.mos.cms.futurecdn.net/PrCmjZ4jDdW8gby9YiHP7J.jpg" mos="" align="middle" fullscreen="" width="4086" height="2298" 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 15-inch display isn’t terrible, but after testing so many laptops with OLED panels, it’s certainly a step down in both picture quality and overall brightness.</p><p>Since this was a pre-production model, we didn’t run our usual suite of display benchmarks. To my eyes, however, the screen is noticeably dimmer and less vibrant than a more premium display.</p><p>That’s not to say things don’t appear clearly defined, because they certainly do. The 1200p resolution lets you see everything on the screen in fine detail. However, the muted colors and low brightness make everything look duller than you’d like.</p><p>Again, things don’t look terrible on the Alienware 15, but don’t expect a top-end viewing experience when playing games or watching videos.</p><h2 id="alienware-15-2026-hands-on-performance-and-battery-life">Alienware 15 (2026) hands-on: Performance and battery life</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:3469px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="aKWVXn3KsqpT77aPXEoLFR" name="Alienware 15 2026-7" alt="Alienware 15 (2026)" src="https://cdn.mos.cms.futurecdn.net/aKWVXn3KsqpT77aPXEoLFR.jpg" mos="" align="middle" fullscreen="" width="3469" height="1951" 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 a pre-production model with entry-level specs. It includes an AMD Ryzen 5 processor, an Nvidia RTX 4050 mobile GPU, 16GB of RAM, and 512GB of SSD storage. These aren’t the latest and greatest components, but they’re good enough for playing even demanding games at smooth frame rates.</p><p>At default graphical settings and native resolution, Cyberpunk 2077 ran at around 45 to 50 frames per second during my testing. Mind you, that’s without the frame-boosting DLSS upscaler enabled. With this feature turned on, the fps jumped to the low 60s, so it’s definitely worth it for a system like this.</p><p>Given its prowess as a gaming machine, the Alienware 15 had no problems handling my average workflow, which usually consists of dozens of open Chrome tabs and the occasional YouTube video running in the background. If you need to get work done, this laptop won’t let you down.</p><p>Lastly, let’s talk about battery life. We didn’t run our usual battery test on this machine, but during my testing, I was able to play for close to 90 minutes before the battery life warning appeared. That’s typical for a gaming laptop, so I wasn’t surprised. Naturally, you’ll want to keep this laptop connected while gaming so it keeps running and maintains optimal performance.</p><h2 id="alienware-15-2026-hands-on-outlook">Alienware 15 (2026) hands-on: Outlook</h2><p>Given how expensive gaming devices are nowadays, I applaud Alienware for keeping the average gamer in mind. Both the Alienware 15 gaming laptop and the $349 <a href="https://www.tomsguide.com/computing/monitors/alienware-aw2726dm-review">Alienware AW2726DM</a> gaming monitor exemplify this philosophy.</p><p>While I wouldn’t call a $1,299 starting price cheap, it’s still affordable given the current state of things. I’ll have a full review for you once I get to test a final model, but for now, I like what Alienware is cooking up.</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/computing/laptops/googlebooks-vs-chromebooks">Googlebooks vs. Chromebooks: Biggest differences explained</a></li><li><a href="https://www.tomsguide.com/gaming/ps5-pro-vs-gaming-pc-which-one-is-the-best-bang-for-your-buck-right-now">PS5 Pro vs gaming PC: Which one is the best bang for your buck?</a></li><li><a href="https://www.tomsguide.com/computing/gaming-desktops/steam-machine-leak-suggests-4-different-models-and-a-queue-system-to-stop-scalpers">Steam Machine leak suggests 4 different models</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I’ve driven over 10,000 miles in Forza Horizon 6, and can confirm it is a dream game for car lovers ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/forza-horizon-6-review</link>
                                                                            <description>
                            <![CDATA[ Forza Horizon 6 is a master class in car culture with technical driving and customization running through its veins, a gargantuan amount of modes to jump into, and an accessible seamlessness to it all. For seasoned veterans, it’s easily the best in the series, and for those getting their first taste of Horizon, it’ll be the best racing game you’ve jumped into in a long time. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">K58aig4tbvFz5Fi8FMj4CP</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/gyyA3xwFsar2vxFYAQrmM-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 14 May 2026 12:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gaming]]></category>
                                                                                                                    <dc:creator><![CDATA[ Jason England ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/v4fSq5U4uZUEtGY2BwNuJ6.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Jason brings a decade of tech and gaming journalism experience to his role as a Managing Editor of Computing at Tom&#039;s Guide. He has previously written for Laptop Mag, Tom&#039;s Hardware, Kotaku, Stuff and BBC Science Focus. In his spare time, you&#039;ll find Jason looking for good dogs to pet or thinking about eating pizza if he isn&#039;t already.&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/gyyA3xwFsar2vxFYAQrmM-1280-80.jpg">
                                                            <media:credit><![CDATA[Playground Games]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Forza Horizon 6]]></media:description>                                                            <media:text><![CDATA[Forza Horizon 6]]></media:text>
                                <media:title type="plain"><![CDATA[Forza Horizon 6]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/gyyA3xwFsar2vxFYAQrmM-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <div  class="fancy-box"><div class="fancy_box-title">Forza Horizon 6 review: Specs</div><div class="fancy_box_body"><p class="fancy-box__body-text"><strong>Platforms:</strong> PC (reviewed), Xbox Series X/S, PS5 (coming soon)<br><strong>Price:</strong> $69 / £59 / AU$109<br><strong>Release date:</strong> May 19, 2026<br><strong>Genre:</strong> Racing</p></div></div><p>Car culture — something that a lot of games try to nail, but never really quite get the <em>feel </em>of it. </p><p>It’s not about features, gameplay, graphics or sound alone. It’s about merging all of these in a way that becomes a genuine love letter to the automobiles. From big moments like grand races or drifts down mountainous Japanese roads, all the way down to the tiniest details like showing your motor at a car meet or the roar of your V8 engine echoing off tunnel walls, every little thing matters.</p><p>And like I said, every game I play comes close but no cigar… Until I played Forza Horizon 6 — a truly seamless, accessible celebration of real-world car enthusiasm and easily the best racing game I’ve played in years.</p><p>Now let me be abundantly clear: 5 stars does <strong>not </strong>mean perfection. There’s no such thing as a perfect game. Online multiplayer may still get you some frustrating moments of being used like a glorified wall buffer for other competitors, which the penalty system can sometimes miss in competitive racing.</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="Fz8WigwmFih5Gg27mm9uhL" name="Forza Horizon 6" alt="Forza Horizon 6" src="https://cdn.mos.cms.futurecdn.net/Fz8WigwmFih5Gg27mm9uhL.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: Playground Games)</span></figcaption></figure><p>But make no mistake about it, if you’re a regular racer at heart or someone who’s caught the bug and wants to experience it, there’s nothing more all-encompassing than this. Japan is truly a joy to drive and the pulse of this culture pumps hard in a way you won’t feel in any other sim racer.</p><p>Yes, I know that’s a little controversial of me — a sim racer — to say, as the Forza Horizon series definitely leans more towards the arcade than the hardcore (though there is the versatility to make it more sim-feeling). </p><p>But through removing barriers to community fun, dropping you in a gorgeously giant sandbox, being true music connoisseurs with the radio stations, giving you all the customization options (including your garage) and making everything flow oh-so fluidly, developer Turn 10 has done the one thing a lot of sim titles seem to forget about in their search for ultimate realism: focus on the fun.</p><p>Whatever you want to do, whoever you want to be, it’s all here. Welcome to a new Horizon. You’re going to be here for a while.</p><h2 id="forza-horizon-6-the-basics">Forza Horizon 6: The basics</h2><ul><li><strong>What is it?</strong> Forza Horizon 6 is a free-roaming racing game with plenty to do in a giant Japan sandbox.</li><li><strong>Who is it for?</strong> This is for racing enthusiasts and those who want to explore car culture anew.</li><li><strong>What's the price?</strong> Forza Horizon 6 costs <a href="https://www.amazon.com/Forza-Horizon-6-Standard-Xbox-X/dp/B0GHC1548X" target="_blank" rel="nofollow">$69 from retailers like Amazon.</a></li><li><strong>What other games has the developer made?</strong> Turn 10 has been dedicated to the Forza franchise ever since 2005, and FH6 is co-developed with Playground Games, also currently making Fable.</li><li><strong>What games is it similar to?</strong> Forza Horizon 6 takes some DNA from fast-paced arcade racers like Outrun 2 and Sega Rally, throws in some sim credentials like Gran Turismo 7, and drops you into a sandbox like Test Drive Unlimited Solar Crown.</li></ul><h2 id="the-wangan-stretch-a-world-of-pure-scale">The Wangan Stretch: A world of pure scale</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="hgi4Yb5uCTp4RLNAENj52M" name="Forza Horizon 6" alt="Forza Horizon 6" src="https://cdn.mos.cms.futurecdn.net/hgi4Yb5uCTp4RLNAENj52M.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: Playground Games)</span></figcaption></figure><p>It all starts just like any Horizon game, with a theatrical intro that has you experiencing the different core types of racing you’ll be jumping into — a full-on assault of the senses with a perfectly paired soundtrack with drops timed to each big moment and all the visual pomp and circumstance of a Horizon Festival opener.</p><p>But while this definitely establishes a real infectious vibe for car lovers, nothing quite prepares you for when the world truly opens up and you see the world for what it really is: a diverse, handcrafted work of art. From the wide-open stretches of roads and mountainous vistas to the bustling neon-lit spaghetti streets of Tokyo, this map (5X bigger than Forza Horizon 5) is a real joy to explore. And yes, that does include a legendary looping highway inspired by the Wangan.</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:3824px;"><p class="vanilla-image-block" style="padding-top:56.33%;"><img id="ecFmtWiMRDifEDFNAsijy6" name="Forza Horizon 6" alt="Forza Horizon 6" src="https://cdn.mos.cms.futurecdn.net/ecFmtWiMRDifEDFNAsijy6.png" mos="" align="middle" fullscreen="" width="3824" height="2154" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Playground Games)</span></figcaption></figure><p>Cars gleam with mesmerizing fidelity as you race through the world, and every finite detail can be observed up close. The faithful recreations of cars old and new give fans of anything on four wheels a lot to love right here. Then there’s the sound engineering, which brings their explosive engines to life in a way that reacts to the world around you. Hearing an engine roar while pelting through a tunnel is a jaw dropping experience.</p><p>To top it all off, Turn 10 has thrown in an absolute banger soundtrack — all your usual array of genre-driven radio stations with Japanese flair for good measure. With an all-in Gacha City Radio giving you a full suite to bands like the incredible BABYMETAL popping up in the Horizon XS, it’s all here to immerse you.</p><p>Performance-wise, you’re assured up to 60 FPS on consoles, and thanks to DLSS 4.5 support and multi-frame generation, I was easily able to get over 200 FPS at 4K max settings on my RTX 5080 rig. Oh, and shout-out to Steam Deck performance too — running at a nice 35-40 FPS average without any of that awkward rubberbanding you saw in the previous Horizon titles. My flights to and from New York flew by with hours of gameplay.</p><h2 id="the-way-of-the-hashiriya-a-never-ending-checklist">The way of the Hashiriya: A never-ending checklist</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="RbaRLfNTdxP6nMMt7VMNiL" name="Forza Horizon 6" alt="Forza Horizon 6" src="https://cdn.mos.cms.futurecdn.net/RbaRLfNTdxP6nMMt7VMNiL.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: Playground Games)</span></figcaption></figure><p>So you’re here in this living, breathing world…what now? Well, there’s <em>a lot </em>to do, and it’s all structured around a simple yet addictive loop of gaining new wristbands based on your way to becoming a Horizon Legend. This will have you doing road (street and now track), dirt and cross country racing, PR stunts and showcases.</p><p>Special mention here to the Horizon Rush events — purpose-built courses that feel like a late, great Ken Block Gymkhana event come to life with a true test of technical skill. Each one grabs you by the collar and pulls you into its addictive replayability to nail that best time.</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="7LXoKj7MvkS5FsMzAQrM2M" name="Forza Horizon 6" alt="Forza Horizon 6" src="https://cdn.mos.cms.futurecdn.net/7LXoKj7MvkS5FsMzAQrM2M.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: Playground Games)</span></figcaption></figure><p>And just like other Horizon games, many side quests become all-encompassing too. Whether it’s watching Japan unfold in storylines that connect you more to the world around you, photography goals to test your snapping fingers, secret aftermarket cars to buy in all kinds of locations, or even food delivery jobs that would make Peter Parker blush in “Spider-Man 2,” you won’t ever be left with an empty world with nothing to do. Oh, and of course, there are over 550 real-world cars to collect, too!</p><p>What’s most impressive about all of this is how seamlessly it all comes together — plenty of depth for the pros and maximum accessibility for the fresh players. There are plenty of menus and a lot of ways you can tweak cars for best performance, or you could just skip all that, have next-to-no menu interaction and just drive. Whatever you want to do, Forza Horizon 6 just lets you go do it in its universe.</p><p>But believe me when I say this is only half the story, as I’ve not even talked about the multiplayer yet.</p><h2 id="zenki-to-kouki-the-art-of-the-culture">Zenki to Kouki: The art of the culture</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="KG6Yb2jrEW6VU3W863TidR" name="Forza Horizon 6" alt="Forza Horizon 6" src="https://cdn.mos.cms.futurecdn.net/KG6Yb2jrEW6VU3W863TidR.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Playground Games)</span></figcaption></figure><p>I’ll be real with you. This is all great, but what tipped it into being a five-star experience for me is how it truly captures the life source of car culture. Too many racing games feel like a sterile interpretation of this essence, and on its sixth iteration, Forza Horizon has finally cracked the code.</p><p>It’s the culmination of all of this paired with the evolution of your many, many motors from Zenki (early) to Kouki (late) and imprinting your personality onto your own personal masterpiece. Knowing you’re going to take your ride to a street race or a touge battle (a straight up 1v1 downhill race) or a car meet really encourages you to get into building a relationship with your ride.</p><p>Nothing quite felt like taking a Toyota Supra A80 and giving it that aggressive aftermarket look I know and love to match the bonkers performance I’d extracted from the engine. But as I said up at the top, Horizon 6 is not afraid to unleash some of the bonkers fun of this culture and turn it up to larger-than-reality highs.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ZhMkT6uZGxtHHyWd3F779" name="Forza Horizon 6" alt="Forza Horizon 6" src="https://cdn.mos.cms.futurecdn.net/ZhMkT6uZGxtHHyWd3F779.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Playground Games)</span></figcaption></figure><p>Want to go drag racing in a limousine? Sure! Throwing your car off a 500-foot jump? Go for it! You even race a damn mech, it's such a cool moment! All these are possible and on paper, it's really silly. But in execution, it's this vibe of anything being possible that makes car culture so great.</p><p>At its core, Turn 10 has made a much more focused effort on starting you with a basic car that you turn into your own pride and joy over time with extensive customization tools (you can even customize your garage)! And throwing all this into the mix with everything up above feels almost surgical in becoming a true tastemaker of the culture. Nothing else captures that emotional grasp quite like this.</p><h2 id="forza-horizon-6-review-verdict">Forza Horizon 6 review: Verdict</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="iW6NZQjFJC6Pk6GQRmPH2M" name="Forza Horizon 6" alt="Forza Horizon 6" src="https://cdn.mos.cms.futurecdn.net/iW6NZQjFJC6Pk6GQRmPH2M.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: Playground Games)</span></figcaption></figure><p>I know you’re going to read a lot of reviews that talk extensively about the huge feature set, the gameplay mechanics, the graphical fidelity and sound production. But in my mind, the sum is <em>far </em>greater than its individual parts as to establish the vibe and feel that truly feels like an ongoing dopamine hit — causing me to accidentally play for 10 hours straight without even realizing.</p><p>Forza Horizon 6 is a master class in capturing car culture with technical driving and customization running through its veins, a gargantuan amount of modes to jump into, and an accessible seamlessness to it all. For seasoned veterans, it’s easily the best in the series, and for those getting their first taste of Horizon, it’ll be the best racing game you’ve jumped into in a long time.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ PS5 Pro vs gaming PC: Which one is the best bang for your buck right now? ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/ps5-pro-vs-gaming-pc-which-one-is-the-best-bang-for-your-buck-right-now</link>
                                                                            <description>
                            <![CDATA[ The PS5 Pro is pricier than ever, but it arguably delivers better price-to-performance than a comparable gaming PC. This comparison details why. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">q9s32hVJXDP3rAX5GJgQDT</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/iebeJMXjYPYCDEm7TiqqDJ-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 12 May 2026 09:30:00 +0000</pubDate>                                                                                                                                <updated>Tue, 12 May 2026 11:11:27 +0000</updated>
                                                                                                                                            <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/iebeJMXjYPYCDEm7TiqqDJ-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[PS5 Pro vs. PC]]></media:description>                                                            <media:text><![CDATA[PS5 Pro vs. PC]]></media:text>
                                <media:title type="plain"><![CDATA[PS5 Pro vs. PC]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/iebeJMXjYPYCDEm7TiqqDJ-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>With the <a href="https://www.tomsguide.com/gaming/playstation/ps5-pro-review">PS5 Pro</a> now costing a whopping $899, many are wondering whether they’re better off building (or buying) a similarly priced gaming PC. </p><p>We touched on this briefly in our <a href="https://www.youtube.com/watch?v=2zd1Hbj9Pxc">PS5 vs. PS5 Pro in 2026</a> video, but I wanted to dive deeper here. It’s a fair question — yet the answer turns out to be more straightforward than you might expect.</p><p>For $899, the PS5 Pro delivers 4K gaming with ray tracing, Sony’s AI-powered PSSR upscaling, smooth 60-120 fps in optimized titles, a fast 2TB SSD, <a href="https://www.tomsguide.com/reference/wi-fi-7-explained">Wi-Fi 7</a>, and full backward compatibility with the <a href="https://www.tomsguide.com/best-picks/the-best-ps5-games">best PS5 games</a> and the <a href="https://www.tomsguide.com/round-up/best-ps4-games">best PS4 games</a>. Add the optional disc drive for about $80, and the included DualSense controller, and you’ve got a complete high-end gaming rig ready to go straight out of the box.</p><p>Sure, the <a href="https://www.tomsguide.com/us/best-gaming-pc,review-2219.html">best gaming PCs</a> can do a lot more than just gaming. But with the ongoing <a href="https://www.tomsguide.com/computing/hardware/ram-prices-are-finally-dropping-but-i-wouldnt-celebrate-just-yet">RAM shortage</a> driving up prices across the board, even budget machines have gotten noticeably more expensive. Factor in Sony’s all-in-one package, and the PS5 Pro currently offers better value than a gaming PC with comparable specs. Here’s why.</p><div class="product"><a data-dimension112="fffdb426-0a83-442b-924f-a557ccfe303d" data-action="Deal Block" data-label="Also check: Best Buy" data-dimension48="Also check: Best Buy" data-dimension25="$899" href="https://www.amazon.com/PlayStation-5-Pro-Console-2TB/dp/B0FTMY4YZ2" 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="o53gSodihxPkSztuP2Lt4Z" name="PS5_Pro_Quick_List" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/o53gSodihxPkSztuP2Lt4Z.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The PS5 Pro is the most powerful PlayStation console ever made. Building on the base PS5, it packs upgraded internal components, a 2TB SSD, and a very slight visual redesign. It also comes with a standard DualSense controller. This $100 Black Friday discount brings the PS5 Pro down to its lowest price.<br><strong>Also check:  </strong><a href="https://www.bestbuy.com/site/sony-playstation-5-pro-console-white/6601524.p?skuId=6601524" target="_blank" rel="nofollow" data-dimension112="fffdb426-0a83-442b-924f-a557ccfe303d" data-action="Deal Block" data-label="Also check: Best Buy" data-dimension48="Also check: Best Buy" data-dimension25="$899"><strong>Best Buy</strong></a><strong> | </strong><a href="https://www.walmart.com/ip/Sony-PlayStation-5-Pro-Console-PS5-Pro/11839818124" target="_blank" rel="nofollow"><strong>Walmart</strong></a><strong></strong><a class="view-deal button" href="https://www.amazon.com/PlayStation-5-Pro-Console-2TB/dp/B0FTMY4YZ2" target="_blank" rel="nofollow" data-dimension112="fffdb426-0a83-442b-924f-a557ccfe303d" data-action="Deal Block" data-label="Also check: Best Buy" data-dimension48="Also check: Best Buy" data-dimension25="$899">View Deal</a></p></div><h2 id="why-the-ps5-pro-offers-better-price-to-performance-right-now">Why the PS5 Pro offers better price-to-performance right now</h2><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/2zd1Hbj9Pxc" allowfullscreen></iframe></div></div><p>To match the PS5 Pro’s real-world performance — consistent 4K/60 fps with ray tracing in optimized games, roughly in RTX 4070/5070 territory — you’re generally looking at a gaming PC that runs $1,000 to $1,500 or more for new parts in today’s market. Recent breakdowns from builders and tech channels like <a href="https://youtu.be/T-yqMN_gqb4?si=WLBTLJ5jFt9CiPkX&t=985" target="_blank">Digital Foundry</a> put equivalent rigs in exactly that range.</p><p>For example, a solid mid-to-high-end build with an AMD Ryzen 5 7600X3D (or similar CPU), an AMD RX 9060 XT 16GB or Nvidia RTX 5060 Ti 16GB GPU, 32GB of RAM, and a 2TB SSD typically lands around $963–$1,200 for the core components alone. That doesn’t include a <a href="https://www.tomsguide.com/reviews/windows-11">Windows 11</a> license, a decent case, PSU, or any peripherals.</p><p>Pre-built options with matching GPUs usually start at $1,000 and climb to $1,600. The GPUs themselves (RX 9060 XT 16GB and RTX 5060 Ti 16GB) are hovering around $450–$550 on the street right now — and that’s if you catch a decent deal, as component prices keep fluctuating.</p><p>Even with the PS5 Pro’s own price increase, equivalent PCs are still pricier to build from scratch.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-X7qznW"></div>                            </div>                            <script src="https://kwizly.com/embed/X7qznW.js" async></script><h2 id="a-head-to-head-comparison">A head-to-head comparison</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="DJwAH5Qdj6ginZR2kxbKn7" name="PS5 Pro-22.jpg" alt="PS5 Pro" src="https://cdn.mos.cms.futurecdn.net/DJwAH5Qdj6ginZR2kxbKn7.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 keep it simple, here’s an easy side-by-side look at the PS5 Pro versus a comparable gaming PC:</p><div ><table><thead><tr><th class="firstcol empty" ></th><th  ><p>PS5 Pro ($899)</p></th><th  ><p>Equivalent gaming PC (~$1,000–$1,500)</p></th><th  ><p>Winner</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Upfront cost</strong></p></td><td  ><p>Lower: Console, controller, and 2TB SSD</p></td><td  ><p>Higher (parts + OS license + extras if needed)</p></td><td  ><p>PS5 Pro</p></td></tr><tr><td class="firstcol " ><p><strong>Performance</strong></p></td><td  ><p>Optimized 4K/60fps & RT, plug-and-play</p></td><td  ><p>Similar or slightly better ceiling, but requires tweaking</p></td><td  ><p>Tie (PC has flexibility)</p></td></tr><tr><td class="firstcol " ><p><strong>Games & ecosystem</strong></p></td><td  ><p>PS5 exclusives & PS Plus (~$80–160/year for multiplayer + free games)</p></td><td  ><p>Steam sales, mods, mostly free multiplayer</p></td><td  ><p>Depends on your library</p></td></tr><tr><td class="firstcol " ><p><strong>Ease of use</strong></p></td><td  ><p>Simple to set up, quiet, power-efficient</p></td><td  ><p>More tinkering, higher power bill</p></td><td  ><p>PS5 Pro</p></td></tr><tr><td class="firstcol " ><p><strong>Longevity/upgrades</strong></p></td><td  ><p>Generally good for 5–7+ years</p></td><td  ><p>Fully upgradable</p></td><td  ><p>PC</p></td></tr><tr><td class="firstcol " ><p><strong>Multi-use</strong></p></td><td  ><p>Gaming & streaming/media only</p></td><td  ><p>Gaming, work, productivity, content creation, etc</p></td><td  ><p>PC</p></td></tr></tbody></table></div><p>If you just want to play games without the hassle, the PS5 Pro is the smarter short-term buy. Your total cost of ownership stays lower because you’re not nickel-and-diming for an operating system or basic setup. And if you already own a bunch of PS4 and PS5 games, it’s a natural upgrade path.</p><h2 id="when-pc-gaming-wins-on-value">When PC gaming wins on value</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="NAoEFBMgeCbSCgBV8JdJMd" name="HP Omen 35L-06-LIST" alt="HP Omen 35L" src="https://cdn.mos.cms.futurecdn.net/NAoEFBMgeCbSCgBV8JdJMd.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>Before anyone thinks I’m just ragging on PCs, full disclosure: I’m a PC gamer myself. The PS5 Pro makes sense for many people, but there are definitely scenarios where a gaming PC is the better option.</p><p>If you already have the basics — a solid monitor, keyboard/mouse, and a Windows license — then upgrading specific components (like your CPU or GPU) can make a lot of sense. You’ll keep enjoying cheaper games through constant Steam sales, which can save you hundreds over time.</p><p>Then there’s the huge library of game mods, custom peripherals, and overall freedom that the PS5 Pro simply can’t match. Don’t dismiss the used or refurbished parts market either — just stick with reputable sellers so you don’t get ripped off.</p><p>To help you out, here is a strong mid-range PC you should consider if you don't want a PS5 Pro.</p><div class="product"><a data-dimension112="04798718-cfcf-44a9-9643-9ab3cca40da3" data-action="Deal Block" data-label="Currently $1,129.99, this pre-built packs an 8-core AMD Ryzen 7 8700F CPU, Radeon RX 7700 16GB GPU, 16GB DDR5 RAM, and 1TB PCIe SSD. It can deliver capable 4K gaming with FSR upscaling to match the PS5 Pro while offering a stronger CPU for multitasking. At roughly $230 more than the $899 PS5 Pro (and half the storage), it’s a smart pick if you already own peripherals and want long-term flexibility over console simplicity." data-dimension48="Currently $1,129.99, this pre-built packs an 8-core AMD Ryzen 7 8700F CPU, Radeon RX 7700 16GB GPU, 16GB DDR5 RAM, and 1TB PCIe SSD. It can deliver capable 4K gaming with FSR upscaling to match the PS5 Pro while offering a stronger CPU for multitasking. At roughly $230 more than the $899 PS5 Pro (and half the storage), it’s a smart pick if you already own peripherals and want long-term flexibility over console simplicity." data-dimension25="$1129" href="https://www.bestbuy.com/product/cyberpowerpc-gaming-desktop-amd-ryzen-7-8700f-amd-radeon-rx-7700-16gb-16gb-ddr5-1tb-pcie-4-0-ssd-black/J3L7GQWSSF/sku/6637827?utm_source=feed&extStoreId=887&ref=212&loc=23718156910&gclsrc=aw.ds&gad_source=1&gad_campaignid=23713580333&gbraid=0AAAAAD-ORIiyZLBHzyoe7UCWFL3q_KVcI&gclid=Cj0KCQjw_IXQBhCkARIsADqELbLahPnPASkKBfwPNTRP-dMaCoPCiHe52HOnEfvW_1YH41FUlb3nMrYaAmLSEALw_wcB" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:956px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="vxogSMwe3VtYTU5x3c7koi" name="CyberPowerPC" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/vxogSMwe3VtYTU5x3c7koi.jpg" mos="" align="middle" fullscreen="" width="956" height="956" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Currently $1,129.99, this pre-built packs an 8-core AMD Ryzen 7 8700F CPU, Radeon RX 7700 16GB GPU, 16GB DDR5 RAM, and 1TB PCIe SSD. It can deliver capable 4K gaming with FSR upscaling to match the PS5 Pro while offering a stronger CPU for multitasking. At roughly $230 more than the $899 PS5 Pro (and half the storage), it’s a smart pick if you already own peripherals and want long-term flexibility over console simplicity.<a class="view-deal button" href="https://www.bestbuy.com/product/cyberpowerpc-gaming-desktop-amd-ryzen-7-8700f-amd-radeon-rx-7700-16gb-16gb-ddr5-1tb-pcie-4-0-ssd-black/J3L7GQWSSF/sku/6637827?utm_source=feed&extStoreId=887&ref=212&loc=23718156910&gclsrc=aw.ds&gad_source=1&gad_campaignid=23713580333&gbraid=0AAAAAD-ORIiyZLBHzyoe7UCWFL3q_KVcI&gclid=Cj0KCQjw_IXQBhCkARIsADqELbLahPnPASkKBfwPNTRP-dMaCoPCiHe52HOnEfvW_1YH41FUlb3nMrYaAmLSEALw_wcB" target="_blank" rel="nofollow" data-dimension112="04798718-cfcf-44a9-9643-9ab3cca40da3" data-action="Deal Block" data-label="Currently $1,129.99, this pre-built packs an 8-core AMD Ryzen 7 8700F CPU, Radeon RX 7700 16GB GPU, 16GB DDR5 RAM, and 1TB PCIe SSD. It can deliver capable 4K gaming with FSR upscaling to match the PS5 Pro while offering a stronger CPU for multitasking. At roughly $230 more than the $899 PS5 Pro (and half the storage), it’s a smart pick if you already own peripherals and want long-term flexibility over console simplicity." data-dimension48="Currently $1,129.99, this pre-built packs an 8-core AMD Ryzen 7 8700F CPU, Radeon RX 7700 16GB GPU, 16GB DDR5 RAM, and 1TB PCIe SSD. It can deliver capable 4K gaming with FSR upscaling to match the PS5 Pro while offering a stronger CPU for multitasking. At roughly $230 more than the $899 PS5 Pro (and half the storage), it’s a smart pick if you already own peripherals and want long-term flexibility over console simplicity." data-dimension25="$1129">View Deal</a></p></div><h2 id="bottom-line-5">Bottom line</h2><p>For reliable 4K performance with minimal compromises and almost zero headaches, the PS5 Pro is still the safest bet. Yes, it now carries a higher price tag, but it remains the more affordable way to jump into high-end gaming right out of the box. That said, if customization, upgrades, and long-term savings on games are your top priorities, a gaming PC is still worth considering.</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/computing/laptops/9-best-macbook-neo-accessories-for-under-usd50-you-need-right-now">9 best MacBook Neo accessories for under $50 you need right now</a></li><li><a href="https://www.tomsguide.com/computing/gaming-desktops/steam-machine-leak-suggests-4-different-models-and-a-queue-system-to-stop-scalpers">Steam Machine leak suggests 4 different models — and a queue system to stop scalpers</a></li><li><a href="https://www.tomsguide.com/computing/gaming-laptops/razer-blade-16-2026-review">I spent two weeks with the Razer Blade 16 (2026) — and it’s a serious gaming laptop powerhouse</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Steam Machine leak suggests 4 different models — and a queue system to stop scalpers ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/gaming-desktops/steam-machine-leak-suggests-4-different-models-and-a-queue-system-to-stop-scalpers</link>
                                                                            <description>
                            <![CDATA[ Valve is reportedly prepping 4 Steam Machine models, along with a reservation queue to curb scalpers and bots, but there's no news on pricing. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Bbv9mHv49sALP5vQMUXUT3</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/WLec9wkyEhDpZxRRLJYEqE-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 11 May 2026 15:23:06 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gaming Desktops]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Desktop Computers]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/WLec9wkyEhDpZxRRLJYEqE-1280-80.jpg">
                                                            <media:credit><![CDATA[Valve]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Valve Steam Machine]]></media:description>                                                            <media:text><![CDATA[Valve Steam Machine]]></media:text>
                                <media:title type="plain"><![CDATA[Valve Steam Machine]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/WLec9wkyEhDpZxRRLJYEqE-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review">Steam Controller</a> launched last week and <a href="https://www.tomsguide.com/news/live/valve-stream-controller-launch-live">sold out in less than 30 minutes</a>. As expected, eBay listings went live shortly after, with the peripheral marked up by hundreds of dollars. Valve has since implemented a queue system for Steam Controller orders, and if a recent rumor is true, the company will do the same for the upcoming Steam Machine.</p><p>As <a href="https://wccftech.com/steam-machine-queue-system-4-models-scalpers/" target="_blank">Wccftech</a> reports, a new leak suggests that Valve is bringing back the reservation queue system—the same one used for the <a href="https://www.tomsguide.com/opinion/steam-deck-oled-is-the-must-buy-handheld-of-2023-and-the-perfect-holiday-gift-for-gamers">Steam Deck’</a>s launch. That alone is interesting, but the leak also suggests how many versions of the PC/console hybrid we should expect.</p><div class="product"><a data-dimension112="1a22437f-994d-45af-8a6c-6e537931c2b0" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. Now with the new queue system, you might have a shot at nabbing one." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. Now with the new queue system, you might have a shot at nabbing one." data-dimension25="$99" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1232px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="p4kRCykqzQRFswEntyNcUE" name="Steam Controller" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/p4kRCykqzQRFswEntyNcUE.jpg" mos="" align="middle" fullscreen="" width="1232" height="1232" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. Now with the new queue system, you might have a shot at nabbing one.<a class="view-deal button" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow" data-dimension112="1a22437f-994d-45af-8a6c-6e537931c2b0" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. Now with the new queue system, you might have a shot at nabbing one." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. Now with the new queue system, you might have a shot at nabbing one." data-dimension25="$99">View Deal</a></p></div><p>For those who don’t know, the reservation queue is tied to a vetted Steam account. By requiring a purchase history or a verified account, Valve can prevent scalpers from using thousands of burner bots to swarm checkout pages. Those who’ve had active Steam accounts for an unspecified amount of time will get priority on the line. Anyone trying to flip a console on eBay for a 300% markup will be out of luck.</p><p>One of the more interesting details from this alleged leak is that there will be four distinct models. Valve has confirmed 512GB and 2TB models, but we can make educated guesses about the other two. As Wccftech notes, one could have 1TB of storage, while the other could be a bundle with the Steam Controller. I agree with this assessment.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-evvmme"></div>                            </div>                            <script src="https://kwizly.com/embed/evvmme.js" async></script><p>The big question about the Steam Machine is its price. Given the ongoing RAM crisis, it’s safe to assume Valve is waiting as long as possible before revealing the official cost. If the company can keep prices in the $599 to $899 range, it would certainly undercut the PS5 Pro, which now costs $899 after PS5 price hikes.</p><p>Given the unofficial nature of this story, please take it with a healthy dose of skepticism. We’ll keep you updated on any further developments, so stay tuned for more!</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/computing/gaming-laptops/razer-blade-16-2026-review">I spent two weeks with the Razer Blade 16 (2026) — and it’s a serious gaming laptop powerhouse</a></li><li><a href="https://www.tomsguide.com/best-picks/best-computers">Best computers in 2026: Our 7 top picks after 500+ hours of testing</a></li><li><a href="https://www.tomsguide.com/best-picks/best-pc-game-controllers">I’ve been gaming for 25 years and these are the best PC controllers in 2026 worth your money</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I spent two weeks with the Razer Blade 16 (2026) — and it’s a serious gaming laptop powerhouse ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/gaming-laptops/razer-blade-16-2026-review</link>
                                                                            <description>
                            <![CDATA[ The Razer Blade 16 impresses thanks to its slim design, gorgeous OLED panel, and strong gaming performance. While expensive, you’re getting a true premium gaming experience. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">ywjGXX4Ebp2zZSdEVjJjiZ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/KgJAQUUFGBbYccwsFebiCi-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 09 May 2026 10:00:00 +0000</pubDate>                                                                                                                                <updated>Mon, 11 May 2026 08:33:38 +0000</updated>
                                                                                                                                            <category><![CDATA[Gaming Laptops]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Laptops]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/KgJAQUUFGBbYccwsFebiCi-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Razer Blade 16 (2026)]]></media:description>                                                            <media:text><![CDATA[Razer Blade 16 (2026)]]></media:text>
                                <media:title type="plain"><![CDATA[Razer Blade 16 (2026)]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/KgJAQUUFGBbYccwsFebiCi-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Razer Blade 16 (2026) is a gaming laptop that makes no compromises. It has an ultraportable design, yet a monstrous gaming beast is packed inside. Though you’ll pay top dollar for Razer’s latest, you’ll get a superlative gaming experience.</p><p>Inside, it packs the latest Nvidia RTX 50-series GPU, along with either an AMD Ryzen 9 or an Intel Core Ultra 9 CPU. That, along with up to 64GB of RAM, means you’ll have little trouble running the <a href="https://www.tomsguide.com/best-picks/best-PC-games">best PC games</a> with graphics and resolution cranked to the max. No matter what I threw at it, the Razer Blade ran buttery smooth.</p><p>Like last year’s model, the new Blade 16 has a gorgeous OLED panel that delivers deep contrast and vivid colors. It also delivers excellent HDR brightness for an OLED gaming laptop. Whether it’s your favorite game or a streaming show, everything on the display will look its best.</p><p>Design-wise, the Razer Blade 16 impresses with its sturdy, CNC-milled aluminum all-black chassis. Without the green Razer logo on the lid, you might not even recognize it as a gaming laptop. Though not exactly light at nearly five pounds, its thin profile makes it easy to slip into your backpack.</p><p>While the Razer Blade 16 (2026) demands a steep asking price and can run very hot during demanding games, it’s undeniably one of the <a href="https://www.tomsguide.com/best-picks/best-gaming-laptops">best gaming laptops</a> I’ve reviewed. If you’re in the market for a slim gaming laptop with power to spare, this is the machine to get. Find out why in my full review.</p><h3 class="article-body__section" id="section-razer-blade-16-review-2026-cheat-sheet"><span>Razer Blade 16 review (2026): Cheat sheet</span></h3><ul><li><strong>What is it?</strong> The Razer Blade 16 is a thin and powerful gaming laptop featuring the latest high-end components.</li><li><strong>Who is it for?</strong> For anyone who wants a premium gaming laptop and is willing to pay top dollar for it.</li><li><strong>What does it cost?</strong> The Razer Blade 16 (2026) starts at $2,399 on <a href="https://www.razer.com/gaming-laptops/razer-blade-16/RZ09-05285EN3-R3U1" target="_blank" rel="nofollow">Razer’s website</a>. As configured, our review unit is valued at $4,899.</li><li><strong>What do we like?</strong> We like the slim design, incredible gaming performance, and vivid OLED panel.</li><li><strong>What don’t we like?</strong> We don’t like the steep asking price, and that it runs too hot and loud under heavy load.</li></ul><h3 class="article-body__section" id="section-razer-blade-16-review-2026-specs"><span>Razer Blade 16 review (2026): Specs</span></h3><div ><table><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>Razer Blade 16 (starting)</strong></p></th><th  ><p><strong>Razer Blade 16 (tested)</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p>$2,399</p></td><td  ><p>$4,899</p></td></tr><tr><td class="firstcol " ><p><strong>Display</strong></p></td><td  ><p>16-inch (2560x1600) 240 Hz OLED</p></td><td  ><p>16-inch (2560x1600) 240 Hz OLED</p></td></tr><tr><td class="firstcol " ><p><strong>CPU</strong></p></td><td  ><p>AMD Ryzen 9 365</p></td><td  ><p>Intel Core Ultra 9 358H</p></td></tr><tr><td class="firstcol " ><p><strong>GPU</strong></p></td><td  ><p>Nvidia GeForce RTX 5060</p></td><td  ><p>Nvidia GeForce RTX 5090</p></td></tr><tr><td class="firstcol " ><p><strong>RAM</strong></p></td><td  ><p>16GB</p></td><td  ><p>32GB</p></td></tr><tr><td class="firstcol " ><p><strong>Storage</strong></p></td><td  ><p>1TB</p></td><td  ><p>2TB</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>3x USB-A, 2x USB-C, 1x microSD, 1x HDMI 2.1</p></td><td  ><p>3x USB-A, 2x USB-C, 1x MicroSD, 1x HDMI 2.1</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Wi-Fi 7, Bluetooth 5.4 </p></td><td  ><p>Wi-Fi 7, Bluetooth 5.4 </p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>13.9 x 9.8 x 0.6 inches</p></td><td  ><p>13.9 x 9.8 x 0.6 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>4.7 pounds</p></td><td  ><p>4.7 pounds</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-razer-blade-16-review-2026-the-ups"><span>Razer Blade 16 review (2026): The ups</span></h3><p>The Razer Blade 16 (2026) is an absolute powerhouse thanks to its beefy specs, but its elegant design and superb display also add to its allure.</p><h2 id="thin-and-light-design">Thin and light design</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="e7gKgkvtHgqsnGYEA4FbMP" name="Razer-Blade-16-(2026)--12" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/e7gKgkvtHgqsnGYEA4FbMP.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 Razer Blade 16 is one of the loveliest-looking gaming laptops I’ve ever reviewed. Its slim profile, rounded edges, and sturdy aluminum frame could make you mistake it for a high-end work notebook rather than a gaming machine. Not only does it look great, but its smooth surface also makes it a pleasure to hold.</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="3DxuD5tGaLHd2g4V2KJsVa" name="Razer-Blade-16-(2026)--14" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/3DxuD5tGaLHd2g4V2KJsVa.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>Measuring 13.9 x 9.8 x 0.6 inches and weighing 4.7 pounds, the Razer Blade 16 makes for an unobtrusive travel partner. Sure, you’ll feel its weight in your backpack, but it won’t exactly break your back. It’s rare for a gaming laptop to be this thin and light, which is a major selling point.</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="aZYxcv23tukmJrKwh5Tq8U" name="Razer-Blade-16-(2026)--9" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/aZYxcv23tukmJrKwh5Tq8U.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>Despite its thin profile, the Razer Blade 16 doesn’t skimp on ports. It packs nearly all the ports you need, including three USB-A, two USB-C, one HDMI, and a microSD reader. You don’t get an Ethernet port, which is a bit of a bummer, but you still get more than enough ports to make this your primary work PC at home.</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="Mdi5vX7TurJPfdGcaXFraN" name="Razer-Blade-16-(2026)--11" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/Mdi5vX7TurJPfdGcaXFraN.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 keyboard is another highlight, thanks to its thick, responsive keys. Travel distance isn’t shallow, which makes for a delightful typing experience. I’m also a fan of the touchpad, since its large size makes it easy to make gestures and swipes. While not as good as a proper mechanical keyboard, the board here is quite great for a gaming laptop.</p><h2 id="vivid-oled-panel">Vivid OLED panel</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="jALcY63fiV95fyzfPvtjDV" name="Razer-Blade-16-(2026)--7" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/jALcY63fiV95fyzfPvtjDV.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 OLED panel on the Razer Blade 16 is one of its biggest selling points. Whether it was the neon-drenched streets of <a href="https://www.tomsguide.com/opinion/cyberpunk-2077-is-finally-worth-buying-heres-why">Cyberpunk 2077</a>’s Night City or the vast open expanses of <a href="https://www.tomsguide.com/us/red-dead-redemption-2,review-5905.html">Red Dead Redemption 2</a>, everything looked bright and colorful to my eyes. You want games to look as good as they run, and you certainly get that here.</p><div ><table><caption>Display benchmarks</caption><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>Razer Blade 16 (2026)</strong></p></th><th  ><p><strong>Asus ROG Zephyrus Duo (2026)</strong></p></th><th  ><p><strong>Alienware 16 Area-51 (2026)</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Nits (brightness)</strong></p></td><td  ><p>408 (SDR) | 586 (HDR)</p></td><td  ><p>439 (SDR) | 650 (HDR)</p></td><td  ><p>368 (SDR) | 556 (HDR)</p></td></tr><tr><td class="firstcol " ><p><strong>sRGB</strong></p></td><td  ><p>127%</p></td><td  ><p>116.5%</p></td><td  ><p>132.2%</p></td></tr><tr><td class="firstcol " ><p><strong>DCI-P3</strong></p></td><td  ><p>90%</p></td><td  ><p>82.5%</p></td><td  ><p>93.7%</p></td></tr><tr><td class="firstcol " ><p><strong>Delta-E</strong></p></td><td  ><p>0.23</p></td><td  ><p>0.21</p></td><td  ><p>0.20</p></td></tr></tbody></table></div><p>As shown in the table above, the Razer Blade 16 delivers strong SDR and HDR brightness. It also features excellent color reproduction (sRGB and DCI-P3) and color accuracy (Delta-E). These values are comparable to those of other gaming laptops we recently tested, such as the <a href="https://www.tomsguide.com/computing/gaming-laptops/i-just-tested-this-usd5-500-dual-screen-gaming-laptop-with-rtx-5090-power-heres-what-happened-when-i-ran-two-games-at-once">Asus ROG Zephyrus Duo</a> and Alienware 16 Area-51.</p><p>The only minor downside is that the display is very glossy and easily picks up reflections and glare. You can mitigate this by playing in a darker room, but it’s something to keep in mind before you settle in to play games or watch videos.</p><h2 id="powerful-gaming-performance">Powerful gaming performance</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="q8HS5apRYSuUFYbqw5oFPa" name="Razer-Blade-16-(2026)--3" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/q8HS5apRYSuUFYbqw5oFPa.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 Razer Blade 16 I tested is a true gaming beast, thanks to its Intel Core Ultra 9 CPU, RTX 5090 GPU, and 32GB of RAM. Those specs also give it plenty of power for video and photo editing. Whether it's demanding tasks in everyday work, the Razer Blade is up to the job.</p><p>At 1080p with graphics set to max, Cyberpunk 2077 ran at around 60-70 frames per second during my testing. This is a very demanding game, so having it run so smoothly is impressive. With DLSS 4 enabled, I saw the fps climb to the mid-70s even when I bumped the resolution to 1440p.</p><div ><table><caption>Gaming benchmarks (fps @ 1800p)</caption><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>Razer Blade 16 (2026)</strong></p></th><th  ><p><strong>Asus ROG Zephyrus Duo (2026)</strong></p></th><th  ><p><strong>Alienware 16 Area-51 (2026)</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Assassin’s Creed Shadows</strong></p></td><td  ><p>45 fps</p></td><td  ><p>33 fps</p></td><td  ><p>43 fps</p></td></tr><tr><td class="firstcol " ><p><strong>Cyberpunk 2077</strong></p></td><td  ><p>41 fps</p></td><td  ><p>26 fps</p></td><td  ><p>38 fps</p></td></tr><tr><td class="firstcol " ><p><strong>Red Dead Redemption 2</strong></p></td><td  ><p>50 fps</p></td><td  ><p>38 fps</p></td><td  ><p>54 fps</p></td></tr></tbody></table></div><p>In our lab tests, where we run a game’s benchmarking tool with the display set to native resolution and graphics maxed out, the Razer Blade 16 also performed well compared to its competitors. Sure, you’re not seeing the desired minimum 60 fps, but the laptop can still play titles at acceptable frame rates even with everything cranked up.</p><p>I should note that while the Asus ROG Zephyrus Duo has the same specs as the Blade 16, it didn’t perform nearly as well because of different TDP and thermals—not to mention a different form factor. However, the Alienware 16, with its RTX 5080 GPU and a stronger Intel Core Ultra 9 CPU variant, was about on par with Razer’s beastly laptop.</p><h2 id="strong-battery-life">Strong battery life</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="HTYf34wuTNaAqDNhvMSaCf" name="Razer-Blade-16-(2026)--16" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/HTYf34wuTNaAqDNhvMSaCf.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’s usually not worth discussing a gaming laptop’s battery life, since most users keep these demanding machines plugged in for optimal performance. While you won’t get all-day gaming from the Razer Blade 16, it lasts surprisingly long for productivity.</p><div ><table><caption>Battery life test</caption><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Time (hours:mins)</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Razer Blade 16 (2026)</strong></p></td><td  ><p>12:46 (web surfing) | 1:41 (gaming)</p></td></tr><tr><td class="firstcol " ><p><strong>Asus ROG Zephyrus Duo (2026)</strong></p></td><td  ><p>6:48 (web surfing) | 1:07 (gaming)</p></td></tr><tr><td class="firstcol " ><p><strong>Alienware 16 Area-51</strong></p></td><td  ><p>3:33 (web surfing) | 1:02 (gaming)</p></td></tr></tbody></table></div><p>In our battery life test, which involves continuous Wi-Fi web surfing with the display set to 150 nits, the Razer Blade 16 (2026) lasted nearly 13 hours. That’s almost as long as the Dell XPS 16 (13 hours 6 minutes), which is extremely impressive. However, its gaming battery life was just under two hours, which is typical for a gaming laptop.</p><h3 class="article-body__section" id="section-razer-blade-16-review-2026-the-downs"><span>Razer Blade 16 review (2026): The downs</span></h3><p>The Razer Blade 16 is a phenomenal gaming laptop, but it has its shortcomings.</p><h2 id="very-expensive">Very expensive</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="Z4U6jLsUiQ5mjKFMkUsNKk" name="Razer-Blade-16-(2026)--8" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/Z4U6jLsUiQ5mjKFMkUsNKk.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>Let’s get the obvious one out of the way — the Razer Blade 16 ain’t cheap! While the starting price of $2,399 might not sound bad for a gaming laptop, you’re settling for a lower-end Nvidia RTX 5060 and less RAM. To get the most from this machine, you’ll want beefier components, which means paying a whole lot more.</p><p>If you want to upgrade to a configuration with an RTX 5080 GPU, an Intel Core Ultra 9 CPU, 1TB of storage, and 32GB of RAM, you’ll need to fork over a meaty $3,999. If you want to go all out with an RTX 5090, the same Intel processor, 2TB of storage, and 64GB of RAM, prepare your bank account for a $5,599 hit.</p><p>Though gaming laptops are notoriously expensive, the Razer Blade 16 demands a very steep price indeed.</p><h2 id="runs-loud-and-hot">Runs loud and hot</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="q4Kw7BGWjQ6xrU4Tatesn4" name="Razer-Blade-16-(2026)--15" alt="Razer Blade 16 (2026)" src="https://cdn.mos.cms.futurecdn.net/q4Kw7BGWjQ6xrU4Tatesn4.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>Thanks to the Razer Blade 16’s relatively lightweight design, it’s comfortable to keep on your lap while you work. However, if you plan to do anything intensive, like gaming or video editing, you won’t exactly have a “cool” experience.</p><p>On its underside, the Razer Blade reached 118 degrees Fahrenheit in our heat test. Since we consider anything above 95 degrees uncomfortable, that’s decidedly too hot.</p><p>This is par for the course with gaming laptops, but the Razer Blade 16 also gets very loud when you’re gaming. Because of that, you’ll want to wear a pair of the best headsets to cancel out the constant noise.</p><h3 class="article-body__section" id="section-razer-blade-16-review-2026-verdict"><span>Razer Blade 16 review (2026): Verdict</span></h3><p>The Razer Blade 16 (2026) is a fantastic gaming laptop that delivers a truly premium experience. Not only can it run even the most demanding games, but it does so in a sleek form factor that fits anywhere. I’ve tested many incredible gaming laptops over the years, and this one is now easily in my top 10. It’s that good.</p><p>Of course, the main drawback is the steep asking price. That’s likely due to RAMageddon, which is a shame. However, if money is no object and you need the best of the best, you won’t be disappointed with the Razer Blade 16 (2026). Right now, it’s my favorite gaming laptop of the year.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Valve is opening a Steam Controller reservation queue to combat resellers starting this weekend ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/gaming-peripherals/valve-is-opening-a-steam-controller-reservation-queue-to-combat-resellers-starting-this-weekend</link>
                                                                            <description>
                            <![CDATA[ Valve has a new reservation queue that should make it easier for you to get a Steam Controller. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">CDuXCumwxCaaW4p5so7Pkc</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Kj6wiCa3UKHcrsq83PFtWN-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 07 May 2026 20:02:42 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gaming Peripherals]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ scott.younker@futurenet.com (Scott Younker) ]]></author>                    <dc:creator><![CDATA[ Scott Younker ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/RZsUpqcJ6Uj2q83oCUwNhQ.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Scott Younker is the West Coast Reporter at Tom’s Guide. He covers all the latest tech news, including phones, computing and more. He’s been involved in tech since 2011 covering everything from cameras and swimming pool equipment to the latest gaming consoles and smart TVs. He is on a seemingly never ending hunt to build the easiest to use home media system. &lt;/p&gt;&lt;p&gt;Before Tom’s Guide, Scott worked for publications like &lt;em&gt;Digital Trends, Outdoor Photographer, Dead Beats Panel&lt;/em&gt;, and in a brief detour, &lt;em&gt;America’s Funniest Home Videos&lt;/em&gt;. Yes, he has seen more pratfalls, silly pets and ridiculous home movie fails than is reasonably healthy. &lt;/p&gt;&lt;p&gt;When not writing about the latest devices or advances in chipsets, be sure to ask about Scott about disc golf and sustainability, or just if you’re being cheeky, ask about his noodle arm. If you truly want to get nerdy, bring up board games and his ongoing losing streak. &lt;/p&gt;&lt;p&gt;Scott joined Tom&#039;s Guide in 2024 as the West Coast Reporter. He graduated from the School of Journalism at the University of Oregon with a degree in magazine journalism and a minor in communications. While there he blogged or wrote for several magazines including the Fluxx, Ethos and the Oregon Commentator. He briefly wrote and managed a moderately successful blog focused on web comics. &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/Kj6wiCa3UKHcrsq83PFtWN-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Steam Controller up close]]></media:description>                                                            <media:text><![CDATA[Steam Controller up close]]></media:text>
                                <media:title type="plain"><![CDATA[Steam Controller up close]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Kj6wiCa3UKHcrsq83PFtWN-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>When Valve finally loosed the new <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review">Steam Controller</a> on the world this past Monday (May 4) stock <a href="https://www.tomsguide.com/gaming/pc-gaming/the-steam-controller-is-officially-out-of-stock-but-valve-promises-a-restock-is-on-the-way">disappeared within 30 minutes</a> and reportedly broke Steam. At the time of writing, it's currently sold out everywhere except for scalper listings on eBay where some greedy pockets are demanding up to <a href="https://www.ebay.com/itm/147293873337?itmmeta=01KR1WCMG0Y59M0QFKREVZ3P0A&hash=item224b6624b9:g:ttoAAeSwajBp-OOV&itmprp=enc%3AAQALAAAAwDKQclQvzFwZQpmMrsO4LupnwVXaIyzWV9ItUAnr11XE8xCy0dTA78N7i8N8dFSTEYxB3Gb13OZt5tTu24e4xQ5RXyV5VpumYCeBegrnaevhPsnAdkMXjMrLPsELbT83uymOLhvGLTz0yPslG6spOfRpm87VdQ7ZONzNJ3AtewJ2lgQtBnWrdICMW8YTs%2FNV0k01KjcgL0lGmVsTK1BCrqprJM3kB4iyvaZIWx%2BcXpeX14f%2ByG5%2FCqmVFoV6IDqseg%3D%3D%7Ctkp%3ABk9SR4zIsrzAZw" target="_blank">three times the $99 price tag.</a></p><p>Today (May 7), <a href="https://store.steampowered.com/news/group/45479024/view/702141174212725149" target="_blank">Valve announced a new plan</a> to help more gamers get their paws on a Steam Controller. The company also acknowledged that the "experience" of trying to buy it was "incredibly frustrating."</p><p>The Steam Controller is one of the <a href="https://www.tomsguide.com/best-picks/best-pc-game-controllers">best PC game controllers</a>, so it's no surprise that it would get snatched up quickly. Valve's new plan aims to make buying one easier and while circumventing scalpers.</p><p>“We plan to continue replenishing stock as we get more in, but in the meantime wanted to share changes we’re making to improve the purchase experience and to limit reseller activity," the Valve announcement says.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-evvmme"></div>                            </div>                            <script src="https://kwizly.com/embed/evvmme.js" async></script><p>Starting on Friday (May 8) at 10 am PT/1 pm ET/6 pm BST, Valve is opening a reservation queue for the Steam Controller. Initially, the queue will only be available in US and Canada with the UK, EU and Australia in the following weeks.</p><p>Adding yourself to the queue puts you in line. When stock is available and it's your spot, you will have 72 hours to buy the controller. Order emails will be sent to your associated account. </p><p>There are some stipulations.</p><p>Valve says that anyone who has already purchased a Steam Controller is ineligible to reserve another one. The company did not specify how long that will last.</p><p>Additionally, your account must be in good standing on Steam and you need to have made a purchase on Steam prior to April 27, 2026.</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/gaming/nintendo/nintendo-switch-2-price-hike-fears-grow-after-reports-investors-dont-like-how-cheap-the-console-is">Nintendo Switch 2 price hike fears grow after reports investors don't like how cheap the console is</a></li><li><a href="https://www.tomsguide.com/audio/headphones/gaming-headphones-are-finally-good-for-listening-to-music-these-open-backs-prove-that-you-dont-need-two-separate-sets-of-cans">Gaming headphones are finally good for listening to music — these open-backs prove that you don’t need two separate sets of cans</a></li><li><a href="https://www.tomsguide.com/gaming/007-first-light-hands-on-review">I played 3 hours of 007 First Light — this could be the best Bond game since GoldenEye</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The Steam Controller is officially out of stock, but Valve promises a restock is on the way ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/pc-gaming/the-steam-controller-is-officially-out-of-stock-but-valve-promises-a-restock-is-on-the-way</link>
                                                                            <description>
                            <![CDATA[ Didn't get a Steam Controller on Monday? More are coming, but there's no definite timeline yet. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">hqHDkdftmDk4o2XQVRrhKJ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 06 May 2026 12:09:53 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tom.pritchard@futurenet.com (Tom Pritchard) ]]></author>                    <dc:creator><![CDATA[ Tom Pritchard ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/biCewUkKfSA6QnT2HxVc3f.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/VA2D2h27873kpRELmPwZHS-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Steam Controller on a desk.]]></media:description>                                                            <media:text><![CDATA[The Steam Controller on a desk.]]></media:text>
                                <media:title type="plain"><![CDATA[The Steam Controller on a desk.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The <a href="https://www.tomsguide.com/computing/peripherals/i-just-spent-48-hours-with-the-steam-controller-heres-my-honest-verdict">Steam Controller</a> officially<a href="https://www.tomsguide.com/news/live/valve-stream-controller-launch-live"> launched earlier this week</a> on May 4, and it's fair to say that demand was pretty high, with the controller officially selling out in around 30 minutes. That's bad news for any PC gamers hoping to pick one of these gamepads up for themselves, though it isn't entirely unexpected.</p><p>Thankfully, there is good news on the horizon, with <a href="https://x.com/valvesoftware/status/2051695149026353424" target="_blank">Valve</a> taking to social media to confirm that more Steam Controllers are on the way. "Steam Controller ran out faster than we anticipated, and we hate that not everyone who wanted one was able to get it," the message says. "We're working on getting more in stock and will have an update on expected timeline soon."</p><p>Obviously, the lack of a concrete timeline is disappointing for those of you who weren't able to get hold of a Steam Controller during Monday's drop. But at least we have hope that more will arrive in the near future, and disappointed fans won't need to pay overinflated prices from scalpers.</p><h2 id="don-t-feed-the-scalpers">Don't feed the scalpers</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="Kj6wiCa3UKHcrsq83PFtWN" name="Steam Controller-7" alt="Steam Controller up close" src="https://cdn.mos.cms.futurecdn.net/Kj6wiCa3UKHcrsq83PFtWN.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>You better believe there are scalpers already trying to cash in on the Steam Controller's low stock. The searches are muddied by the fact that people are trying to sell the<a href="https://www.tomsguide.com/us/valve-steam-controller,review-3263.html" target="_blank"> first-generation Steam Controller</a> from 2015, but the newer model can be found if you look carefully enough. </p><p>In fact, <a href="https://www.ebay.com/sch/i.html?_nkw=steam+controller&_sacat=0&_from=R40&_trksid=p4624852.m570.l1313" target="_blank" rel="nofollow">two listings</a> I found are trying to sell the controller for $329 and $93, respectively. The latter is also located in Australia, which means you're expected to pay $51 for shipping on top of the already extortionate price. </p><p>Needless to say, you should definitely not encourage these people and pay over the odds for your Steam Controller. It doesn't matter how good the new controller might be; it's definitely not worth paying two or three times the official price to get one quickly. Just like the <a href="https://www.tomsguide.com/news/forget-ps5-restocks-global-chip-shortage-now-spilling-over-to-all-of-these-products">PS5 shortages</a> that kicked off back in 2020, you're just going to have to be patient and wait for your turn to buy.</p><p>Your wallet will thank you, and you won't be left with the knowledge that you got ripped off by someone without any scruples. </p><h2 id="more-valve-hardware-may-be-coming-soon">More Valve hardware may be coming soon</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="HJ6ZRxVDUjBBGPfdRCPNrm" name="Steam Controller-12" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/HJ6ZRxVDUjBBGPfdRCPNrm.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>If the impending Controller restock wasn't enough to look forward to, there's speculation that the release of the<a href="https://www.tomsguide.com/gaming/pc-gaming/i-might-ditch-my-gaming-pc-for-the-steam-machine-heres-why"> Steam Machine</a> and <a href="https://www.tomsguide.com/computing/vr-ar/steam-frame-will-take-over-vr-in-2026-3-key-features-i-cant-wait-for">Steam Frame</a> may be coming up soon. Both the Steam Machine system and the Steam Frame VR headset have been <a href="https://www.tomsguide.com/computing/half-life-3-and-steam-machine-could-be-delayed-and-you-can-blame-the-ram-price-crisis-for-that">delayed thanks to the ongoing memory shortages</a>, and there's been no official word on when they might be released.</p><p>But the fact that<a href="https://x.com/SadlyItsBradley/status/2049899806709915761" target="_blank"> Valve has just imported</a> 50 tons of "games consoles" into the U.S. is hope for some official news soon. Some of this cargo may include new <a href="https://www.tomsguide.com/reviews/steam-deck-review-the-nintendo-switch-for-adults">Steam Decks</a>, and considering <a href="https://www.tomsguide.com/computing/hardware/steam-deck-oled-stock-is-drying-up-valve-confirms-and-the-ram-price-crunch-has-me-worried-for-the-steam-machine">stock has dried up since the start of the year,</a> that can only be a good thing. But that volume is more than people expected from Valve's handheld, and may mean one of the other systems is on its way very soon.</p><p>Sadly, we don't know more than that, and we'll have to wait for Valve to decide when it's ready to unveil a launch date for its upcoming systems. Here's hoping that this happens sooner rather than later.</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/computing/mini-pcs/i-gave-my-favorite-pocketable-mini-pc-an-instant-upgrade-with-this-docking-station-and-now-its-a-full-fledged-gaming-rig">I gave my favorite pocketable mini PC an instant upgrade with this docking station — and now it’s a full-fledged gaming rig</a></li><li><a href="https://www.tomsguide.com/gaming/pc-gaming/steam-controller-is-sold-out-skip-the-ebay-scalpers-and-grab-one-of-these-12-alternatives-instead">Steam Controller is sold out! Skip the eBay scalpers and grab one of these 12 alternatives instead</a></li><li><a href="https://www.tomsguide.com/gaming/handheld-gaming/valve-is-hard-at-work-on-steam-deck-2-but-steam-machine-and-steam-frame-are-held-hostage-by-ai-gold-rush">Valve is 'hard at work' on Steam Deck 2, but Steam Machine and Steam Frame are held hostage by AI gold rush</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Steam Controller is sold out! Skip the eBay scalpers and grab one of these 12 alternatives instead ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/pc-gaming/steam-controller-is-sold-out-skip-the-ebay-scalpers-and-grab-one-of-these-12-alternatives-instead</link>
                                                                            <description>
                            <![CDATA[ The Steam Controller sold out in minutes, but that doesn't mean you have to wait for a restock or pay huge prices to get an elite gaming experience on PC today. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">VYPqaHfwmvSZbVQTsiyZKc</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 05 May 2026 09:44:58 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ john-anthony.disotto@futurenet.com (John-Anthony Disotto) ]]></author>                    <dc:creator><![CDATA[ John-Anthony Disotto ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/apUjevMoC6MzjfVN7GBCoi.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;John-Anthony Disotto is the Collections Editor at Tom&#039;s Guide, curating advice on the best products to spend your hard-earned cash on. An award-winning journalist and longtime Apple expert, he previously covered AI at TechRadar and served as How To Editor at iMore.&lt;/p&gt;&lt;p&gt;He used to work for Apple as a technician focused on iOS and iPhone repairs at the Genius Bar and has used the Apple ecosystem for over a decade. In his spare time, John-Anthony can be found watching any sport under the sun, from football to darts, taking the term &#039;Lego house&#039; far too literally as he runs out of space to display any more plastic bricks, or chilling on the couch with his French bulldog, Kermit. &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/VA2D2h27873kpRELmPwZHS-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Steam Controller on a desk.]]></media:description>                                                            <media:text><![CDATA[The Steam Controller on a desk.]]></media:text>
                                <media:title type="plain"><![CDATA[The Steam Controller on a desk.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Steam Controller might just be the most hyped PC gaming controller launch of all time, and unfortunately, that means it sold out in minutes when it <a href="https://www.tomsguide.com/news/live/valve-stream-controller-launch-live">went on sale this week</a>.</p><p>Now, the next generation of Valve's PC controller is selling on eBay with some asking prices as high as $300 (crazy considering the controller retails for $100). </p><p>We don't know when the Steam Controller will restock, but here's hoping those of us who want one don't have to wait too long. That said, if you don't want to wait for a restock, I've chosen 12 alternatives that are all in the upper echelon of PC gaming controllers.</p><p>Whether you want a Steam Controller for TMR thumbsticks, low-latency 2.4Hz wireless gameplay, back paddles, or those awesome trackpads, you'll find a controller below that's in stock and capable of fulfilling some (but not all) of those needs.</p><p>So why pay scalper prices or wait for a restock when you can have an excellent gaming experience on PC with one of the 12 alternatives found below?</p>        <div class="featured_product_block featured_block_hero" data-id="2f91f3f5-65a1-46c6-ad75-2eb8c8d7636a">            <a href="https://www.amazon.com/dp/B0FC9DTDJ3" data-model-name="Razer Wolverine V3 Pro 8K (8000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/uhYsYUJDgPkdXg2ovz8Hcf.jpg" alt="Razer, Razer Wolverine V3 Pro"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Razer</div>                                        <div class="featured__title">Razer Wolverine V3 Pro 8K (8000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="81be475e-f36e-49bf-ae2e-d01bd96afb28">            <a href="https://www.amazon.com/dp/B0DBLMZJRJ" data-model-name="GameSir Cyclone 2 (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/Qi7vndFuw37DAE4kPpMzVg.jpg" alt="GameSir, GameSir Cyclone 2"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>GameSir</div>                                        <div class="featured__title">GameSir Cyclone 2 (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="7cbec354-46df-4a38-8ec4-aa81020b3b61">            <a href="https://www.amazon.com/dp/B0DR8V899R" data-model-name="8BitDo Ultimate 2 Wireless (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/HtGUUnv8B7FVA3c7zRVaS5.jpg" alt="8Bitdo, 8BitDo Ultimate 2"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>8Bitdo</div>                                        <div class="featured__title">8BitDo Ultimate 2 Wireless (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="6eb6c0e6-5ec3-43a9-8cc1-400c1b5eb128">            <a href="https://www.amazon.com/dp/B07SFKTLZM" data-model-name="Xbox Elite Series 2 (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/tNoeXYsesJYuvQdDFkiRGi.jpg" alt="Xbox, Xbox Elite Series 2"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Xbox</div>                                        <div class="featured__title">Xbox Elite Series 2 (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="6bbe96b9-4048-4d6f-bef2-0382c7970b7b">            <a href="https://www.amazon.com/dp/B0DTB3F17W" data-model-name="SCUF Valor Pro (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/E9FHCvpFkgZ6v9gDQD99xi.jpg" alt="SCUF, SCUF Valor Pro"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>SCUF</div>                                        <div class="featured__title">SCUF Valor Pro (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="ebc5b82b-031f-4411-a879-4f5dcbd53be2">            <a href="https://www.amazon.com/dp/B0FXDT6QC4" data-model-name="Flydigi Vader 5 Pro (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/f4CngkHtU9DtiaMk5Y9dpj.jpg" alt="FLYDIGI, Flydigi Vader 5 Pro"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>FLYDIGI</div>                                        <div class="featured__title">Flydigi Vader 5 Pro (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="f147dafc-0bac-4c87-88ed-a84447037e11">            <a href="https://www.amazon.com/dp/B0D7WYPB3V" data-model-name="PDP Victrix Pro BFG (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/QR6zN9HsXp8VzgmAqRAyfk.jpg" alt="PDP, PDP Victrix Pro BFG"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>PDP</div>                                        <div class="featured__title">PDP Victrix Pro BFG (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="bd487894-6f0d-4665-96e7-34996529b8c1">            <a href="https://www.amazon.com/dp/B0F14XLBDJ" data-model-name="NACON Revolution X Unlimited (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/uEqDGquSRMYgDGvfbMBBfm.jpg" alt="NACON, Nacon Revolution X Unlimited"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>NACON</div>                                        <div class="featured__title">NACON Revolution X Unlimited (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="3c88be74-16d1-4d8a-a5cf-64bc3317da19">            <a href="https://www.amazon.com/dp/B0D8T82K5C" data-model-name="PowerA Fusion Pro 4 Wired (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.37%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/NcTx7PfoL9DvfYAQK3E5Rn.jpg" alt="PowerA, PowerA Fusion Pro 4"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>PowerA</div>                                        <div class="featured__title">PowerA Fusion Pro 4 Wired (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="01c8ad59-cdb9-4039-b89a-10a2f68a666d">            <a href="https://www.amazon.com/dp/B0DLLKRFG8" data-model-name="HORI HORIPAD for Steam (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/uf3kkmF52VsqzxnBvU78Co.jpg" alt="HORI, Hori Wireless Horipad for Steam"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>HORI</div>                                        <div class="featured__title">HORI HORIPAD for Steam (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="4d6e2084-8956-421a-b01e-6371d3b617f1">            <a href="https://www.amazon.com/dp/B0CGWZBPQQ" data-model-name="GuliKit KK3 Max (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/93fYQsjRkTQcynCeyfadBE.jpg" alt="GuliKit, GuliKit KingKong 3 Max"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>GuliKit</div>                                        <div class="featured__title">GuliKit KK3 Max (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="daba8c2e-5850-4984-b32d-666e82ffed1c">            <a href="https://www.amazon.com/dp/B0CKXGNZZD" data-model-name="Machenike G5Pro (1000Hz)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.48%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/WfZcusgM4KB2ULP37k5jyE.jpg" alt="Machenike, Machenike G5pro"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Machenike</div>                                        <div class="featured__title">Machenike G5Pro (1000Hz)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div><h2 id="steam-controller-chaos">Steam Controller chaos</h2><p>I was lucky enough to snag a Steam Controller when it went on sale yesterday, but within minutes, I noticed listings appear on eBay as gamers swarmed social media with complaints about the ordering process.</p><p>I knew the Steam Controller would be popular (some people have been waiting a decade for a new one), but I didn't think the PC gamepad with trackpads would cause hysteria in this way.</p><p>In fact, I managed to buy one a couple of minutes before the official launch time, which made me think it would be an easy purchase for anyone willing to fork out the $100 RRP. Unfortunately, I was wrong.</p><p>Now, scalpers are listing pre-orders for exorbitant prices on platforms like eBay, and honestly, <em>no one should be lining those pockets</em> by paying 3x for a controller that is likely to be back in stock in the coming months, if not weeks.</p><p>Valve is on to a winner with the Steam Controller. In our <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review">Tom's Guide Steam Controller review</a>, my colleague Tony said, "The Steam Controller is a nearly perfect PC game controller thanks to its fantastic design, solid performance, simple pairing and charging, and extreme level of customization."</p><p>I can't wait to try the Steam Controller, but honestly, if you can't get your hands on one for that $100 price tag, you should opt for one of the alternatives I've listed above.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OzLJle"></div>                            </div>                            <script src="https://kwizly.com/embed/OzLJle.js" async></script>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested the new Steam Controller — and it's the only PC gamepad I'll ever need ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review</link>
                                                                            <description>
                            <![CDATA[ The Steam Controller is arguably the best PC game controller for Steam users, thanks to its ergonomic design and high degree of customization. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">pgfzGnjfhNHUY7BznZ49L6</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 04 May 2026 18:04:28 +0000</pubDate>                                                                                                                                <updated>Wed, 10 Jun 2026 14:33:27 +0000</updated>
                                                                                                                                            <category><![CDATA[Gaming Peripherals]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/VA2D2h27873kpRELmPwZHS-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Steam Controller on a desk.]]></media:description>                                                            <media:text><![CDATA[The Steam Controller on a desk.]]></media:text>
                                <media:title type="plain"><![CDATA[The Steam Controller on a desk.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The new Steam Controller ($99 / AU$149) is arguably the best peripheral for playing Steam games on PC and on the <a href="https://www.tomsguide.com/opinion/steam-deck-oled-is-the-must-buy-handheld-of-2023-and-the-perfect-holiday-gift-for-gamers">Steam Deck</a>. While we don’t yet have the Steam Machine this controller was supposed to ship with, having it available right now isn’t a bad compromise. Even without its parent console/PC hybrid, this is a brilliant controller that’s a major improvement over the controversial original that launched 11 years ago.</p><p>Don’t let pictures fool you, as the Steam Controller is only slightly bigger than an Xbox controller. Because of that, it feels natural to hold. Except for the large touchpads under the thumbsticks and four back buttons, the controller has the same basic layout you’re familiar with from other game pads.</p><p>Since this is a Steam device, pairing it with any machine running <a href="https://www.tomsguide.com/us/steamos-faq-machines,news-17614.html">SteamOS</a> or the Steam App is seamless. It’s also fun, as you can charge and pair the controller to your PC or handheld via an included puck. Though the puck makes charging and pairing simple, you can always connect via a USB cable or Bluetooth connection.</p><p>Though it’s pricier than a standard controller and isn’t compatible with gaming consoles, there’s no denying that Valve knocked it out of the park with the Steam Controller. As a dedicated Steam user, I might dabble with other controllers, but this will be my go-to from now on. Find out more in my full review.</p><div class="product"><a data-dimension112="6f8776aa-cda2-479c-b15a-aff75942fd4e" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension25="$99" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1232px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="p4kRCykqzQRFswEntyNcUE" name="Steam Controller" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/p4kRCykqzQRFswEntyNcUE.jpg" mos="" align="middle" fullscreen="" width="1232" height="1232" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4.<br><a class="view-deal button" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow" data-dimension112="6f8776aa-cda2-479c-b15a-aff75942fd4e" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension25="$99">View Deal</a></p></div><h3 class="article-body__section" id="section-steam-controller-review-cheat-sheet"><span>Steam Controller review: Cheat sheet</span></h3><ul><li><strong>What is it?</strong> It’s an update of the original Steam Controller, with a more ergonomic and practical design.</li><li><strong>Who is it for?</strong> This controller is for dedicated Steam users who want a controller that works seamlessly with Valve’s ecosystem.</li><li><strong>What does it cost?</strong> The Steam Controller costs $99 / AU$149 and is available only on the <a href="https://store.steampowered.com/hardware/steamcontroller" target="_blank" rel="nofollow"><u>Steam Store</u></a>.</li><li><strong>What do we like?</strong> We like the comfortable design, easy pairing with SteamOS, smooth performance, and high customization.</li><li><strong>What don’t we like?</strong> We don’t like that it doesn’t support other PC launchers or consoles.</li></ul><h3 class="article-body__section" id="section-steam-controller-review-specs"><span>Steam Controller review: Specs</span></h3><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Steam Controller</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p>$99 / AU$149</p></td></tr><tr><td class="firstcol " ><p><strong>Compatibility</strong></p></td><td  ><p>SteamOS</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Steam Controller Puck (2.4GHz Wireless), Bluetooth, USB-C</p></td></tr><tr><td class="firstcol " ><p><strong>Thumbsticks</strong></p></td><td  ><p>TMR</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>4.37 x 6.26 x 2.24 inches / 111mm x 159mm x 57mm</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>0.64 pounds / 292 grams</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-steam-controller-review-the-ups"><span>Steam Controller review: The ups</span></h3><p>The Steam Controller is the perfect controller for Steam users thanks to its comfortable build, intuitive control layout, extensive customization options, and simple pairing and charging.</p><h2 id="ergonomic-design">Ergonomic design</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="pYbKmQsMkuRoQvKm5FAh8c" name="Steam Controller-6" alt="The Steam Controller flat on a desk." src="https://cdn.mos.cms.futurecdn.net/pYbKmQsMkuRoQvKm5FAh8c.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>Design-wise, the Steam Controller is both traditional and unique. The top half has a layout similar to an Xbox controller, with a d-pad, face buttons, thumbsticks, and shoulder buttons. The bottom half is where things get interesting, as it’s rather large to accommodate the touchpads. This also gives your hands more room for a better grip.</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="DMZnrKJ8hvF2LA5XzD2cLW" name="Steam Controller-2" alt="The back of the Steam Controller." src="https://cdn.mos.cms.futurecdn.net/DMZnrKJ8hvF2LA5XzD2cLW.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 large back buttons are strategically placed right where your middle and ring fingers naturally rest. Since they’re pretty unintrusive, you can ignore them if you’re not a fan of back buttons. Like the back buttons, the shoulder buttons are also smartly placed where your fingers rest.</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="UwNaPz8frxECNkhbcBQRAc" name="Steam Controller-5" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/UwNaPz8frxECNkhbcBQRAc.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 controller has the same matte finish as the Steam Deck, which means it not only feels nice to hold, but it’s also very grippy.</p><h2 id="responsive-controls">Responsive controls</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="HJ6ZRxVDUjBBGPfdRCPNrm" name="Steam Controller-12" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/HJ6ZRxVDUjBBGPfdRCPNrm.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 Steam Controller is not only fun to hold, but it’s also extremely responsive. Valve could have easily just used the Steam Deck’s components, but the company went a step further by including some features you’d only find on pricier pro controllers.</p><p>First up are the new TMR thumbsticks, which are designed to be even more responsive and less prone to stick drift than Hall-effect sensors. I’ll spare you the details on how these magnetic technologies differ from one another, but suffice it to say that the TMR sticks on the Steam Deck feel amazing and allowed me to make small and large movements seamlessly.</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="t2uYK7KSJZephgu4LyShBk" name="Steam Controller-3" alt="The top of the Steam Controller" src="https://cdn.mos.cms.futurecdn.net/t2uYK7KSJZephgu4LyShBk.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>Then we have the haptic touchpads beneath the thumbsticks. Every click and thumb movement makes them vibrate. Thanks to their large size, you can use them in place of thumbsticks, which isn’t just a gimmick, since it makes playing point-and-click games much more intuitive. The original Steam Controller had super huge touchpads instead of traditional thumbsticks, so I’m glad Valve shrunk them without sacrificing performance.</p><p>The other inputs are just as great to use. While I wish the ABXY face buttons were a tad clickier, they work as well as you’d expect. The left and right bumpers are also relatively quiet and have a satisfying travel distance. This also applies to the trigger buttons, though they don’t have trigger locks to cut down the actuation point.</p><h2 id="unique-pairing-and-charging">Unique pairing and charging</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="2on6Q6pXBJRLv9qybxnqm9" name="Steam Controller-8" alt="Steam Controller puck" src="https://cdn.mos.cms.futurecdn.net/2on6Q6pXBJRLv9qybxnqm9.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>One of the coolest features is the included Steam Controller Puck. It's a 2.4GHz USB-C transmitter that can also charge the controller and pair it with the device you’re playing on.</p><p>Speaking of pairing, you can connect up to four Steam Controllers to the puck in case you want to play games with friends locally. It also magnetically attaches to the controller with a satisfying click.</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="Vnw4Z2Uhp2MxLz9byPeVi6" name="Steam Controller-9" alt="Steam Controller puck snapped on" src="https://cdn.mos.cms.futurecdn.net/Vnw4Z2Uhp2MxLz9byPeVi6.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>You connect the puck to your PC using the included USB-C to USB-A cable, though you can theoretically use any cable with power delivery. I like that you can keep the controller connected, easily snap it off to play wirelessly, and snap it back on when you’re done.</p><p>Valve claims the controller can last over 35 hours on a single charge. I haven’t had the controller long enough to fully drain it, but it has already lasted significantly longer than the PS5 DualSense. Based on what other reviewers have said about battery life, it appears Valve’s claims aren’t just baseless boasting.</p><h2 id="highly-customizable">Highly customizable</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="wXqarwHGksv9v9Rda4jNQG" name="Steam Controller-13" alt="Steam Controller customization" src="https://cdn.mos.cms.futurecdn.net/wXqarwHGksv9v9Rda4jNQG.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 Steam Controller offers a slew of customization options. For instance, you can program the dual touchpads to act as a mouse for shooters, a traditional D-Pad for 2D games, or even a scroll wheel for navigating menus. Other features also enable more fine-tuning for specific game genres, effectively giving you multiple controllers in a single device.</p><p>Naturally, you can remap all the buttons as you see fit. Beyond that, you can add visual overlays like Radial Menus to your screen to handle dozens of keyboard shortcuts with a quick thumb swipe. You can also make the haptic feedback provide clicks and notches to help guide your movements. These types of controls are perfect for games traditionally played with a mouse and keyboard.</p><p>There’s more I could detail, but let’s just say you could spend hours tinkering with all the customization options. And if you don’t, you can always download popular, pre-made configurations that players from the Steam community have created.</p><h3 class="article-body__section" id="section-steam-controller-review-the-downs"><span>Steam Controller review: The downs</span></h3><p>The Steam Controller is a brilliant peripheral for dedicated Steam users. However, it has one major flaw for those who play outside of Steam.</p><h2 id="for-steamos-only">For SteamOS only</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="Kj6wiCa3UKHcrsq83PFtWN" name="Steam Controller-7" alt="Steam Controller up close" src="https://cdn.mos.cms.futurecdn.net/Kj6wiCa3UKHcrsq83PFtWN.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 Steam Controller works seamlessly with SteamOS. That’s certainly a strength, but it’s also its main weakness. If you hoped to easily use Valve’s controller on other PC game launchers like the Epic Games Store or the Xbox App for PC, you’re going to be out of luck. This also applies to gaming consoles.</p><p>If you’re like me and rarely leave Steam when PC gaming, then this likely won’t be an issue. And given how clever the PC gaming community is, I’m sure someone will find a workaround before I finish this sentence. Again, this won’t be the end of the world for most players given Steam’s ubiquity, but it’s worth keeping in mind.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-evvmme"></div>                            </div>                            <script src="https://kwizly.com/embed/evvmme.js" async></script><h3 class="article-body__section" id="section-steam-controller-review-verdict"><span>Steam Controller review: Verdict</span></h3><p>Some believe that $99 / AU$149 is too much for the Steam Controller, but I say the price is more than justified for dedicated Steam users. Sure, Valve’s peripheral costs $20 to $30 more than a standard console controller, but it packs pro controller-like features for $50-$100 less than you’d pay for those premium devices. In that way, you’re actually getting a fantastic deal.</p><p>Though it’s admittedly strange to have the Steam Controller without the platform it was designed for, I’m glad that Valve decided to launch this peripheral now so we can get acclimated to it before the Steam Machine’s arrival. Like I said before, switching to another PC controller won’t be easy, since this one gives me everything I need. If you live in the Steam ecosystem, I’m sure you’ll feel the same way.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Steam Controller launch live — hands-on report, and latest stock updates from Valve ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/news/live/valve-stream-controller-launch-live</link>
                                                                            <description>
                            <![CDATA[ Valve's new Steam Controller launches today, and we've got the latest news, hands-on impressions, and the important buying information. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">fBCopZfBBhS4NYGgnqp2A</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Kj6wiCa3UKHcrsq83PFtWN-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 04 May 2026 12:34:00 +0000</pubDate>                                                                                                                                <updated>Tue, 05 May 2026 19:47:47 +0000</updated>
                                                                                                                                            <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ rory.mellon@futurenet.com (Rory Mellon) ]]></author>                    <dc:creator><![CDATA[ Rory Mellon ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/5Rv6LtQXMj5JB4Eu8Lt4Sn.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                        <dc:contributor><![CDATA[ Tony Polanco ]]></dc:contributor>
                                            <dc:contributor><![CDATA[ Scott Younker ]]></dc:contributor>
                                                                    <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/Kj6wiCa3UKHcrsq83PFtWN-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Steam Controller up close]]></media:description>                                                            <media:text><![CDATA[Steam Controller up close]]></media:text>
                                <media:title type="plain"><![CDATA[Steam Controller up close]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Kj6wiCa3UKHcrsq83PFtWN-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Steam Controller launch week has arrived. Valve’s second stab at a dedicated PC gaming pad is <strong>now available</strong> on Steam. It already looks like a contender for our <a href="https://www.tomsguide.com/best-picks/best-pc-game-controllers">best PC gaming controller</a> guide. However, it's proving popular and is currently <strong>out of stock </strong>after selling out in just 30 minutes.</p><p>As the name suggests, this PC controller is “built for steam” and is compatible not just with the <a href="https://www.tomsguide.com/us/best-gaming-pc,review-2219.html">best gaming PCs</a> but also with gaming laptops, the <a href="https://www.tomsguide.com/reviews/steam-deck-oled">Steam Deck OLED</a>, and, naturally, the upcoming <a href="">Steam Machine</a>. </p><p>It offers all the basic controller features, including magnetic thumbsticks, haptic motors for rumbles, and 35+ hours of battery life on a single charge. Plus, it also packs two trackpads and mappable back buttons. It’s not a cheap pad at $99, but if you’re a serious PC player, it looks essential.</p><p>Again, the controller is currently out of stock as of 5 a.m. ET on May 5. <a href="https://x.com/valvesoftware/status/2051695149026353424" target="_blank">Valve promises a stock update "soon,"</a> but we have no idea when that could be.</p><p>To that end, keep it locked to Tom's Guide for the latest restock updates. In the meantime, check out our full <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review">Steam Controller review</a> if you're still deciding if it's worth all the effort.</p><h3 class="article-body__section" id="section-steam-controller-quick-links"><span>Steam Controller - quick links</span></h3><ul><li><strong>Steam Controller: </strong><a href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><strong>$99 @ Steam</strong></a><strong> (check stock)</strong></li><li><strong>Steam Controller: </strong><a href="https://www.amazon.com/s?k=steam+controller" target="_blank" rel="nofollow"><strong>check stock @ Amazon</strong></a></li><li><strong>Steam Controller: </strong><a href="https://www.bestbuy.com/site/searchpage.jsp?id=pcat17071&st=steam%20controller" target="_blank" rel="nofollow"><strong>check stock @ Best Buy</strong></a></li></ul><h3 class="article-body__section" id="section-steam-controller-retailer-listings"><span>Steam Controller - retailer listings</span></h3><div class="product"><a data-dimension112="6d45f81e-accb-43f8-9763-f5e7a500b05d" data-action="Deal Block" data-label="The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life." data-dimension48="The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life." data-dimension25="$99" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1232px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="p4kRCykqzQRFswEntyNcUE" name="Steam Controller" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/p4kRCykqzQRFswEntyNcUE.jpg" mos="" align="middle" fullscreen="" width="1232" height="1232" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life. <a class="view-deal button" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow" data-dimension112="6d45f81e-accb-43f8-9763-f5e7a500b05d" data-action="Deal Block" data-label="The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life." data-dimension48="The second-generation Steam Controller launches today (May 4). It's a next-generation pad designed to take full advantage of Valve's popular PC gaming platform. It includes magnetic thumbsticks, haptic motors for rumble, dual trackpads, four customisable back buttons, and 35+ of battery life." data-dimension25="$99">View Deal</a></p></div><h2 id="welcome-to-our-steam-controller-live-coverage">Welcome to our Steam Controller live coverage</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="pYbKmQsMkuRoQvKm5FAh8c" name="Steam Controller-6" alt="The Steam Controller flat on a desk." src="https://cdn.mos.cms.futurecdn.net/pYbKmQsMkuRoQvKm5FAh8c.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>Hello! PC gamers rejoice, today is the day that Valve launches its new Steam Controller, a premium pad designed specifically (and exclusively) for PC gaming, and here at Tom's Guide we'll be guiding you through launch day. In this live blog you'll find the latest news, our hands-on impression and the important buying info.</p><h2 id="steam-controller-costs-how-much">Steam Controller costs how much?</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="HJ6ZRxVDUjBBGPfdRCPNrm" name="Steam Controller-12" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/HJ6ZRxVDUjBBGPfdRCPNrm.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 biggest question you're probably asking about the Steam Controller is the price, and fortunately, Valve has confirmed this key detail ahead of the order floodgate opening in just a little over four hours time. The pad will cost <strong>$99</strong>, or for the folks in my native U.K., it'll run you <strong>£85</strong>. That makes it more expensive than a PS5 DualSense or Xbox Controller, but it is cheaper than either console's "Pro" pad.</p><h2 id="console-players-this-one-ain-t-for-you">Console players, this one ain't for you!</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:2629px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="jdwLjBSgdJsHB9pqpKrXWR" name="ps5 dualsense Geoff Keighley.jpg" alt="PS5 dualsense controller" src="https://cdn.mos.cms.futurecdn.net/jdwLjBSgdJsHB9pqpKrXWR.jpg" mos="" align="middle" fullscreen="" width="2629" height="1479" 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 own a PS5 or Xbox Series X and you're eyeing up the Steam Controller, don't be fooled into picking one up. This is a dedicated PC gaming controller, and isn't compatible with Sony or Microsoft's gaming consoles. It's designed solely for use with Valve's Steam platform, and Steam-dedicated hardware (like the Steam Deck and the upcoming Steam Machine). Console gamers will need to stick with their DualSense or Xbox controller because the Steam Controller is for the PCMR only.</p><h2 id="steam-controller-is-just-hours-away">Steam Controller is just hours 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="VA2D2h27873kpRELmPwZHS" name="Steam Controller-1-LIST" alt="The Steam Controller on a desk." src="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS.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>Consider this is your four hour warning! The Steam Controller will be available to purchase at 10 a.m. PT / 1 p.m. ET / 6 p.m. BST, as of the time of this post, that is just four hours away. So, if you're already sold, make sure you set a reminder, stock levels are unknown and you don't want to miss out. Of course, you can just stick with this live bog, and I'll be sure to alert you the moment the order button is live.</p><h2 id="here-s-our-steam-controller-unboxing">Here's our Steam Controller unboxing!</h2>                    <div class= "tiktok-wrapper" style="min-height: 750px;"><blockquote class="tiktok-embed" cite="https://www.tiktok.com/@tomsguide/video/7634624250518785294" data-video-id="7634624250518785294" 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="♬ Pew Pew！ - Official Sound Studio" href="https://www.tiktok.com/music/Pew-Pew-6815535271791036418">♬ Pew Pew！ - Official Sound Studio</a></section>                    </blockquote></div>                <p>One of my favorite parts of getting new gaming hardware and accessories is the first unboxing experience, but if you don't mind having that moment spoiled ahead of time, check out our Steam Controller unboxing video linked above!</p><h2 id="we-ve-got-our-hands-on-a-steam-controller">We've got our hands on a Steam Controller</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="HJ6ZRxVDUjBBGPfdRCPNrm" name="Steam Controller-12" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/HJ6ZRxVDUjBBGPfdRCPNrm.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>My colleague Tony Polanco has <a href="https://www.tomsguide.com/computing/peripherals/i-just-spent-48-hours-with-the-steam-controller-heres-my-honest-verdict">spent the weekend with a Steam Controller</a>. I swear I'm not jealous (okay... I totally am)! His initial impressions are pretty darn positive, and he even declares that it "lives up to the hype." If you're on the fence about whether to add one to your cart later today, be sure to read his article right now.</p><h2 id="that-s-one-powerful-puck">That's one powerful puck!</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="2on6Q6pXBJRLv9qybxnqm9" name="Steam Controller-8" alt="Steam Controller puck" src="https://cdn.mos.cms.futurecdn.net/2on6Q6pXBJRLv9qybxnqm9.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 Steam Controller comes with an extra in the box, the snappily named, Steam Controller Puck. This little device is a wireless transmitter that serves two purposes. Firstly, it provided a fast/stable connection for your controller, allowing you to use it as a wired pad (if you don't want to use wireless Bluetooth, or USB). It also serves as a charging station, with your Steam Controller snapping onto the puck with a click.</p><h2 id="just-look-at-those-back-buttons">Just look at those back buttons!</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="DMZnrKJ8hvF2LA5XzD2cLW" name="Steam Controller-2" alt="The back of the Steam Controller." src="https://cdn.mos.cms.futurecdn.net/DMZnrKJ8hvF2LA5XzD2cLW.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>One of the things that appeals to me most about the Steam Controller is in the in-built back buttons. Remember, typically on console, you need to spring for a "Pro" controller to get these, but on the Steam Controller you have four out of the box. These can be mapped as you wish, allowing you to pick which inputs they offer.</p><h2 id="one-hour-to-drop">One hour to drop</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="Kj6wiCa3UKHcrsq83PFtWN" name="Steam Controller-7" alt="Steam Controller up close" src="https://cdn.mos.cms.futurecdn.net/Kj6wiCa3UKHcrsq83PFtWN.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>We're just one hour away from launch.</p><p>While we wait, let us know what interests you about the Steam Controller?</p><h2 id="less-than-20-minutes-to-go">Less than 20 minutes to go!</h2><p>If you're planning to pick up a Steam Controller as soon as the order button goes live, now is the time to get in position. Get your tab open, and get ready. There's less than 20 minutes until the floodgates open and Valve lets people start purchasing.</p><h2 id="steam-controller-orders-are-live">Steam Controller orders are LIVE!</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="VA2D2h27873kpRELmPwZHS" name="Steam Controller-1-LIST" alt="The Steam Controller on a desk." src="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS.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><ul><li><strong>Steam Controller: </strong><a href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><strong>$99 @ Steam</strong></a></li></ul><p>And just as the clock strikes 10 a.m. PT, the Steam Controller order button has turned blue, and you can now pick up yours. At present, Steam is the only place to purchase a Steam Controller, so if you want one ASAP, get your order in right now.</p><h2 id="steam-controller-stock-seems-to-be-holding-strong">Steam Controller stock seems to be holding strong</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="wXqarwHGksv9v9Rda4jNQG" name="Steam Controller-13" alt="Steam Controller customization" src="https://cdn.mos.cms.futurecdn.net/wXqarwHGksv9v9Rda4jNQG.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>10 minutes later, and the <strong>Steam Controller is still in stock</strong>. Steam seems to be handling the traffic influx well, I did have a momentary issue reloading the page, but it's otherwise been smooth sailing. I can still add the Steam Controller to my cart with minimal fuss, so if you're late on the scene, you haven't missed out yet!</p><h2 id="the-dreaded-out-of-stock-warning-has-appeared">The dreaded "Out of stock" warning has appeared</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="NcVbKsrfkY4rawQRAzDuYV" name="Steam Controller-11" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/NcVbKsrfkY4rawQRAzDuYV.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>Uh oh! Just shy of 40 minutes after the Steam Machine order page went live, and we've got the three words nobody wants to hear: Out of stock. It looks like the interest in this new PC pad has been high, and Valve's supply has run low. I'm staying on the page to see if more stock will appear, fingers crossed for a restock! </p><h2 id="still-out-of-stock">Still out of stock...</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:941px;"><p class="vanilla-image-block" style="padding-top:45.16%;"><img id="zxZJxNDBTdYQyTqwBGuTUH" name="Steam Controller out of stock" alt="Steam Controller out of stock image" src="https://cdn.mos.cms.futurecdn.net/zxZJxNDBTdYQyTqwBGuTUH.jpg" mos="" align="middle" fullscreen="" width="941" height="425" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>Hey, all! Tony Polanco here to take over the Steam Controller liveblog for the next few hours. Not only will I keep you updated on availability, but I'll also share some insights into the controller, since I wrote our <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review">Steam Controller review</a>.</p><p>Right now, the Steam Controller appears to be sold out, as you can see from the image above that I snapped. This is disappointing considering how long people have waited for this peripheral. It's also not surprising given the demand for it. Hopefully, Valve can get more stock as soon as possible.</p><h2 id="the-steam-controller-is-already-on-ebay">The Steam Controller is already on eBay</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:1905px;"><p class="vanilla-image-block" style="padding-top:46.51%;"><img id="Em3gfDEmuQa7ohCvDYDAD9" name="Steam Controller on eBay" alt="Steam Controller on eBay" src="https://cdn.mos.cms.futurecdn.net/Em3gfDEmuQa7ohCvDYDAD9.jpg" mos="" align="middle" fullscreen="" width="1905" height="886" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: eBay)</span></figcaption></figure><p>It shouldn't come as a surprise that people are already scalping the Steam Controller on eBay. As you can see above, users are selling the peripheral for $150+ above the original MSRP. There might be more exorbitant prices on eBay, but these are the ones I was able to find. Please wait for a restock and avoid paying these users your hard-earned cash.</p><h2 id="steam-controller-sold-out-in-just-30-minutes">Steam Controller sold out in just 30 minutes</h2><div class="see-more see-more--clipped"><blockquote class="twitter-tweet hawk-ignore" data-lang="en"><p lang="en" dir="ltr">The Steam Controller sold out just 30 minutes after launch pic.twitter.com/HBhMB1ew8m<a href="https://twitter.com/cantworkitout/status/2051357272563925245">May 4, 2026</a></p></blockquote><div class="see-more__filter"></div></div><p>Word is spreading that the Steam Controller is now sold out. I just hope most of those orders came from folks who are actually going to use the controller and not just scalpers looking to take advantage of people's excitement for the peripheral.</p><h2 id="yes-it-s-still-out-of-stock">Yes, it's still out of stock</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:941px;"><p class="vanilla-image-block" style="padding-top:45.16%;"><img id="zxZJxNDBTdYQyTqwBGuTUH" name="Steam Controller out of stock" alt="Steam Controller out of stock image" src="https://cdn.mos.cms.futurecdn.net/zxZJxNDBTdYQyTqwBGuTUH.jpg" mos="" align="middle" fullscreen="" width="941" height="425" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>I realize these posts are getting repetitive, but as you might have guessed, the Steam Controller is still out of stock. It's hard to say whether Valve can restock today or if we'll have to wait a while for a refresh. Regardless, I'll keep an eye on the situation. Hopefully, it'll change for the better soon!</p><h2 id="one-of-the-coolest-features">One of the coolest features</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="2on6Q6pXBJRLv9qybxnqm9" name="Steam Controller-8" alt="Steam Controller puck" src="https://cdn.mos.cms.futurecdn.net/2on6Q6pXBJRLv9qybxnqm9.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>Yes, the Steam Controller is still out of stock, but that doesn't mean we can't talk about some of its amazing features.</p><p>As I said in my review, one of the coolest features is the included Steam Controller Puck. It's a 2.4GHz USB-C transmitter that can also charge the controller and pair it with the device you’re playing on. It attaches magnetically to the controller with a satisfying click and can be paired with up to four other Steam Controllers.</p><p>You connect the puck to your PC using the included USB-C to USB-A cable, though you can theoretically use any cable with power delivery. I like that you can keep the controller connected, easily snap it off to play wirelessly, and snap it back on when you’re done.</p><p>The controller is rated for 35+ hours, and in all my time with it (nearly a week), it still hasn’t drained its battery. That's something the PS5's DualSense controller can't match, that's for sure.</p><h2 id="a-comfortable-controller">A comfortable controller</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="HJ6ZRxVDUjBBGPfdRCPNrm" name="Steam Controller-12" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/HJ6ZRxVDUjBBGPfdRCPNrm.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>One of the main concerns folks had (including mine) about the Steam Controller was that it would be too big and heavy. Let me tell you, that couldn't be further from the truth!</p><p>Despite its appearance, the Steam Controller is only slightly longer and wider than a traditional Xbox controller. It's also lighter! I've used Valve's peripheral for almost a week, and it's become my favorite PC controller because it's so comfortable and intuitive. Don't let the pictures fool you. The Steam Controller feels great to hold.</p><h2 id="some-useful-reader-comments">Some useful reader comments</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="NcVbKsrfkY4rawQRAzDuYV" name="Steam Controller-11" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/NcVbKsrfkY4rawQRAzDuYV.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>This is my last post for the day (don't worry, we're going to keep this live blog going), but I wanted to highlight two comments you might find useful.</p><p><strong>TheVaudevillian</strong> has been keeping an eye on things since sales went live. They kept getting a "failed to initialize" error when trying to check out, and it took about 5 minutes of repeated clicks to finally complete the order. This is something our own Darraugh Murphy did to get his Steam Controller.</p><p><strong>Jarred Hines</strong> also points out that stock has been sporadically coming back, saying it usually lasts less than a minute before going out of stock again. This is why we advise staying vigilant.</p><h2 id="what-valve-hardware-is-available">What Valve hardware is available?</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:1198px;"><p class="vanilla-image-block" style="padding-top:58.68%;"><img id="KWQjfzsxuJLpjgtiUgthYT" name="Screenshot 2026-05-04 141502" alt="Valve Steam Deck out of stock on 5-4-26" src="https://cdn.mos.cms.futurecdn.net/KWQjfzsxuJLpjgtiUgthYT.png" mos="" align="middle" fullscreen="" width="1198" height="703" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>Hey, this is Scott taking over for Tony, and for my first of the day, I thought we could take a look at what is available. Turns out nothing.</p><p>Yes, the Steam Controller is still sold out, but if you wanted to get into the Valve ecosystem, let's see what else is available.</p><p>Obviously, the Steam Machine and Steam Frame have not yet been released.</p><p>Which just leaves the Steam Deck...which is out of stock. Currently, every variant from the 1TB OLED to the 256GB LCD is listed as unavailable. </p><h2 id="while-we-wait">While we wait</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="djtjcDyxp27vCNuxWeTJ8B" name="Steam Machine edit 2" alt="Steam Machine" src="https://cdn.mos.cms.futurecdn.net/djtjcDyxp27vCNuxWeTJ8B.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: Valve)</span></figcaption></figure><p>With the Steam Controller immediately out of stock, I have a speculative leak that may be of interest. </p><p>Regular VR and Valve <a href="https://x.com/SadlyItsBradley/status/2051038702546174044" target="_blank">tipster Brad Lynch</a> has posted a couple of times regarding recent shipments Valve has received to its distribution warehouse. </p><p>The shipments are listed "Game Console." It's possible that these could be Steam Deck shipments or as Lynch hints at, the arrival of Steam Machines. </p><p>We can see that "Wireless PC Controllers" arrived on April 4, and started releasing now. So, I expect if its the Machine, we might see it drop in early June. If its Steam Decks, maybe those will be available sooner.</p><h2 id="calling-it-for-today">Calling it for today</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="VA2D2h27873kpRELmPwZHS" name="Steam Controller-1-LIST" alt="The Steam Controller on a desk." src="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS.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 Steam Controller is still out of stock as of 4:30 pm Pacific. </p><p>But don't worry, we're keeping track and we'll be back to tomorrow to let you know when the controller is available again.</p><p>Keep us in your tabs.</p><h2 id="have-you-managed-to-order-a-steam-controller-yet">Have you managed to order a Steam Controller yet?</h2><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OzLJle"></div>                            </div>                            <script src="https://kwizly.com/embed/OzLJle.js" async></script><h2 id="tuesday-morning-stock-check">Tuesday morning stock 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:1506px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="pCdaysxcM5mpT5CdE2DmhV" name="Steam Controller" alt="A still image showing the Steam Controller" src="https://cdn.mos.cms.futurecdn.net/pCdaysxcM5mpT5CdE2DmhV.jpg" mos="" align="middle" fullscreen="" width="1506" height="847" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>It's just ticked over 6:30 a.m. ET, and at present, I'm not seeing any sign of additional Steam Controller stock today. For now, that dreaded "Out of stock" message is sticking around. Some TG readers have reported seeing stock, but it reportedly only lasts for a few moments, so if you do happen to get lucky and get the chance to order, I advise checking out at speed. In the meantime, I'm still monitoring the page, and will update this live blog if the situation changes.</p><h2 id="unfortunately-nothing-new-to-report">Unfortunately, nothing new to report!</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="HJ6ZRxVDUjBBGPfdRCPNrm" name="Steam Controller-12" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/HJ6ZRxVDUjBBGPfdRCPNrm.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><ul><li><strong>Steam Controller: </strong><a href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><strong>$99 @ Steam</strong></a> <strong>(check stock)</strong></li></ul><p>10:15 a.m. ET, and still no signs of a restock today. After selling out within 30 minutes of launch, there hasn't been a major restock of the Steam Controller, but I'm keeping my fingers crossed for Valve to find some additional supply soon. Till then we'll keep checking!</p><h2 id="official-word-from-valve">Official word from Valve</h2><div class="see-more see-more--clipped"><blockquote class="twitter-tweet hawk-ignore" data-lang="en"><p lang="en" dir="ltr">Steam Controller ran out faster than we anticipated, and we hate that not everyone who wanted one was able to get it. We’re working on getting more in stock and will have an update on expected timeline soon.<a href="https://twitter.com/cantworkitout/status/2051695149026353424">May 5, 2026</a></p></blockquote><div class="see-more__filter"></div></div><p>Things have been quiet regarding restocks, but Valve took to X to make an official statement. Here is what the company had to say:<br><br>"Steam Controller ran out faster than we anticipated, and we hate that not everyone who wanted one was able to get it. We’re working on getting more in stock and will have an update on expected timeline soon."</p><p>Hopefully, that "soon" won't take too long!</p><h2 id="valve-recently-imported-50-tons-of-game-consoles">Valve recently imported 50 tons of "game consoles"</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:3840px;"><p class="vanilla-image-block" style="padding-top:60.68%;"><img id="sJthZiHkM5CLN6Ur7BGtmE" name="SM_front_b" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/sJthZiHkM5CLN6Ur7BGtmE.jpg" mos="" align="middle" fullscreen="" width="3840" height="2330" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>The Steam Controller is still out of stock, so we figured we'd update you on something potentially related, namely, the Steam Machine.</p><p>As <a href="https://www.theverge.com/news/923461/valve-steam-machine-frame-deck-import-records-may-2026" target="_blank">The Verge</a> reports, Valve has supposedly shipped over 45 tons of "game consoles" into the United States. This follows the company shipping about 90 tons of orders since February (via <a href="https://www.pcmag.com/news/steam-machine-incoming-valve-imports-thousands-of-game-consoles-into-the" target="_blank">PCMag</a>). While we don't know what these consoles are, they could very well be the Steam Machine.</p><p>Valve hasn't disclosed the official price of its console/PC hybrid, but if the consoles the company is reportedly shipping are indeed the Steam Machine, perhaps we'll get an answer soon. Since this isn't official confirmation from Valve, take this report with a grain of salt. For all we know, this could be a new shipment of Steam Decks... a handheld which has also been sold out for some time.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I ditched my dual-monitor setup for a single 40-inch ultrawide — and two screens aren’t better than one ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/i-ditched-my-dual-monitor-setup-for-a-single-40-inch-ultrawide-and-two-screens-arent-better-than-one</link>
                                                                            <description>
                            <![CDATA[ After trying the Innocn 401CU ultrawide monitor, dealing with the bezels and cables of a dual-monitor setup just doesn’t seem worth the hassle. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">cwd92T58zgZuWivmcyJPbG</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/2wspfuqjczyMPLAgXHmYwk-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 03 May 2026 10:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ anthony.spadafora@futurenet.com (Anthony Spadafora) ]]></author>                    <dc:creator><![CDATA[ Anthony Spadafora ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/z73LEoj7FkUjNG85GcWHtH.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Anthony Spadafora is the managing editor for security and home office furniture at Tom’s Guide where he covers everything from data breaches and malware to password managers and the best way to cover your whole home or business with a strong Wi-Fi signal.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Before joining the team, he spent three years covering cybersecurity and B2B tech for ITProPortal while living in South Korea. After moving back to the US. Anthony joined the TechRadar Pro team where he covered these topics along with VPNs, web hosting, online collaboration software and video conferencing for four years. Anthony also has his ears to the ground and is on the lookout for the next major cyberattack or data breach.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Based in Houston, Texas, Anthony also handles VPN testing for both Tom’s Guide and TechRadar. As someone who has worked from home exclusively since 2018, he has reviewed dozens of standing desks as well as office chairs and has taken a closer look at other essential remote working accessories. As part of these reviews, Anthony frequently builds intricate desk setups which is why he’s such a big advocate for cable management and keeping things organized. When he’s not writing, he can be found tinkering with PCs and game consoles, managing cables and making upgrades to his smart home.&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/2wspfuqjczyMPLAgXHmYwk-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A person working on the Innocn 40C1U ultrawide monitor at their desk]]></media:description>                                                            <media:text><![CDATA[A person working on the Innocn 40C1U ultrawide monitor at their desk]]></media:text>
                                <media:title type="plain"><![CDATA[A person working on the Innocn 40C1U ultrawide monitor at their desk]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/2wspfuqjczyMPLAgXHmYwk-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>There’s no ideal <a href="https://www.tomsguide.com/computing/i-built-a-black-and-white-gaming-desk-setup-that-feels-clean-calm-and-completely-me-and-it-has-a-secret-weapon-that-makes-it-all-work">desk setup</a> that works for everyone. While one person might be content with a laptop or a single monitor, another might want multiple monitors. Likewise, your old desk setup might have been perfect at the time but now, it no longer meets your needs.</p><p>As someone who builds desk setups for a living, I’m constantly trying out new configurations when it comes to how many displays I have and what’s driving them. Although I spent years using a single ultrawide monitor by itself, I later added a <a href="https://www.tomsguide.com/computing/hardware/i-upgraded-my-desk-setup-with-a-touchscreen-display-and-its-made-multitasking-so-much-easier">portable monitor underneath it</a> specifically to keep up with work chats. Of course, I wasn’t done there.</p><p>From <a href="https://www.tomsguide.com/computing/monitors/i-spent-a-week-trying-3-different-stacked-monitor-setups-and-this-is-my-favorite">stacked monitors</a> to <a href="https://www.tomsguide.com/computing/i-ditched-my-ultrawide-display-for-this-dual-monitor-setup-heres-what-happened">dual monitors</a> and even <a href="https://www.tomsguide.com/computing/i-thought-putting-together-a-triple-monitor-setup-would-be-hard-but-i-did-it-with-three-budget-monitors-and-a-mini-pc">triple monitors</a>, it feels like my desk is constantly evolving and rightfully so. However, at the beginning of this year, I put together a <a href="https://www.tomsguide.com/computing/i-added-this-usd30-accessory-to-my-desk-setup-and-it-finally-let-me-use-a-dual-monitor-setup-comfortably-for-video-calls">dual-monitor setup</a> that I just couldn’t bear to break down. That all changed though, when I finally had a chance to try out a larger, 40-inch ultrawide.</p><p>Even though the Innocn 40C1U’s screen is only six inches wider than the 34-inch ultrawide I’ve used for years now, it’s made a massive difference. So much so that I don’t think I could go back to using a dual-monitor setup anytime soon. If you’ve also been considering upgrading your own desk setup, here’s why you might want to go wider instead of adding another display.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Wl4rDW"></div>                            </div>                            <script src="https://kwizly.com/embed/Wl4rDW.js" async></script><h2 id="no-curves-here">No curves here</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="DbQugiSNwy3mK2cqsPHnw" name="Innocn 401CU--6" alt="The Innocn 40C1U set up on a desk but not plugged in" src="https://cdn.mos.cms.futurecdn.net/DbQugiSNwy3mK2cqsPHnw.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 40 inches, the Innocn 40C1U is certainly an outlier. With most monitors, once you go beyond 34 inches wide, you no longer have the choice between a flat or a curved display. Since I have multiple monitors for my various desk setups stored in a closet, I don’t really have the option to use curved ones as they take up far too much space when not in use. </p><p>After eying the Innocn 40C1R online for what seemed like ages, the company reached out and asked if I’d be interested in trying out the more powerful 40C1U instead. Since I just reviewed the <a href="https://www.tomsguide.com/computing/monitors/apple-studio-display-xdr-review">Apple Studio Display XDR</a>, I decided to give this 5K2K monitor a try and I’m glad I did.</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="bVE4j4uKbjSjuUoYnvqEm6" name="Innocn 401CU--8" alt="The monitor stand and cables that come in the box with the Innocn 40C1U" src="https://cdn.mos.cms.futurecdn.net/bVE4j4uKbjSjuUoYnvqEm6.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>In the box, you get a surprisingly capable stand along with a high-speed HDMI cable, a USB-C video cable and a power cable. The fact that Innocn includes a USB-C cable in the box is a nice touch. However, like with the <a href="https://www.tomsguide.com/reviews/lg-dualup-monitor">LG DualUp</a> monitor I reviewed back when I first started at Tom’s Guide, I would have loved to see a USB-B to USB-A cable included as well — but more on that in a bit</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="e4L44FKXNx6LVDSiLSYLY9" name="Innocn 401CU--7" alt="The rear ports on the Innocn 40C1U ultrawide monitor" src="https://cdn.mos.cms.futurecdn.net/e4L44FKXNx6LVDSiLSYLY9.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>While the 40C1U is definitely on the less expensive side for a 5K2K monitor, I really like how it has a built-in power supply instead of a bulky power adapter with a barrel port connector. Likewise, it has standard 100 x 100 VESA mounting holes instead of the 75 x 75 ones you see on many of the <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html">best gaming monitors</a>. If you’ve ever tried to lift a display like that up off your desk using one of the <a href="https://www.tomsguide.com/best-picks/best-monitor-arms">best monitor arms</a>, then you know how much of a hassle it can be.</p><p>In terms of ports, the 40C1U has a generous selection on the right side including two HDMI 2.0 ports, a DisplayPort 1.4 connection, an upstream USB-C port with 65W of power delivery, two USB-A ports, a USB-B port and a headphone jack. As such, you can connect up to four devices at the same time.</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="X8LFC7TkH8XyAYYoCqup6D" name="Innocn 401CU--5" alt="An overhead shot showing a MacBook Pro connected to an Innocn 40C1U ultrawide monitor" src="https://cdn.mos.cms.futurecdn.net/X8LFC7TkH8XyAYYoCqup6D.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>After unboxing the 40C1U and attaching the included monitor stand, it was time to take it for a spin. Given I had a <a href="https://www.tomsguide.com/computing/macbooks/macbook-pro-16-inch-m5-pro-review">MacBook Pro with an M5 Pro chip</a> on hand, I figured that would be perfect for testing out this monitor as I previously used that laptop with the Studio Display XDR. Fortunately, there weren’t any dead pixels or other issues to be worried about and everything worked like a charm right out of the box. </p><p>With my initial testing out of the way, I decided to build a new desk setup based around the Innocn 40C1U to see just what this 40-inch, 5K2K ultrawide was capable of.</p><div class="product"><a data-dimension112="4b4acd90-9503-4365-857d-72b5924b7e79" data-action="Deal Block" data-label="This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens." data-dimension48="This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens." data-dimension25="$594" href="https://www.amazon.com/INNOCN-Inch-2160p-Ultrawide-Monitor/dp/B0D7Q8N64F" 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:61.07%;"><img id="BzCn3DiniFqNV4SefEPo3D" name="40C1U" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/BzCn3DiniFqNV4SefEPo3D.jpg" mos="" align="middle" fullscreen="" width="1500" height="916" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens. <a class="view-deal button" href="https://www.amazon.com/INNOCN-Inch-2160p-Ultrawide-Monitor/dp/B0D7Q8N64F" target="_blank" rel="nofollow" data-dimension112="4b4acd90-9503-4365-857d-72b5924b7e79" data-action="Deal Block" data-label="This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens." data-dimension48="This massive 40-inch flat panel is a rare find in the ultrawide world. It delivers a stunning 5K2K resolution (5120 x 2160), giving you the same pixel density as a 32-inch 4K monitor but with 33% more horizontal space. It features a built-in KVM switch, 65W USB-C power delivery and a flat IPS panel that’s perfect for creators who can't stand the distortion of curved screens." data-dimension25="$594">View Deal</a></p></div><h2 id="mac-or-pc-why-not-both">Mac or PC: why not both?</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="Rs6kjtZeD5HJmQBr8pWpEH" name="Innocn 401CU--4" alt="The Innocn 40C1U ultrawide monitor on a desk with a Mac on one side and a PC on the other" src="https://cdn.mos.cms.futurecdn.net/Rs6kjtZeD5HJmQBr8pWpEH.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>Deciding between a Mac or a PC for work can be difficult which is why many people like myself use both. Normally, I spend my time working on my <a href="https://www.tomsguide.com/computing/desktop-computers/mac-mini-m4-review">Mac mini M4</a> at one desk setup and on one of the <a href="https://www.tomsguide.com/us/best-mini-pc.html">best mini PCs</a> at another. This time though, I wanted the best of both worlds and figured having two computers on the wider <a href="https://www.tomsguide.com/home/home-office/secretlab-magnus-evo-review">Secretlab Magnus Evo</a> desk wouldn’t be a problem, so I did just that.</p><p>On the left side, I set up that MacBook Pro in a vertical stand with the computer set to not go to sleep with its lid closed. Then on the right, I plugged in the <a href="https://www.tomsguide.com/computing/mini-pcs/framework-desktop-review">Framework Desktop</a> which, in addition to being a powerful PC for work, holds up surprisingly well when gaming despite not having a discrete GPU.</p><p>Normally, you’d need two separate keyboards and mice with a setup like this one. However, remember those USB-A ports and that USB-B port around back? Well, like many of the <a href="https://www.tomsguide.com/best-picks/best-monitors">best monitors</a>, the 40C1U features a built-in KVM (keyboard, video, mouse) switch. So instead of having to connect, disconnect and then reconnect my mouse and keyboard over Bluetooth, I plugged their respective 2.4 GHz USB dongles into the back of the 40C1U. This let me use the same mouse and keyboard with multiple computers.</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="ww5qXDWH5G425cZtDw3p2L" name="Innocn 401CU--3" alt="The Innocn 40C1U ultrawide monitor on a desk with a PC on one side and a Mac on the other" src="https://cdn.mos.cms.futurecdn.net/ww5qXDWH5G425cZtDw3p2L.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>Since the USB-C cable plugged into the MacBook Pro handles both video and data, I was able to use my peripherals on Mac with just a single cable. However, because I connected the Framework Desktop via HDMI, I had to connect a USB-B to USB-A cable at the back of the monitor and then plug it into my PC.  If you get a monitor with a built-in KVM switch that doesn’t come with this cable, don’t worry. Just like I did, you can likely borrow the one from your printer until you pick up a new one.</p><p>What I like about using the Innocn 40C1U with both of these computers is that I don’t have to press any buttons or mess around in the display’s settings menu to use my mouse and keyboard. Instead, I just switch inputs and the monitor does the rest, automatically assigning my peripherals to whichever computer is currently on screen. Having the option to use macOS or Windows 11 while working has been great and I’m kind of surprised I didn’t try something like this earlier.</p><p>With my dual-OS desk setup for work finished, it was time to try pushing the 40C1U — and the Framework Desktop too for that matter — to its limit.</p><h2 id="work-hard-play-wide">Work hard, play wide</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="8SWC4HpmiULrqwHuw36d3Q" name="Innocn 401CU--2" alt="A person playing Death Stranding 2 on the Innocn 401CU ultrawide monitor" src="https://cdn.mos.cms.futurecdn.net/8SWC4HpmiULrqwHuw36d3Q.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>Now I know what you might be thinking: gaming on a 5K2K monitor requires a beefy gaming PC. I thought the same thing when I first booted up Steam on the Framework Desktop. Using a massive panel like the 40C1U for gaming seems impractical since you need to render a whole lot more pixels than you would on a 1080p or 1440p display.</p><p>I know Nvidia’s DLSS and AMD’s FSR upscaling tech sometimes get a bad rap due to "fake frames," but in this instance, FSR was a lifesaver. When I first loaded up Death Stranding 2, everything looked a bit blurry at this high resolution. After updating AMD’s software and enabling FSR, however, the game was surprisingly playable.</p><p>I did have to drop the game’s internal resolution down to 2560 x 1080 and let FSR upscale it back to 5K2K. Much like when I <a href="https://www.tomsguide.com/computing/mini-pcs/forget-consoles-i-spent-a-week-with-this-mini-pc-in-my-living-room-and-i-cant-believe-how-well-it-performs">brought the Framework Desktop to my living room</a> to play on my 4K TV, the Ryzen AI Max+ 395 chip and built-in Radeon 8060S graphics in this mini PC really surprised me.</p><p>Playing <a href="https://www.tomsguide.com/gaming/death-stranding-2-is-the-most-beautiful-game-ive-ever-played-and-its-everything-id-hope-for-in-a-sequel">Death Stranding 2</a> on a 40-inch ultrawide adds so much immersion. With FSR enabled, my frame rate stayed at around 70 fps — even with the graphics set to high. I also didn’t have to worry about hooking up bookshelf speakers as the 40C1U has built-in audio. While you’ll still want one of the <a href="https://www.tomsguide.com/best-picks/best-gaming-headsets">best gaming headsets</a> for a truly premium experience, the monitor’s built-in speakers were more than capable.</p><p>It’s worth noting that with its 100Hz refresh rate, the 40C1U is a productivity monitor first and foremost. If you have a powerful GPU or don't mind enabling frame generation, you can certainly game on it, but running games natively at 5K2K will be a tall order for most rigs.</p><p>If you’re after a larger ultrawide primarily for gaming, the Innocn 40C1R is the better (and cheaper) choice. It has a more manageable 1440p resolution and a faster 144Hz refresh rate. Still, while it's better for high-speed gaming, you lose out on the incredible clarity and text crispness you get with the 40C1U’s 5K2K resolution.</p><div class="product"><a data-dimension112="3358e249-5ebd-4cf5-8c6f-f754852f8b3a" data-action="Deal Block" data-label="If you want the scale of a 40-inch monitor but prioritize gaming speed over raw pixel count, the 40C1R is the better value. It swaps the 5K2K resolution for a more GPU-friendly 3440 x 1440 but bumps the refresh rate up to a smooth 144Hz. It actually beats its more expensive sibling in one area: it offers a beefier 90W of power delivery over USB-C, making it a better hub for power-hungry gaming laptops." data-dimension48="If you want the scale of a 40-inch monitor but prioritize gaming speed over raw pixel count, the 40C1R is the better value. It swaps the 5K2K resolution for a more GPU-friendly 3440 x 1440 but bumps the refresh rate up to a smooth 144Hz. It actually beats its more expensive sibling in one area: it offers a beefier 90W of power delivery over USB-C, making it a better hub for power-hungry gaming laptops." data-dimension25="$359" href="https://www.amazon.com/INNOCN-Ultrawide-Monitor-FreeSync-Premium/dp/B09N3G9T16" 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:62.07%;"><img id="SD5VTihpfBoetQyx8jZckP" name="40C1R" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SD5VTihpfBoetQyx8jZckP.jpg" mos="" align="middle" fullscreen="" width="1500" height="931" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>If you want the scale of a 40-inch monitor but prioritize gaming speed over raw pixel count, the 40C1R is the better value. It swaps the 5K2K resolution for a more GPU-friendly 3440 x 1440 but bumps the refresh rate up to a smooth 144Hz. It actually beats its more expensive sibling in one area: it offers a beefier 90W of power delivery over USB-C, making it a better hub for power-hungry gaming laptops. <a class="view-deal button" href="https://www.amazon.com/INNOCN-Ultrawide-Monitor-FreeSync-Premium/dp/B09N3G9T16" target="_blank" rel="nofollow" data-dimension112="3358e249-5ebd-4cf5-8c6f-f754852f8b3a" data-action="Deal Block" data-label="If you want the scale of a 40-inch monitor but prioritize gaming speed over raw pixel count, the 40C1R is the better value. It swaps the 5K2K resolution for a more GPU-friendly 3440 x 1440 but bumps the refresh rate up to a smooth 144Hz. It actually beats its more expensive sibling in one area: it offers a beefier 90W of power delivery over USB-C, making it a better hub for power-hungry gaming laptops." data-dimension48="If you want the scale of a 40-inch monitor but prioritize gaming speed over raw pixel count, the 40C1R is the better value. It swaps the 5K2K resolution for a more GPU-friendly 3440 x 1440 but bumps the refresh rate up to a smooth 144Hz. It actually beats its more expensive sibling in one area: it offers a beefier 90W of power delivery over USB-C, making it a better hub for power-hungry gaming laptops." data-dimension25="$359">View Deal</a></p></div><h2 id="the-cost-of-simplicity">The cost of simplicity</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="cAY2YE9eJtnsTdCtAHpnKe" name="SmallRig Camera Desk Mount-4" alt="A dual-monitor desk setup on the Secretlab Magnus Evo with the SmallRig Camera Desk Mount holding up a webcam behind the displays" src="https://cdn.mos.cms.futurecdn.net/cAY2YE9eJtnsTdCtAHpnKe.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>Deciding between a dual-monitor setup and a single ultrawide is a tough choice. You can pick up a pair of identical monitors — or even use mismatched ones like I did here — for a whole lot less than a massive ultrawide display. However, doing so requires a bit more work, both during the initial setup and in your daily workflow.</p><p>With two screens, you have twice the cables to manage. You also might need to swap out your power strip for one with more outlets and be much more deliberate with your cable management. Using a dual-monitor arm can help, but as I’ve found, this often requires longer cables to route through the arms and down to your computer.</p><p>When using a single ultrawide like the Innocn 40C1U, you cut your cable count in half. But since the display is so large, you might need to invest in a heavy-duty monitor arm. If you use a standard one, your monitor will likely droop instead of staying firmly in place.</p><p>After years of testing both configurations, I’d recommend setting aside some extra cash for a single, wider display. You don't have to worry about lining up bezels or managing a nest of wires. At the same time, both Windows and macOS also tend to play better with a single monitor than they do with multiple screens.</p><p>The Innocn 40C1U was the upgrade I needed to finally break down my previous setup and go back to an ultrawide. I’m not saying I won’t build another dual-monitor setup in the future — or finally tackle a quad-monitor one — but for now, I’m more than content using multiple computers on a single, massive display.</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/computing/i-built-the-ultimate-distraction-free-desk-setup-and-now-im-truly-locked-in">I built a completely distraction-free desk setup with these 10 gadgets and now I’m truly locked in</a></li><li><a href="https://www.tomsguide.com/computing/peripherals/monitor-stand-vs-monitor-arm-how-to-pick-the-right-one-for-your-display">Monitor stand vs monitor arm: how to pick the right one for your display</a></li><li><a href="https://www.tomsguide.com/computing/monitors/i-spent-a-week-with-dual-apple-studio-displays-and-realized-ive-been-lying-to-myself-about-glossy-screens-for-years">I spent a week with dual Apple Studio Displays and realized I’ve been lying to myself about glossy screens for years</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just spent 48 hours with the Steam Controller — here's my honest verdict ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/peripherals/i-just-spent-48-hours-with-the-steam-controller-heres-my-honest-verdict</link>
                                                                            <description>
                            <![CDATA[ I tested the Steam Controller for 48 hours to see if it lives up to the hype. Here's what I think of Valve's latest peripheral. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">aQ5o8nDeK6y2tuGQHDNu3G</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/HJ6ZRxVDUjBBGPfdRCPNrm-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 02 May 2026 07:19:41 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Computing Peripherals]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/HJ6ZRxVDUjBBGPfdRCPNrm-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Steam Controller]]></media:description>                                                            <media:text><![CDATA[Steam Controller]]></media:text>
                                <media:title type="plain"><![CDATA[Steam Controller]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/HJ6ZRxVDUjBBGPfdRCPNrm-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The <a href="https://www.tomsguide.com/gaming/gaming-peripherals/im-a-lifelong-gamer-and-i-cant-wait-to-try-the-steam-controller-3-reasons-why">Steam Controller</a> is the real deal. This is my conclusion after having used Valve’s new controller for over 48 hours. Not only is it the perfect controller for Steam users, but it’s also a smart redesign of the controversial original from 11 years ago. It’s a brilliant peripheral that only makes me yearn for the Steam Machine even more.</p><p>On top of a more traditional controller layout than its predecessor, the Steam Controller has unique features, such as large haptic touchpads, four back buttons, TMR thumbsticks, and a slew of software-specific customization options. The latter is particularly noteworthy, as you can fine-tune the controller for virtually any game genre. It also just feels good to hold thanks to its ergonomic, lightweight design.</p><p>I’ll have a full review of the Steam Controller for you soon. For now, here are my impressions after 48 hours with the peripheral.</p><div class="product"><a data-dimension112="c07e72b5-5e54-4e69-b1e6-3301cf179d25" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension25="$99" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1232px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="p4kRCykqzQRFswEntyNcUE" name="Steam Controller" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/p4kRCykqzQRFswEntyNcUE.jpg" mos="" align="middle" fullscreen="" width="1232" height="1232" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4.<br><a class="view-deal button" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow" data-dimension112="c07e72b5-5e54-4e69-b1e6-3301cf179d25" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension25="$99">View Deal</a></p></div><h2 id="first-impressions">First impressions</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="VA2D2h27873kpRELmPwZHS" name="Steam Controller-1-LIST" alt="The Steam Controller on a desk." src="https://cdn.mos.cms.futurecdn.net/VA2D2h27873kpRELmPwZHS.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 official press shots and even reviewers’ photos made the controller appear as big as an old Dreamcast controller, but in reality, it’s just slightly wider and longer than a modern Xbox controller. I do have large hands, so folks with smaller hands might feel differently, but this controller fits my grip nicely.</p><p>The controller has the same matte-like finish as the Steam Deck. Thanks to that, it's easy to maintain your grip, even if your hands get sweaty. The ABXY face buttons and shoulder buttons feel like a more rigid, durable version of their Steam Deck equivalents. In fact, you could almost consider this controller a Steam Deck without a screen since it feels so similar.</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="2on6Q6pXBJRLv9qybxnqm9" name="Steam Controller-8" alt="Steam Controller puck" src="https://cdn.mos.cms.futurecdn.net/2on6Q6pXBJRLv9qybxnqm9.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>Setting up the Steam Controller is extremely simple. All you have to do is connect the included receiver puck to your PC via the USB cable, then magnetically snap it to the controller to begin pairing. Snapping the puck on and pulling it off is immensely fun and reminds me of doing the same with MagSafe on MacBooks.</p><h2 id="the-gaming-experience">The gaming experience</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="NcVbKsrfkY4rawQRAzDuYV" name="Steam Controller-11" alt="Steam Controller" src="https://cdn.mos.cms.futurecdn.net/NcVbKsrfkY4rawQRAzDuYV.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>You know a controller is great when it becomes a natural extension of your hands. That has largely been my experience with the Steam Controller, since it’s so intuitive to use. The TMR thumbsticks respond to even the smallest movements, while the buttons have a nice level of resistance when pressed. And as I said before, it feels awesome simply holding it.</p><p>When exploring the open-world setting of <a href="https://www.tomsguide.com/reviews/cyberpunk-2077-phantom-liberty">Cyberpunk 2077</a>, I had no issues moving around and taking in the dystopian game’s sights. Whether I was walking down a neon-lit street or blasting cyborgs away with an assault rifle, everything felt just right. The triggers are excellent for shooting games and racers alike.</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="wXqarwHGksv9v9Rda4jNQG" name="Steam Controller-13" alt="Steam Controller customization" src="https://cdn.mos.cms.futurecdn.net/wXqarwHGksv9v9Rda4jNQG.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>There are a ton of customization options within SteamOS’ Steam Input settings menu. Not only can you remap all the buttons, but you can even program the touchpads to act like a mouse or even a D-Pad. I haven’t toyed around with all the settings, but trust me, you could spend hours messing around with them. This high level of customization lets you tailor controls for specific games and genres.</p><p>I don’t play genres like RTS or MMOs that would make greater use of touchpads, but I do enjoy their haptic feedback when I scroll through menus. This isn’t a game-changing feature, but little touches like this make the experience more enjoyable and immersive.</p><p>Except for fighting games, where I prefer using a <a href="https://www.tomsguide.com/gaming/gaming-peripherals/i-swapped-my-controller-for-an-arcade-stick-and-fighting-games-will-never-be-the-same">dedicated fight stick</a>, I don’t see myself using another controller for PC gaming since it works so well for the main genres I play.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-evvmme"></div>                            </div>                            <script src="https://kwizly.com/embed/evvmme.js" async></script><h2 id="outlook-5">Outlook</h2><p>My full review will be posted soon, but suffice it to say that the Steam Controller more than lives up to the hype. It’s a brilliantly designed peripheral that feels like a natural extension of the Steam ecosystem. While it’s not compatible with other PC game launchers, Steam users will be more than happy with this product.</p><p>The Steam Controller is already great on its own, but it’s a nice appetizer for the full Steam Machine experience. If that platform can deliver the same smooth and intuitive experience, we’re in for something special. But for now, we can enjoy the Steam Controller for what it delivers—and what it delivers is pretty darn phenomenal.</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/gaming/gaming-peripherals/steam-controller-review-roundup">Steam Controller reviews are in: 'I can’t imagine playing my PC games with anything else'</a></li><li><a href="https://www.tomsguide.com/computing/monitors/lg-ultragear-27gx790b-b-review">I just tested the world’s fastest OLED gaming monitor — and its refresh rates are insane</a></li><li><a href="https://www.tomsguide.com/computing/gaming-laptops/nvidia-rtx-5070-laptop-gpu-officially-has-12gb-of-vram-and-its-about-time">Nvidia RTX 5070 laptop GPU gets 12GB VRAM — here’s why it's a game-changer</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested the world’s fastest OLED gaming monitor — and its refresh rates are insane ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/lg-ultragear-27gx790b-b-review</link>
                                                                            <description>
                            <![CDATA[ The LG UltraGear 27GX79B-B impresses with its high refresh rates. While it’s fast and offers high HDR brightness, it’s only for competitive gamers. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">jhgpPrv9rBZzFf4ZVurH94</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/bTFR52GxrQktq9aeYFmZX8-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 30 Apr 2026 06:15:00 +0000</pubDate>                                                                                                                                <updated>Wed, 10 Jun 2026 14:33:26 +0000</updated>
                                                                                                                                            <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/bTFR52GxrQktq9aeYFmZX8-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[LG UltraGear 27GX790B-B gaming monitor on a desk.]]></media:description>                                                            <media:text><![CDATA[LG UltraGear 27GX790B-B gaming monitor on a desk.]]></media:text>
                                <media:title type="plain"><![CDATA[LG UltraGear 27GX790B-B gaming monitor on a desk.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/bTFR52GxrQktq9aeYFmZX8-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The LG UltraGear 27GX790B-B ($999) is one of the wildest devices I’ve tested. Like most of LG’s current gaming monitors, it lets you switch between two refresh rates. The difference is how high those numbers go: 540Hz at 1440p resolution and 720Hz at 720p resolution. No, those numbers aren’t typos! As things stand, this is certainly one of the fastest gaming monitors you can buy, but that’s not all the UltraGear 27GX790B-B has going for it.</p><p>The main complaint I have with every OLED gaming monitor I’ve reviewed is the dim HDR compared to other monitors. LG’s latest bucks that trend by delivering some of the brightest brights I’ve seen on similar devices. In fact, the company claims this is the world’s brightest OLED gaming monitor. I can’t verify if that’s true, but I’m inclined to believe it, especially after our testing.</p><p>As with all LG UltraGear monitors, this 27-inch model features an elegant design that’s well-suited for any office or gaming setup. Since this is a gaming monitor, you can enable RGB backlighting for fun. You also get a great range of motion to help you achieve the best viewing angle.</p><p>The insanely high refresh rates are certainly impressive and ensure that everything runs buttery smooth. However, unless you’re a professional gamer, you likely won’t be able to tell the difference between what you get here and what you’d get from a similar 240Hz monitor. In fact, I even question whether professionals can tell the difference.</p><p>Other than refresh rates that feel like tech flexing and the monitor topping out at 1440p, I have little to complain about. Faults aside, it’s certainly one of the <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html">best gaming monitors</a>, especially if you want such high refresh rates. Find out more in my full review.</p><h3 class="article-body__section" id="section-lg-ultragear-27gx790b-b-review-cheat-sheet"><span>LG UltraGear 27GX790B-B review: Cheat sheet</span></h3><ul><li><strong>What is it?</strong> The LG UltraGear 27GX790B-B is a 27-inch OLED gaming monitor featuring two refresh rates: 540Hz at 1440p and 720Hz at 720p.</li><li><strong>Who is it for?</strong> For competitive gamers who need the absolute highest refresh rates.</li><li><strong>What does it cost?</strong> The LG UltraGear 27GX790B-B <a href="https://www.amazon.com/27GX790B-B-Ultragear-TrueBlack-Compatible-DisplayPort/dp/B0G5R2QK24" target="_blank" rel="nofollow">costs $994 on Amazon</a>.</li><li><strong>What do we like?</strong> We like the elegant design, high HDR brightness for an OLED gaming monitor, and relatively affordable price.</li><li><strong>What don’t we like?</strong> The super high refresh rates aren’t essential for most gamers, and the display tops out at 1440p resolution.</li></ul><h3 class="article-body__section" id="section-lg-ultragear-27gx790b-b-review-specs"><span>LG UltraGear 27GX790B-B review: Specs</span></h3><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>LG UltraGear 27GX790B-B</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p>$994</p></td></tr><tr><td class="firstcol " ><p><strong>Display</strong></p></td><td  ><p>27-inch</p></td></tr><tr><td class="firstcol " ><p><strong>Resolution</strong></p></td><td  ><p>2560 x 1440 | 1280 x 720</p></td></tr><tr><td class="firstcol " ><p><strong>Aspect ratio</strong></p></td><td  ><p>16:9 </p></td></tr><tr><td class="firstcol " ><p><strong>Refresh rate</strong></p></td><td  ><p>540Hz | 720Hz</p></td></tr><tr><td class="firstcol " ><p><strong>Response time</strong></p></td><td  ><p>0.02ms</p></td></tr><tr><td class="firstcol " ><p><strong>Panel type</strong></p></td><td  ><p>OLED</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>2x HDMI, 1x DisplayPort, 1x USB-C, 2x USB-A</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>23.8" × 20.8" × 8.7 (raised, with stand)</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>15 pounds</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-lg-ultragear-27gx790b-b-review-the-ups"><span>LG UltraGear 27GX790B-B review: The ups</span></h3><p>The UltraGear 27GX790B-B impresses thanks to its insanely high refresh rates, bright HDR brightness, and overall sleek design.</p><h2 id="lovely-design-2">Lovely design</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="cm63oisD4pBJhSNXKWzVcc" name="LG-UltraGear-27GX790B-B--11" alt="LG UltraGear 27GX790B-B" src="https://cdn.mos.cms.futurecdn.net/cm63oisD4pBJhSNXKWzVcc.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 27GX790B-B has the classic LG UltraGear design, which is to say that it’s sleek and elegant. I like how the all-silver understated aesthetic can work just as well in an office environment as it would in a proper gaming den. Even the RGB lighting surrounding the monitor arm on the back is relatively subdued, should you choose to turn it on.</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="9J7E5mu8XJvfHXypPxbv4S" name="LG-UltraGear-27GX790B-B--9" alt="LG UltraGear 27GX790B-B" src="https://cdn.mos.cms.futurecdn.net/9J7E5mu8XJvfHXypPxbv4S.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>Gliding the monitor up and down along the stand is a smooth process, as is tilting it forward and back for that perfect viewing angle. If you want, you can also rotate the monitor a full 90 degrees for vertical orientation—something I certainly appreciate.</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="ebTu2zDtx4oim7EykqP6pc" name="LG-UltraGear-27GX790B-B--13" alt="LG UltraGear 27GX790B-B stand" src="https://cdn.mos.cms.futurecdn.net/ebTu2zDtx4oim7EykqP6pc.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>You get a good amount of ports, including two HDMI, one DisplayPort, a lone USB-C, and a pair of USB-A. All the ports are located on the back, so you’ll need to turn the whole monitor and stand around to access them. The button to switch from 540Hz to 720Hz is conveniently located underneath the display’s bottom bezel, along with the OSD joystick.</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="bt7ZdPu2Y6DietvQFZJg7G" name="LG-UltraGear-27GX790B-B--15" alt="LG UltraGear 27GX790B-B ports" src="https://cdn.mos.cms.futurecdn.net/bt7ZdPu2Y6DietvQFZJg7G.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 wide and flat stand keeps the monitor in place even when you’re swiveling it. It’s also large enough to place items like your phone or an extra controller. The shaft doesn’t have an opening for tucking your cables through, but this isn’t a deal-breaker.</p><h2 id="vivid-display">Vivid display</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="C3wpoW2goU9QQyaVXZF29A" name="LG-UltraGear-27GX790B-B--5-LEDE" alt="LG UltraGear 27GX790B-B" src="https://cdn.mos.cms.futurecdn.net/C3wpoW2goU9QQyaVXZF29A.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 27-inch OLED panel on the 27GX790B-B is a sight to behold. Even though it tops out at 1440p, you get sharp, crisp picture quality when playing games or scrolling through websites. The OLED itself delivers strong contrast between dark and light elements, which helps oversaturated colors look even more vivid.</p><p>I played <a href="https://www.tomsguide.com/reviews/cyberpunk-2077-phantom-liberty">Cyberpunk 2077</a> on this monitor and was impressed by how vivid the dystopian Night City looked. All the cars, buildings, pedestrians, and holographic displays popped out, heightening my immersion. Similarly, YouTube videos and websites looked great.</p><p>The 27GX790B-B has 14 display modes, including modes dedicated to game genres like FPS and RTS. Most of the modes are only slightly different from one another, depending on their intended function. If these presets aren’t to your liking, the “Personalized Picture” mode offers a greater degree of customization.</p><p>One of the big selling points here is the HDR brightness, which LG claims is the highest ever for an OLED gaming monitor. To that end, let’s take a look at what our lab results had to say about the Max Brightness display mode.</p><div ><table><caption>Display benchmarks</caption><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>LG UltraGear 27GX790B-B</strong></p></td><td  ><p><strong>Alienware AW2726DM</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Nits (brightness)</strong></p></td><td  ><p>249 (SDR) | 561 (HDR)</p></td><td  ><p>181 (SDR) / 342 (HDR)</p></td></tr><tr><td class="firstcol " ><p><strong>sRGB</strong></p></td><td  ><p>177%</p></td><td  ><p>190%</p></td></tr><tr><td class="firstcol " ><p><strong>DCI-P3</strong></p></td><td  ><p>125.4%</p></td><td  ><p>140.9%</p></td></tr><tr><td class="firstcol " ><p><strong>Delta-E</strong></p></td><td  ><p>0.33</p></td><td  ><p>0.24</p></td></tr></tbody></table></div><p>As you can see from the table above, the LG UltraGear 27GX790B-B produces oversaturated colors (sRGB and DCI-P3) and decent color accuracy (Delta-E). We saw similar values across most of the other modes. The <a href="https://www.tomsguide.com/computing/monitors/i-just-tested-alienwares-new-usd349-gaming-monitor-and-its-too-good-to-be-true">Alienware AW2726DM</a> also produces oversaturated hues, though it has better color accuracy (closer to 0 is best).</p><p>You’ll notice that the LG UltraGear 27GX790B-B delivers significantly higher brightness than its Alienware counterpart. While 561 nits across 10% of the display might not sound impressive, keep in mind that this is nearly double what most OLED gaming monitors deliver. It makes a huge difference, making everything appear more vibrant.</p><h2 id="smooth-performance-2">Smooth performance</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="SY5eHKhiZfCs8F7oapXThk" name="LG-UltraGear-27GX790B-B--3" alt="LG-UltraGear-27GX790B-B" src="https://cdn.mos.cms.futurecdn.net/SY5eHKhiZfCs8F7oapXThk.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>Thanks to its “Dual Mode” feature, discussing the 27GX790B-B’s performance isn’t as straightforward as it is with other gaming monitors. The default setting is 1440p at 540Hz. With the press of a button, you can switch to 720p at 720Hz. Both of these are tailor-made for professional competitive gamers or hardcore enthusiasts.</p><p>Regardless of which mode you choose, both have the same low response time of 0.02ms. Compatibility with Nvidia G-SYNC Compatible & AMD FreeSync Premium Pro also ensures smooth performance.</p><p>For my testing, I had the 27GX790B-B connected to the new Razer Blade 16 gaming laptop, which packs an Intel Core Ultra 9 “Panther Lake” CPU, an Nvidia GeForce RTX 5090 mobile GPU, and 32GB of RAM. That’s a pretty powerful gaming laptop, but even with such a rig, you’ll struggle to get frame rates that match this monitor’s refresh rates—even if you drop the graphics settings to low and disable all effects like ray tracing.</p><p>That said, even if you can’t get a game to run at 540 frames per second, games will run very smoothly. During my time testing Cyberpunk 2077 on this monitor, I never experienced screen tearing or input delays. The low response time also contributes to the excellent performance.</p><h2 id="simple-ui">Simple UI</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="UMDYVwWVbTTYdYhYQNqWe7" name="LG-UltraGear-27GX790B-B--16" alt="LG UltraGear 27GX790B-B UI" src="https://cdn.mos.cms.futurecdn.net/UMDYVwWVbTTYdYhYQNqWe7.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 27GX790B-B has the same simple and clean interface I’ve come to expect from UltraGear monitors. This is where you’ll find the aforementioned display modes, along with picture adjust, sound, input, and general options. Everything is easy to locate.</p><p>The OSD (On Screen Display) joystick under the display is small but intuitive to use. You don’t have to apply much pressure when you’re moving it up, down, left, or right with your finger.</p><p>LG’s interface is pretty bare, but I like the simplicity since I always know where to find what I’m looking for. As I’ve said in previous reviews, the less time I spend fiddling around in the menu, the more time I can spend actually playing games.</p><h3 class="article-body__section" id="section-lg-ultragear-27gx790b-b-review-the-downs"><span>LG UltraGear 27GX790B-B review: The downs</span></h3><p>The LG UltraGear 27GX790B-B is certainly impressive, but its defining feature is also its greatest weakness.</p><h2 id="obscenely-high-refresh-rate">Obscenely high refresh rate</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="v3DrmsFGyR9JuV7aY6yfJM" name="LG-UltraGear-27GX790B-B--7" alt="LG UltraGear 27GX790B-B" src="https://cdn.mos.cms.futurecdn.net/v3DrmsFGyR9JuV7aY6yfJM.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 big selling point of this monitor is its super-high refresh rates. While it’s certainly impressive to see a monitor going as high as 720Hz, I don’t think it’s completely necessary.</p><p>The main issue is that very few games can achieve frame rates high enough to match the refresh rate. Perhaps you could pull it off if you’re playing an ancient game on the lowest possible settings and on a gaming rig with an RTX 5090 GPU and an obscene amount of RAM, but that’s the only scenario I can imagine.</p><p>Then there’s the loss of visual fidelity. 540Hz at 1440p looks fine, but everything looks very blurry when playing at 720Hz at 720p resolution. I understand you’re prioritizing performance over visuals, but if you can’t clearly see enemies in a game, is the extra refresh rate even worth it?</p><p>I realize I’m not the target esports player who would want such ludicrously high refresh rates. I might feel different if I had the reflexes and timing required for professional gaming. But as an average gamer, I’d rather have a monitor with a more modest refresh rate.</p><h2 id="no-4k-option">No 4K option</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="Wok9THxoBLUA8jjPKuZtGY" name="LG-UltraGear-27GX790B-B--4" alt="LG UltraGear 27GX790B-B" src="https://cdn.mos.cms.futurecdn.net/Wok9THxoBLUA8jjPKuZtGY.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>This ties into the last point, but to achieve such lofty refresh rates, resolution had to take a hit—hence why this isn’t a 4K monitor. That’s a shame, considering how the <a href="https://www.tomsguide.com/computing/monitors/lg-ultragear-32gs95ue-b-review">LG UltraGear 32GS95UE-B</a> has a default setting of 240Hz and 4K resolution.</p><p>Again, I’m sure professional gamers are fine with sacrificing visuals to achieve the best performance possible—but I’m not that kind of gamer!</p><h3 class="article-body__section" id="section-lg-ultragear-27gx790b-b-review-verdict"><span>LG UltraGear 27GX790B-B review: Verdict</span></h3><p>There’s no denying that the LG UltraGear 27GX709B-B offers unprecedented performance. It also delivers astonishing HDR brightness for an OLED gaming monitor. For what you get, it’s certainly worth considering, even if it's admittedly for niche use cases.</p><p>That same focus on a specific audience is also this monitor’s greatest weakness. Yes, it’s cool that it can achieve such monumental refresh rates, but most folks don’t need that level of performance. And while the $999 asking price isn’t offensive, something like the $349 Alienware AW2726 has excellent performance and picture quality for a third of the cost—even if it doesn’t get nearly as bright.</p><p>The LG UltraGear 27GX790B-B isn’t a gaming monitor for everyone, but it’s arguably the best at what it does. For that reason, I say check it out if you are a hardcore competitive gamer who wants what is arguably the fastest gaming monitor available.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 56 Amazon Gaming Week PS5, Switch, Xbox video game deals actually worth buying ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/56-amazon-gaming-week-ps5-switch-xbox-video-game-deals-actually-worth-buying</link>
                                                                            <description>
                            <![CDATA[ I dug past the Amazon Gaming Week filler and found 56 genuine bargains across PS5, Nintendo Switch, and Xbox worth your money. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">NYAtqiWw9GCfohk9vDLMM6</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/f28AxCfSgmVkRKPJ2tNfzh-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 29 Apr 2026 10:21:55 +0000</pubDate>                                                                                                                                <updated>Wed, 29 Apr 2026 10:33:13 +0000</updated>
                                                                                                                                            <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ john-anthony.disotto@futurenet.com (John-Anthony Disotto) ]]></author>                    <dc:creator><![CDATA[ John-Anthony Disotto ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/apUjevMoC6MzjfVN7GBCoi.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;John-Anthony Disotto is the Collections Editor at Tom&#039;s Guide, curating advice on the best products to spend your hard-earned cash on. An award-winning journalist and longtime Apple expert, he previously covered AI at TechRadar and served as How To Editor at iMore.&lt;/p&gt;&lt;p&gt;He used to work for Apple as a technician focused on iOS and iPhone repairs at the Genius Bar and has used the Apple ecosystem for over a decade. In his spare time, John-Anthony can be found watching any sport under the sun, from football to darts, taking the term &#039;Lego house&#039; far too literally as he runs out of space to display any more plastic bricks, or chilling on the couch with his French bulldog, Kermit. &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/f28AxCfSgmVkRKPJ2tNfzh-1280-80.jpg">
                                                            <media:credit><![CDATA[Amazon / Sony / Nintendo / Microsoft / Edited by Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[amazon gaming week]]></media:description>                                                            <media:text><![CDATA[amazon gaming week]]></media:text>
                                <media:title type="plain"><![CDATA[amazon gaming week]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/f28AxCfSgmVkRKPJ2tNfzh-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Did you know Amazon Gaming Week has started? You'd be forgiven if you weren't aware, because quite honestly I had no idea up until this morning.</p><p>Amazon-themed discount weeks can often be underwhelming, especially when it's just a load of old stock the company is trying to offload before the next big Amazon Prime Day.</p><p>That said, I've scoured through Amazon Gaming Week and selected what I believe to be the best deals across Nintendo Switch, PS5, and Xbox, so you can add a new game to your library just in time for the weekend.</p><p>Some of these games are physical releases while others are discounts on digital codes (check the product name to be sure). And while I've not played all of these games, I've checked reviews and made sure nothing on this list is filler.</p><p>If you want my personal recommendation, I suggest any of the Resident Evil games on PS5, Sonic X Shadow Generations on Nintendo Switch, or Doom: The Dark Ages on Xbox.</p><h3 class="article-body__section" id="section-ps5-games"><span>PS5 Games</span></h3>        <div class="featured_product_block featured_block_hero" data-id="f9f169c1-5818-4a19-a9cb-d1e537872d25">            <a href="https://www.amazon.com/dp/B0D4RJGFDT" data-model-name="Metal Gear Solid Δ: Snake Eater Tactical Ed – PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:127.23%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/CFNtYigYmu6SWVssdjJLeP.jpg" alt="Metal Gear Solid Δ: Snake Eater Tactical Ed – Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Konami</div>                                        <div class="featured__title">Metal Gear Solid Δ: Snake Eater Tactical Ed – PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="3b2a1119-8ae1-4d0c-977b-577d131ea8c6">            <a href="https://www.amazon.com/dp/B0DKW2H52M" data-model-name="Resident Evil 2 - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/d34avGWyNmWv9pmT2vGKLN.jpg" alt="Resident Evil 2 - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Capcom</div>                                        <div class="featured__title">Resident Evil 2 - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="61eb6fb5-5a17-4a08-95b1-28b0b21dc5c0">            <a href="https://www.amazon.com/dp/B0DKWQ5WSZ" data-model-name="Resident Evil 3 - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/RRnciVKm4objZUXTyLXaRN.jpg" alt="Resident Evil 3 - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Capcom</div>                                        <div class="featured__title">Resident Evil 3 - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="f89a183e-5c7b-46ee-92bb-83625a96f63d">            <a href="https://www.amazon.com/dp/B0DKW9TJ23" data-model-name="Resident Evil 7 Biohazard Gold Edition - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/UuRHaxQTyC4FCwvzX5qLPN.jpg" alt="Resident Evil 7 Biohazard Gold Edition - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Capcom</div>                                        <div class="featured__title">Resident Evil 7 Biohazard Gold Edition - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="f0d1ce32-c522-48de-a686-0aacd3c3d3c7">            <a href="https://www.amazon.com/dp/B0DVMVRN9Z" data-model-name="Elden Ring Nightreign PS5 Amazon Exclusive Deluxe Edition" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/965kWMuLxG7pDPKZGqi8UP.jpg" alt="Elden Ring Nightreign Ps5 Amazon Exclusive Deluxe Edition"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Bandai Namco</div>                                        <div class="featured__title">Elden Ring Nightreign PS5 Amazon Exclusive Deluxe Edition</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="e8b5ab2a-ea95-4f85-97db-f7adb7705ffc">            <a href="https://www.amazon.com/dp/B0CW5RNMJR" data-model-name="Five Nights at Freddy's Help Wanted 2 PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/9XeP7bn88oFUDJ4eMvpzKP.jpg" alt="Five Nights at Freddy's Help Wanted 2 Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Five Nights at Freddy's Help Wanted 2 PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="b37c77b1-d031-4f73-b4dd-8c4245a27285">            <a href="https://www.amazon.com/dp/B0DT1HDBMY" data-model-name="Pga Tour 2K25 - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/haPRDzNtio5BMNhecntvRP.jpg" alt="Pga Tour 2k25 - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>2K</div>                                        <div class="featured__title">Pga Tour 2K25 - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="ff5cc9f3-42a9-45e6-a957-7eb12d0d65a9">            <a href="https://www.amazon.com/dp/B0D2PL2X82" data-model-name="Cat Quest III PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/T4AmWe57rhywiJSspkEmVN.jpg" alt="Cat Quest Iii Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Cat Quest III PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="833e4431-3142-4613-b6da-f7ccc3707b54">            <a href="https://www.amazon.com/dp/B0D1ZH728K" data-model-name="Squirrel With a Gun PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/gvhAipyijyS5w2sS6X7ZPP.jpg" alt="Squirrel With a Gun Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Squirrel With a Gun PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="255fc105-8eee-4678-9fb8-57c6d2e16572">            <a href="https://www.amazon.com/dp/B0DV9TT5XT" data-model-name="WWE 2K25 - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/KNfRpzLA9Rz3xK5U6HEuKP.jpg" alt="Wwe 2k25 - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>2K</div>                                        <div class="featured__title">WWE 2K25 - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="42e51ef4-8ba9-464e-b21e-2f908c3858a8">            <a href="https://www.amazon.com/dp/B0GKHMCC5V" data-model-name="MLB The Show 26 – PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:124.69%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/HZ6DMvdbwxsYi6uJPiYoMN.jpg" alt="Mlb® the Show™ 26 – Ps5™"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>PlayStation</div>                                        <div class="featured__title">MLB The Show 26 – PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="51d26171-ca7d-4032-b276-c1ed9b8c900d">            <a href="https://www.amazon.com/dp/B0DYR6F37F" data-model-name="MotoGP25 - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/YELowVBSNiFudxaG7EDPWP.jpg" alt="Motogp25 - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Deep Silver</div>                                        <div class="featured__title">MotoGP25 - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="14234d9d-c1b3-498b-ae8e-e3bd5e02cdea">            <a href="https://www.amazon.com/dp/B0DQVTFS95" data-model-name="Roadcraft PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:122.25%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/KmJJAw7D6SYaASS9AB2EcP.jpg" alt="Roadcraft Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Roadcraft PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="301f2907-13a0-48a6-859a-405bd3e4c55c">            <a href="https://www.amazon.com/dp/B0DDWF8KKD" data-model-name="Lost Records - Bloom & Rage PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/MphMSeeBbgMoMHetJiythP.jpg" alt="Lost Records - Bloom & Rage Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Lost Records - Bloom & Rage PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="514ac2e7-ad48-443f-a09b-4da30bb5da76">            <a href="https://www.amazon.com/dp/B0F1C14LY8" data-model-name="Silent Hill F - Playstation 5, Amazon Exclusive Day One Edition" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:127.23%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/ABUY6EVhx6KtcTKz78pVgP.jpg" alt="Silent Hill F - Playstation 5, Amazon Exclusive Day One Edition"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Konami</div>                                        <div class="featured__title">Silent Hill F - Playstation 5, Amazon Exclusive Day One Edition</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="2b0ca1ab-fc21-48f0-bed8-78b8d0c6c87b">            <a href="https://www.amazon.com/dp/B0DD67PTC9" data-model-name="Suikoden I & II HD Remastered PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:127.23%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/PmtWQHSE3mgfdF7JDLNpZP.jpg" alt="Suikoden I & Ii Hd Remastered Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Konami</div>                                        <div class="featured__title">Suikoden I & II HD Remastered PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="cf9c173c-9afd-4bad-810f-556be2cbe46c">            <a href="https://www.amazon.com/dp/B0DHX2V7TX" data-model-name="Monster Hunter Wilds Standard Edition - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:124.69%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/QSixp8uxYYFDUHWB7sBjUN.jpg" alt="Monster Hunter Wilds Standard Edition - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Capcom</div>                                        <div class="featured__title">Monster Hunter Wilds Standard Edition - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="8ec334c4-52f1-4767-b99b-13e9b096606e">            <a href="https://www.amazon.com/dp/B0DGW4BY9C" data-model-name="Dog Man: Misson Impawsible - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:118.76%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/LxwNBP699Lcyuf7KFKCqXN.jpg" alt="Dog Man: Misson Impawsible - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Mindscape</div>                                        <div class="featured__title">Dog Man: Misson Impawsible - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="8e8640f9-1f7b-4cec-b4b2-2ab809613b05">            <a href="https://www.amazon.com/dp/B0BJTKYLCB" data-model-name="Resident Evil 4 - PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:117.65%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/oxjrFenfGG9brFiay2nGQN.jpg" alt="Resident Evil 4 - Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Capcom</div>                                        <div class="featured__title">Resident Evil 4 - PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="093cfa80-9972-44b1-9325-984f82e081ae">            <a href="https://www.amazon.com/dp/B0DX42RXMS" data-model-name="Lost Soul Aside - PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:124.69%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/YJc3WUX4ZjUtaxSMVBzUaR.jpg" alt="Lost Soul Aside - Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>PlayStation</div>                                        <div class="featured__title">Lost Soul Aside - PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="b698cb74-1380-4126-9aa5-0e9c22bd87ec">            <a href="https://www.amazon.com/dp/B0F19GPDW3" data-model-name="Death Stranding 2: On the Beach - PS5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:127.55%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/bX7L2WmndWDTmvQ6UpgYXR.jpg" alt="Death Stranding 2: on the Beach - Ps5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>PlayStation</div>                                        <div class="featured__title">Death Stranding 2: On the Beach - PS5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="c98b5d18-30ee-41d1-9964-95f877aef4d8">            <a href="https://www.amazon.com/dp/B0DKV9B1Y3" data-model-name="Bye Sweet Carole - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/Kbwa6DRLwdZJkkKsxy5meR.jpg" alt="Bye Sweet Carole - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Bye Sweet Carole - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="f4b7c7d9-0285-433d-a451-b31c1e41ab49">            <a href="https://www.amazon.com/dp/B0F49DTZ88" data-model-name="Disney Illusion Island Starring Mickey & Friends - Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/kSeFZdNYEukFyqjzHA9UWR.jpg" alt="Disney Illusion Island Starring Mickey & Friends - Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Nighthawk Interactive</div>                                        <div class="featured__title">Disney Illusion Island Starring Mickey & Friends - Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="4378eefb-c00a-4b21-b6fb-7bfe01e7c95b">            <a href="https://www.amazon.com/dp/B0DTRRGVSD" data-model-name="Doom: The Dark Ages – Playstation 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:140.06%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/kRUQ2wPRygz7fziNqE3sYR.jpg" alt="Doom: the Dark Ages – Playstation 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Xbox</div>                                        <div class="featured__title">Doom: The Dark Ages – Playstation 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div><h3 class="article-body__section" id="section-nintendo-switch-games"><span>Nintendo Switch games</span></h3>        <div class="featured_product_block featured_block_hero" data-id="e1853e4a-1789-40c4-9d39-76cbba38c41c">            <a href="https://www.amazon.com/dp/B0D9PKCT42" data-model-name="Yu-Gi-Oh! Early Days Collection Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/h6keEAgzoSbZXVjcRY5joZ.jpg" alt="Yu-Gi-Oh! Early Days Collection Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Konami</div>                                        <div class="featured__title">Yu-Gi-Oh! Early Days Collection Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="e3a6173d-741a-470c-8d30-645857461ec1">            <a href="https://www.amazon.com/dp/B0D6JKTRHP" data-model-name="Sonic X Shadow Generations - Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/e6eMqddKxDRMVCHjJiAMpZ.jpg" alt="Sonic X Shadow Generations - Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>SEGA</div>                                        <div class="featured__title">Sonic X Shadow Generations - Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="e034556f-c538-4403-8e3b-3af7e34ffc4e">            <a href="https://www.amazon.com/dp/B078JWMTNC" data-model-name="Bayonetta 2 - Nintendo Switch [digital Code]" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:75.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/4ZFFzBYqPz3bZ9oBkifpfZ.jpg" alt="Bayonetta 2 - Nintendo Switch [digital Code]"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Nintendo</div>                                        <div class="featured__title">Bayonetta 2 - Nintendo Switch [digital Code]</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="70d19b6e-291b-4e1d-95f3-dc9ab13bc0dd">            <a href="https://www.amazon.com/dp/B0D7NQN715" data-model-name="Marvel Vs. Capcom Fighting Collection: Arcade Classics - Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/kRFYXD5JGytfziYFLRTrjZ.jpg" alt="Marvel Vs. Capcom Fighting Collection: Arcade Classics - Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Capcom</div>                                        <div class="featured__title">Marvel Vs. Capcom Fighting Collection: Arcade Classics - Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="2f0b7aee-a0bc-4187-b840-6cd695f4edda">            <a href="https://www.amazon.com/dp/B0DSCRSCJW" data-model-name="Carmen Sandiego 40th Anniversary Edition Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/5WN7k9hWMLh9vPJvu2pdMZ.jpg" alt="Carmen Sandiego 40th Anniversary Edition Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Carmen Sandiego 40th Anniversary Edition Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="ad487d0e-dff8-4b0e-9fc2-dae56fd336c7">            <a href="https://www.amazon.com/dp/B0FBCNB57Q" data-model-name="40 Sports Games in 1 Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/mEtZngQKkMR4kbFCyTuMdZ.jpg" alt="40 Sports Games in 1 Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">40 Sports Games in 1 Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="1c49289f-1791-418f-85dd-2a3802eaa3b1">            <a href="https://www.amazon.com/dp/B0D2PJ2WMT" data-model-name="Cat Quest III Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/chMMSXddNSFkhMJzG6bdVZ.jpg" alt="Cat Quest Iii Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Cat Quest III Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="bc83249a-2527-4d3c-9fc5-89ed4fb47630">            <a href="https://www.amazon.com/dp/B07B3NQJY9" data-model-name="Kirby Star Allies - Nintendo Switch [digital Code]" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:57.20%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/7Ef4FGgsoaPTp79ify8ZHD.jpg" alt="Kirby Star Allies - Nintendo Switch [digital Code]"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Nintendo</div>                                        <div class="featured__title">Kirby Star Allies - Nintendo Switch [digital Code]</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="d3e455d5-eff6-4be0-91f8-0d7568b1a301">            <a href="https://www.amazon.com/dp/B07BW16JT3" data-model-name="Hyrule Warriors: Definitive Edition - Nintendo Switch [Digital Code]" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:56.20%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/hvB37GHu4DRnFJNQGjSPbZ.jpg" alt="Hyrule Warriors: Definitive Edition - Nintendo Switch [digital Code]"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Nintendo</div>                                        <div class="featured__title">Hyrule Warriors: Definitive Edition - Nintendo Switch [Digital Code]</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="4e912447-27b6-49fc-bbf7-5346508fd199">            <a href="https://www.amazon.com/dp/B07DM7KD4W" data-model-name="Fire Emblem: Three Houses - Nintendo Switch [igital Code]" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:56.20%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/CmSfRgajLpDJ6aiXfKQiFZ.jpg" alt="Fire Emblem: Three Houses - Nintendo Switch [digital Code]"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Nintendo</div>                                        <div class="featured__title">Fire Emblem: Three Houses - Nintendo Switch [igital Code]</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="528a4390-64ef-46c5-88d3-1e51665cabc5">            <a href="https://www.amazon.com/dp/B0DCHN3YQL" data-model-name="Cat Quest - The Fur-Tastic Trilogy Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/EJDSJZE7oKZmRix9P5JJiZ.jpg" alt="Cat Quest - the Fur-Tastic Trilogy Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Cat Quest - The Fur-Tastic Trilogy Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="0c74b6dd-403d-4faf-a722-139bd40c71a4">            <a href="https://www.amazon.com/dp/B0CK4Y8YLG" data-model-name="Star Wars: Heritage Pack - Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/tXUChGvKw2Vug4XVGYKSQZ.jpg" alt="Star Wars: Heritage Pack - Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Aspyr</div>                                        <div class="featured__title">Star Wars: Heritage Pack - Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="9c670a11-ce5b-41aa-b861-03c67cd1089f">            <a href="https://www.amazon.com/dp/B0DGW49QJB" data-model-name="Dog Man: Mission Impawsible - Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/pTkot4eYa2TMBqyjgYiNTZ.jpg" alt="Dog Man: Mission Impawsible - Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Mindscape</div>                                        <div class="featured__title">Dog Man: Mission Impawsible - Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="91adad6f-d5d1-441a-b651-b0a3cfed4033">            <a href="https://www.amazon.com/dp/B0DFRLZBP8" data-model-name="Five Nights at Freddy's Help Wanted 2 Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/PybZ7HnsSHHHDi5fJmDDKZ.jpg" alt="Five Nights at Freddy's Help Wanted 2 Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Five Nights at Freddy's Help Wanted 2 Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="cd6735f8-3b5d-4aca-80b2-cced45d0b47a">            <a href="https://www.amazon.com/dp/B0CW3LVC9H" data-model-name="Disney Epic Mickey: Rebrushed - Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/Lhm4jkdX7URdbWv4KyfWGZ.jpg" alt="Disney Epic Mickey: Rebrushed - Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>THQ Nordic</div>                                        <div class="featured__title">Disney Epic Mickey: Rebrushed - Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="f88204d5-a29a-4b47-aa1c-73b1d0b3d94b">            <a href="https://www.amazon.com/dp/B0DKV7PZHK" data-model-name="Bye Sweet Carole - Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/42yC2d2E7B2zPuCiftM9mZ.jpg" alt="Bye Sweet Carole - Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Bye Sweet Carole - Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="83a021f4-a07f-4fcb-a8f9-788e15daa7b6">            <a href="https://www.amazon.com/dp/B0F2PPWWMX" data-model-name="Xseed Games Story of Seasons: Grand Bazaar - Premium Edition - Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:77.40%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/maLRXYD2Ro4yLbJs6BxcYZ.jpg" alt="Xseed Games Story of Seasons: Grand Bazaar - Premium Edition - Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Xseed Games</div>                                        <div class="featured__title">Xseed Games Story of Seasons: Grand Bazaar - Premium Edition - Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="732a1d9d-b174-4ae7-834f-d4bbf8549906">            <a href="https://www.amazon.com/dp/B0CJ3GM5CS" data-model-name="Bluey: the Videogame- Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/Kb6ZYgzdkJWGVhn9iRzZeb.jpg" alt="Bluey: the Videogame- Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Outright Games</div>                                        <div class="featured__title">Bluey: the Videogame- Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="60400a59-8da5-4bbb-879b-045c6ebe86b2">            <a href="https://www.amazon.com/dp/B0C91MLPNG" data-model-name="Sonic Superstars - Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/BHz2FX775HJJP8YwKuqvfb.jpg" alt="Sonic Superstars - Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>SEGA</div>                                        <div class="featured__title">Sonic Superstars - Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="db3ed566-87b4-412b-9bd6-0f9fae7a1cdf">            <a href="https://www.amazon.com/dp/B0DD6HKF2H" data-model-name="Suikoden I & II HD Remastered Nintendo Switch" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:150%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/CN8Lb9BPKJ4TyWAVKhgMjb.jpg" alt="Suikoden I & Ii Hd Remastered Nintendo Switch"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Konami</div>                                        <div class="featured__title">Suikoden I & II HD Remastered Nintendo Switch</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div><h3 class="article-body__section" id="section-xbox-games"><span>Xbox Games</span></h3>        <div class="featured_product_block featured_block_hero" data-id="5d45dfd8-eb1f-4207-be4b-ad1550910e01">            <a href="https://www.amazon.com/dp/B071ZF5L32" data-model-name="Far Cry 5 - Xbox One Standard Edition" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:126.90%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/EYyA69zqAax8KLLhE8z6Fe.jpg" alt="Far Cry 5 - Xbox One Standard Edition"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Ubisoft</div>                                        <div class="featured__title">Far Cry 5 - Xbox One Standard Edition</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="47da0e7c-dc75-4f33-8d31-956cc7b5a0aa">            <a href="https://www.amazon.com/dp/B0DTRP1PC5" data-model-name="Doom: The Dark Ages – Xbox Series X" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:140.45%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/YCvBd3yBCMoz7jjPCRGzSe.jpg" alt="Doom: the Dark Ages – Xbox Series X"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Xbox</div>                                        <div class="featured__title">Doom: The Dark Ages – Xbox Series X</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="43f7e9ee-7366-4654-a426-e5fe1b0c24db">            <a href="https://www.amazon.com/dp/B0DYVS54XN" data-model-name="Tony Hawk's™ Pro Skater™ 3 + 4 – Collector's Edition – Xbox Series X and Xbox One" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/vZumDHkDWQhdLubz9GYXW6.jpg" alt="Tony Hawk's™ Pro Skater™ 3 + 4 – Collector's Edition – Xbox Series X and Xbox One"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Xbox</div>                                        <div class="featured__title">Tony Hawk's™ Pro Skater™ 3 + 4 – Collector's Edition – Xbox Series X and Xbox One</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="be1ee031-d8a0-49a9-9bf1-afce5c132e2e">            <a href="https://www.amazon.com/dp/B0DT1JY68G" data-model-name="PGA Tour 2K25 - Xbox Series X" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:136.24%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/7VHD9SuQStYCsGhJSYu6Ke.jpg" alt="Pga Tour 2k25 - Xbox Series X"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>2K</div>                                        <div class="featured__title">PGA Tour 2K25 - Xbox Series X</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="0eff6f88-da3f-47a1-9922-ec7be64ee289">            <a href="https://www.amazon.com/dp/B0DYR3Y3MH" data-model-name="Motogp25 - Xbox Series X" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:127.88%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/fCVTFNkBe2fA8UMA72j6Ge.jpg" alt="Motogp25 - Xbox Series X"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Deep Silver</div>                                        <div class="featured__title">Motogp25 - Xbox Series X</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="f24d1b51-08ab-4eda-8ced-80c4b4c4ea2b">            <a href="https://www.amazon.com/dp/B0F2541MYQ" data-model-name="Raidou: Remastered – the Mystery of the Soulless Army Launch Edition - Xbox Series X" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:136.24%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/uRnTv6g2sTWAUWHHWX3WRe.jpg" alt="Raidou: Remastered – the Mystery of the Soulless Army Launch Edition - Xbox Series X"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>SEGA</div>                                        <div class="featured__title">Raidou: Remastered – the Mystery of the Soulless Army Launch Edition - Xbox Series X</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="c64a6a67-aa77-4c0b-9c3d-36f22a6c9f5f">            <a href="https://www.amazon.com/dp/B0DQBJB1SN" data-model-name="Five Nights at Freddy's Help Wanted 2 Xbox Series X" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/UMHYBEpaFMiwt7q82ajgMe.jpg" alt="Five Nights at Freddy's Help Wanted 2 Xbox Series X"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Five Nights at Freddy's Help Wanted 2 Xbox Series X</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="cb2843ba-18d0-488a-947d-55ef864967ff">            <a href="https://www.amazon.com/dp/B0DQVRK4WH" data-model-name="Roadcraft Xbox Series X" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:127.23%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/VKniwvU74owVwLmiaBSoKe.jpg" alt="Roadcraft Xbox Series X"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Roadcraft Xbox Series X</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="5a2325b3-d234-40e7-af8f-4746e8dddebe">            <a href="https://www.amazon.com/dp/B0DGWQSHW4" data-model-name="Revenge of the Savage Planet Day One Edition Xbox Series X" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/9VuWFP3Mf2DHunB3nuTwPe.jpg" alt="Revenge of the Savage Planet Day One Edition Xbox Series X"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Revenge of the Savage Planet Day One Edition Xbox Series X</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="11f5307a-a30a-4baa-b99a-a3495941ce98">            <a href="https://www.amazon.com/dp/B0DVMPV5JF" data-model-name="Elden Ring Nightreign Xbox Series X Amazon Exclusive Deluxe Edition" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:122.55%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/maBZ9C9aeUkPTYNBj44oCe.jpg" alt="Elden Ring Nightreign Xbox Series X Amazon Exclusive Deluxe Edition"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Bandai Namco</div>                                        <div class="featured__title">Elden Ring Nightreign Xbox Series X Amazon Exclusive Deluxe Edition</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="455ff97c-4401-4a5f-abf0-6cde91933745">            <a href="https://www.amazon.com/dp/B0DN3DM49R" data-model-name="Poppy Playtime Triple Pack Xbox Seriex X | Xbox One" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:115.47%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/yL7CSQuvseueNq6hWaLDCe.jpg" alt="Poppy Playtime Triple Pack Xbox Seriex X | Xbox One"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Maximum Entertainment</div>                                        <div class="featured__title">Poppy Playtime Triple Pack Xbox Seriex X | Xbox One</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Valve is 'hard at work' on Steam Deck 2, but Steam Machine and Steam Frame are held hostage by AI gold rush ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/handheld-gaming/valve-is-hard-at-work-on-steam-deck-2-but-steam-machine-and-steam-frame-are-held-hostage-by-ai-gold-rush</link>
                                                                            <description>
                            <![CDATA[ Valve is 'hard at work' on the Steam Deck 2, but the Steam Machine and Steam Frame face a major roadblock. Here are my launch predictions, the 2026 hardware roadmap and how the global RAM crisis is shifting Valve's strategy. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">2xyTpn9e7hfsDp6z3WgknR</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ePtQiRAw8M9V2QGMEyEFTG-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 28 Apr 2026 11:11:30 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Handheld Gaming]]></category>
                                                    <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                                    <dc:creator><![CDATA[ Jason England ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/v4fSq5U4uZUEtGY2BwNuJ6.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Jason brings a decade of tech and gaming journalism experience to his role as a Managing Editor of Computing at Tom&#039;s Guide. He has previously written for Laptop Mag, Tom&#039;s Hardware, Kotaku, Stuff and BBC Science Focus. In his spare time, you&#039;ll find Jason looking for good dogs to pet or thinking about eating pizza if he isn&#039;t already.&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/ePtQiRAw8M9V2QGMEyEFTG-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Steam Deck OLED]]></media:description>                                                            <media:text><![CDATA[Steam Deck OLED]]></media:text>
                                <media:title type="plain"><![CDATA[Steam Deck OLED]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ePtQiRAw8M9V2QGMEyEFTG-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review-roundup">Steam Controller</a> is here, but the <a href="https://www.tomsguide.com/gaming/pc-gaming/steam-machine-delayed-as-valve-will-revisit-the-cost-because-of-the-ram-price-crisis">Steam Machine and Steam Frame have been delayed</a> due to the ongoing RAM price crisis. However, Valve Programmer Pierre-Loup Griffais spoke to <a href="https://www.ign.com/articles/the-steam-controller-interview" target="_blank">IGN</a> and confirmed that while there isn’t an exact launch timeline, “things are going well” and we can expect news “soon.”</p><p>But his comments looked further into the future too, as he confirmed that the company is “hard at work” on <a href="https://www.tomsguide.com/gaming/handheld-gaming/steam-deck-2-rumored-to-be-in-the-works-and-it-may-arrive-with-a-massive-amd-apu-upgrade">Steam Deck 2</a> — echoing a lot of what <a href="https://www.tomsguide.com/gaming/handheld-gaming/we-may-never-get-a-steam-deck-2-and-im-ok-with-that-heres-why">Griffais told me</a> in terms of wanting to see a “worthwhile performance upgrade to make sense.”</p><h2 id="ram-is-the-pain-point">RAM is the pain point</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="6xBrL6Zv4c8cVa3fWMuZtQ" name="image (1)" alt="Valve Steam Machine, Steam Frame, and Steam Controller devices" src="https://cdn.mos.cms.futurecdn.net/6xBrL6Zv4c8cVa3fWMuZtQ.png" 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: Valve)</span></figcaption></figure><p>It’s the most obvious answer, right? And Valve confirmed as much in its <a href="https://store.steampowered.com/news/group/45479024/view/625565405086220583" target="_blank">blog </a><a href="https://store.steampowered.com/news/group/45479024/view/625565405086220583" target="_blank">post </a>about having to “revisit” when it will ship and how much it will cost. And Valve hardware engineer Steve Cardinali said as much in his time <a href="https://www.polygon.com/steam-controller-steam-machine-release-schedule-why/" target="_blank">talking to Polygon</a> — the hardware’s not the problem, but the RAM inside it is.</p><p>“This doesn't have RAM in it, and it's not as complicated to start getting out the door for us,” Cardinali said. “We're ready for it. We wanted to build up quantity so that we could try to address everybody who wants one at launch, but it's possible that the demand for it far exceeds our expectations.”</p><p>It’s another of the many memory-related struggles the consumer tech industry has faced ever since the massive AI data center buildout spiked the cost, including the <a href="https://www.tomsguide.com/gaming/playstation/major-sony-ps5-price-hike-just-hit-all-models-heres-what-youll-pay-now">PS5 price hike recently</a>.</p><p>However, there are some reasons to be <a href="https://www.tomsguide.com/computing/hardware/from-allbirds-lunacy-to-mediateks-cautious-optimism-why-im-finally-hopeful-about-ridiculous-ram-prices">optimistic about the near future</a> (tariff refunds, Chinese RAM foundries picking up the consumer slack, etc), and all eyes are on Microsoft, Google and Amazon’s investors’ calls tomorrow to see whether there are any signs of a bubble pop.</p><p>We’ve just got to wait and see.</p><h2 id="predicting-the-launches">Predicting the launches</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:3840px;"><p class="vanilla-image-block" style="padding-top:60.68%;"><img id="RzusMSoFqREVkoErH63pMN" name="SM_ledStrip" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/RzusMSoFqREVkoErH63pMN.jpg" mos="" align="middle" fullscreen="" width="3840" height="2330" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>So while Valve has (understandably) not confirmed a timeline given everything that’s happening, it's time for me to put on my tin foil hat and lay out some predictions of my own. And it made me think about MediaTek’s comments about having “cautious optimism” about a “slowdown” in RAM price rises.</p><p>In case you missed it, MediaTek’s Head of Global Sales Eric Fischer talked about how the huge initial <a href="https://www.tomsguide.com/computing/pc-sales-are-up-but-dont-be-fooled-idc-report-warns-ramageddon-is-just-getting-started">demand for memory-heavy products early this year</a> is probably an illusion of people panic buying before it gets worse. He said that we’re on our way to a moment where “the consumer’s ability to spend” breaks, and the industry will adjust in the second half of the year.</p><p>With that in mind, allow me to paint a timeline for you:</p><ul><li><strong>Steam Machine and Steam Frame: </strong>It’s clear Valve is working hard behind the scenes to figure out RAM supply and the pricing strategy for this. I know the company said to expect news “soon,” but as for a launch, I’d look more to maybe <strong>Summer/early Fall 2026</strong>. The company’s waiting this spike out, just like we are.</li><li><strong>Steam Deck 2: </strong>For the worthwhile gains Valve is looking for in silicon performance and power efficiency, we need to look at this as more of a console generational leap more than the iterative curve of annual computing chip versions. I’m expecting an <strong>early 2028 launch.</strong></li></ul><p>But what do you think? I’ll throw up a poll to get your thoughts on when you think these devices will land!</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eBxmoO"></div>                            </div>                            <script src="https://kwizly.com/embed/eBxmoO.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/gaming/gaming-peripherals/im-a-lifelong-gamer-and-i-cant-wait-to-try-the-steam-controller-3-reasons-why">I'm a lifelong gamer, and I can't wait to try the Steam Controller — 3 reasons why</a></li><li><a href="https://www.tomsguide.com/computing/hardware/the-squeeze-is-real-i-spoke-to-ram-crisis-oracle-carmen-li-about-when-this-nightmare-ends-heres-what-she-told-me">‘The squeeze is real’: I spoke to RAM crisis oracle, Carmen Li, about when this nightmare ends — here’s what she told me</a></li><li><a href="https://www.tomsguide.com/computing/keyboards/logitech-g-g512-x-review">I became a keyboard tinkerer with the Logitech G G512 X, and it seriously upgraded my gaming performance</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I'm a lifelong gamer, and I can't wait to try the Steam Controller — 3 reasons why ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/gaming-peripherals/im-a-lifelong-gamer-and-i-cant-wait-to-try-the-steam-controller-3-reasons-why</link>
                                                                            <description>
                            <![CDATA[ The Steam Controller arrives on May 4, and I can't wait to try it. Here are the top 3 reasons why this could be the best PC game controller yet. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">pbL7GG7gvAyLNzPWKPcT2B</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/pCdaysxcM5mpT5CdE2DmhV-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 28 Apr 2026 05:15:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Gaming Peripherals]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/pCdaysxcM5mpT5CdE2DmhV-1280-80.jpg">
                                                            <media:credit><![CDATA[Valve]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A still image showing the Steam Controller]]></media:description>                                                            <media:text><![CDATA[A still image showing the Steam Controller]]></media:text>
                                <media:title type="plain"><![CDATA[A still image showing the Steam Controller]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/pCdaysxcM5mpT5CdE2DmhV-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Steam Controller is almost here, and I couldn’t be more excited. The first wave of <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review-roundup">Steam Controller reviews</a> began circulating today (May 27), and they’re almost universally positive. I was already on board when Valve announced the controller and the <a href="https://www.tomsguide.com/gaming/pc-gaming/valve-steam-machine-console-just-announced-6x-more-powerful-than-steam-deck">Steam Machine</a>, but after reading some reviews, I’m even more eager to get hands-on with this peripheral.</p><p>This isn’t the same <a href="https://www.tomsguide.com/us/valve-steam-controller,review-3263.html">Steam Controller</a> from 11 years ago. It features a brand-new, more ergonomic design. Standout features include TMR thumbsticks, large touchpads, and a unique USB dongle that also serves as a charger. Though the controller looks large and unwieldy, reviewers say it feels extremely comfortable.</p><p>I’ll have a full review once I’ve had some hands-on time with the Steam Controller. For now, here are the three main reasons I’m excited to try it.</p><div class="product"><a data-dimension112="bb94633b-4a78-4e73-8b3f-34095a4597e7" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension25="$99" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1232px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="p4kRCykqzQRFswEntyNcUE" name="Steam Controller" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/p4kRCykqzQRFswEntyNcUE.jpg" mos="" align="middle" fullscreen="" width="1232" height="1232" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4.<br><a class="view-deal button" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow" data-dimension112="bb94633b-4a78-4e73-8b3f-34095a4597e7" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension25="$99">View Deal</a></p></div><h2 id="tmr-thumbsticks">TMR thumbsticks</h2><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/a55UIaiTE-A" allowfullscreen></iframe></div></div><p>Hall Effect magnetic sticks and buttons have been all the rage for gaming controllers in recent years, but Valve has taken the next step by using more advanced TMR technology. In short, these sticks should be even less prone to stick drift because they use magnetic sensing with no physical contact, unlike traditional analog sticks. This should, in theory, keep the sticks performing like new for many years.</p><p>The <a href="https://www.tomsguide.com/gaming/gaming-peripherals/i-just-tested-the-new-scuf-valor-pro-controller-and-its-a-must-have-for-pc-gamers">Scuf Valor Pro</a> controller I reviewed also features TMR sticks, which I find extremely smooth and responsive. Given that the Steam Controller uses the same technology, I’m expecting a similar experience. Thankfully, virtually all reviews I’ve seen say the sticks are great to use and extremely responsive.</p><p>I’ll need to test the controller’s thumbsticks for myself to see if they’re up to snuff, but I have faith they’ll be as great as I imagine. This alone could make the relatively steep $99 asking price more than worth it—but there are other features I’m excited about as well.</p><h2 id="customization">Customization</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="6xBrL6Zv4c8cVa3fWMuZtQ" name="image (1)" alt="Valve Steam Machine, Steam Frame, and Steam Controller devices" src="https://cdn.mos.cms.futurecdn.net/6xBrL6Zv4c8cVa3fWMuZtQ.png" 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: Valve)</span></figcaption></figure><p>Since it’s designed for PC gaming, the Steam Controller is highly customizable and reprogrammable, so you can adjust it for whatever game you’re playing.</p><p>You can remap every digital control to virtually any PC input, such as keystrokes, gamepad buttons, mouse clicks, or more. Reviewers say that sensitivities for analog sticks, triggers, touchpads, and gyro are also adjustable. For instance, triggers support separate actions for half-pull and full-pull, allowing for more in-game actions.</p><p>Some reviewers say that programming the controller can be daunting because there are so many customization options. Given the numerous inputs, I’m inclined to believe this.</p><p>I’m eager to dive into the Steam software configurator to explore all the customization options. If said options are as robust as reviewers claim, it’s understandable why so many of them now consider this the perfect PC gaming controller.</p><h2 id="battery-life-and-charging">Battery life and charging</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:3840px;"><p class="vanilla-image-block" style="padding-top:60.68%;"><img id="p7bernaLEm4CdAJq4wuD8f" name="SC_front_b" alt="Valve Steam Machine" src="https://cdn.mos.cms.futurecdn.net/p7bernaLEm4CdAJq4wuD8f.jpg" mos="" align="middle" fullscreen="" width="3840" height="2330" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Valve)</span></figcaption></figure><p>Valve claims the Steam Controller can last 35+ hours on a single charge. Reviewers who tested the controller said this claim isn’t just boasting, as none of them had the controller run out of power even during extended sessions. Considering how the PS5 DualSense lasts eight hours if you’re lucky, over 35 hours of endurance would be incredible.</p><p>Charging the controller is interesting because it’s done via the included “Steam Controller Puck.” This is a small 2.4GHz USB dongle that doubles as a magnetic charging dock and snaps onto pins on the back of the controller. The puck connects to your PC or Steam Deck via a 5-foot USB cable. Before you ask, the cable connects to the puck via a USB-C port, in case you want to use a different length cable. Additionally, there’s a standard USB-C port on top of the controller if you want to charge it that way.</p><p>The only concern I have is that the puck reportedly connects only one way and can be finicky on some desks. Bluetooth is supported as a backup, but it’s not recommended for the best performance, as <a href="https://gizmodo.com/steam-controller-review-trackpads-change-everything-for-pc-gaming-2000751120" target="_blank">Gizmodo</a> notes. This, like everything else, is something I’ll need to experience firsthand to see how it works.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-evvmme"></div>                            </div>                            <script src="https://kwizly.com/embed/evvmme.js" async></script><h2 id="outlook-6">Outlook</h2><p>With most reviewers saying the Steam Controller is now their preferred way to play PC games, I’m very stoked to try it for myself. The original Steam Controller was unconventional and polarizing, so it’s good to see the company release a controller that has received so much universal praise.</p><p>Stay tuned for more updates on the Steam Controller, and let us know in the comments if this is a peripheral you’re interested in.</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/gaming/steam-machine-pricing-may-have-just-leaked-by-retailer-and-its-not-cheap">Steam Machine pricing may have just leaked by retailer</a></li><li><a href="https://www.tomsguide.com/gaming/pc-gaming/steam-machine-delayed-as-valve-will-revisit-the-cost-because-of-the-ram-price-crisis">Steam Machine delayed</a></li><li><a href="https://www.tomsguide.com/gaming/pc-gaming/i-might-ditch-my-gaming-pc-for-the-steam-machine-heres-why">I might ditch my gaming PC for the Steam Machine</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Steam Controller reviews are in: 'I can’t imagine playing my PC games with anything else' ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-review-roundup</link>
                                                                            <description>
                            <![CDATA[ The first reviews of the Steam Controller have gone live. Here's what tech reviewers have to say about Valve's latest peripheral. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">cWsu7h8zSyN6YEcgvAZodT</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/p7bernaLEm4CdAJq4wuD8f-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 27 Apr 2026 17:47:40 +0000</pubDate>                                                                                                                                <updated>Mon, 27 Apr 2026 18:09:59 +0000</updated>
                                                                                                                                            <category><![CDATA[Gaming Peripherals]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/p7bernaLEm4CdAJq4wuD8f-1280-80.jpg">
                                                            <media:credit><![CDATA[Valve]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Valve Steam Machine]]></media:description>                                                            <media:text><![CDATA[Valve Steam Machine]]></media:text>
                                <media:title type="plain"><![CDATA[Valve Steam Machine]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/p7bernaLEm4CdAJq4wuD8f-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The first reviews of the Steam Controller have gone live. This peripheral is effectively a redesign of the original Steam Controller from over a decade ago, and is meant to complement the upcoming Steam Machine. It’s also compatible with PC, and of course, Valve’s own Steam Deck.</p><p>As we reported over the weekend, an industry insider named <a href="https://x.com/SadlyItsBradley/status/2046363689721245922" target="_blank"><u>Brad Lynch on X</u></a> found evidence of a "<a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-launch-imminent-as-valve-uploads-secret-unboxing-heres-what-you-need-to-know"><u>Steam Controller Unboxing</u></a>" video that was uploaded to SteamDB. Soon after, reports of a potential Steam Controller price leak circulated online, suggesting the <a href="https://www.tomsguide.com/gaming/gaming-peripherals/steam-controller-price-leaked-online-and-id-start-saving-now"><u>peripheral would cost $99</u></a>. Given how reviews have gone live, it seems some folks spilled the beans prematurely.</p><p>The Steam Controller features TMR thumbsticks, rumble support, capacitive touch, and gyro controls. Like most controllers, it has four face buttons, four shoulder buttons, and the aforementioned pair of thumbsticks. Unique inputs include the large touchpads beneath the thumbsticks and four back buttons.</p><p>We’ll have our review of the Steam Controller soon. For now, here’s what tech reviewers are saying about Valve’s new peripheral.</p><div class="product"><a data-dimension112="821eeade-f5f9-4b44-b5e7-003106aa70fa" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension25="$99" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1232px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="p4kRCykqzQRFswEntyNcUE" name="Steam Controller" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/p4kRCykqzQRFswEntyNcUE.jpg" mos="" align="middle" fullscreen="" width="1232" height="1232" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4.<br><a class="view-deal button" href="https://store.steampowered.com/sale/steamcontroller" target="_blank" rel="nofollow" data-dimension112="821eeade-f5f9-4b44-b5e7-003106aa70fa" data-action="Deal Block" data-label="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension48="The new Steam Controller could be one of the best PC game controllers thanks to its Magnetic thumbsticks, a full set of inputs for your Steam games, haptic motors, and claimed 35+ hours of battery life. It's not on sale yet, but the product page says it will be available on May 4." data-dimension25="$99">View Deal</a></p></div><h2 id="what-are-reviewers-saying-about-the-steam-controller">What are reviewers saying about the Steam Controller?</h2><p>Steam Controller reviews are largely positive, with many sites and YouTube channels saying this is now their favorite PC game controller. That’s high praise, especially considering how controversial the original Steam Controller was.</p><p><a href="https://www.techradar.com/computing/peripherals-accessories/valve-steam-controller-2026" target="_blank">TechRadar’</a>s Matt Hanson says the Steam Controller is “a massive improvement over the flawed original, offering some great innovations while also coming with a more conventional — and user-friendly —design.”</p><p>This is a sentiment that <a href="https://www.pcmag.com/reviews/valve-steam-controller-2026?test_uuid=06f2t2mKxAWPbc1xmAn5J4t&test_variant=B" target="_blank">PCMag</a>’s Will Greenwald shares, saying that the controller is “fundamentally better in every way thanks to a deep feature set, terrific feel, and customizable controls like those on the Steam Deck.”</p><p>“I’ve spent so much time with Valve’s second attempt at its Steam Controller that I can’t imagine playing my PC games with anything else,” says <a href="https://www.polygon.com/steam-controller-2026-review/" target="_blank">Polygon</a>’s Giovanni Colantonio. Similarly, <a href="https://www.youtube.com/watch?v=I2RVnFP5rBI" target="_blank">IGN</a>’s Bo Moore said it was his “favorite controller for PC gaming.”</p><div><blockquote><p>I’ve spent so much time with Valve’s second attempt at its Steam Controller that I can’t imagine playing my PC games with anything else.</p><p>Giovanni Colantonio</p></blockquote></div><p>So what do reviewers love about the Steam Controller? Matt Hanson says the more conventional design is a major factor. “This makes it much easier to get to grips with if you’re used to other gamepads.” Gizmodo’s Kyle Barr echoes this sentiment, saying that the “new Steam Controller feels far more natural for anybody used to a PS5 DualSense-like design.”</p><p>The new thumbsticks also won over reviewers, thanks to TMR technology for improved performance. Not only does this lead to quicker actions, but it also allows them to glide smoothly.</p><p>“The new thumbsticks are no slouches, either, thanks to tunneling magneto-resistance (TMR) technology, which is the tech of choice for most premium gamepads. This uses small magnets to measure even the smallest of movements, which improves precision, and excels in genres such as shooters and racing games, where even the smallest of movements need to be accurately recorded and reflected in-game,” says Matt Hanson.</p><div><blockquote><p>The Steam Controller’s joysticks have the right amount of resistance to add a tactile feel to your movements.</p><p>Kyle Barr</p></blockquote></div><p>Kyle Barr says that the Steam Controller’s “joysticks have the right amount of resistance to add a tactile feel to your movements.”</p><p>One sticking point is the controller’s price of $99. While that’s certainly less than many “pro” controllers like the PS5 DualSense Edge, it’s still $20-$30 more expensive than standard PS5 or Xbox controllers. However, given its features, most reviewers say the price is justified. “But considering everything it does,” says Will Greenwald, “the Steam Controller is a worthwhile purchase if you mostly play games on Steam.”</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-evvmme"></div>                            </div>                            <script src="https://kwizly.com/embed/evvmme.js" async></script><p>Right now, it seems like the Steam Controller is a hit among reviewers, and I’m certainly eager to go hands-on with it myself. I’m curious how the gaming community will view Valve’s latest peripherals. It won’t be long to get that answer, as the Steam Controller is set to launch on May 4.</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/gaming/pc-gaming/valve-steam-machine-console-just-announced-6x-more-powerful-than-steam-deck">Steam Machine console challenges PS5 and Xbox</a></li><li><a href="https://www.tomsguide.com/gaming/pc-gaming/i-might-ditch-my-gaming-pc-for-the-steam-machine-heres-why">I might ditch my gaming PC for the Steam Machine</a></li><li><a href="https://www.tomsguide.com/gaming/pc-gaming/steam-machine-delayed-as-valve-will-revisit-the-cost-because-of-the-ram-price-crisis">Steam Machine delayed</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 'At this level, those numbers aren’t for us gamers': Why 720Hz gaming monitors might be overkill ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/at-this-level-those-numbers-arent-for-us-gamers-why-720hz-gaming-monitors-might-be-overkill</link>
                                                                            <description>
                            <![CDATA[ Are insanely high refresh rates for gaming monitors worth it? We asked experts if they provide real benefits for gamers or if it's just manufacturers flexing. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">MJaSMUHjNqTRjVQZB4dj9W</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/SY5eHKhiZfCs8F7oapXThk-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 25 Apr 2026 06:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/SY5eHKhiZfCs8F7oapXThk-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[LG-UltraGear-27GX790B-B]]></media:description>                                                            <media:text><![CDATA[LG-UltraGear-27GX790B-B]]></media:text>
                                <media:title type="plain"><![CDATA[LG-UltraGear-27GX790B-B]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/SY5eHKhiZfCs8F7oapXThk-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Shortly after I began writing for Tom’s Guide, I covered a news story about an Asus gaming monitor boasting a 240Hz refresh rate. At the time, my team and I thought it was over the top. Who but the most hardcore gamer needed such high refresh rates? In the years since, we’ve only seen refresh rates on certain gaming monitors climb even higher.</p><p>What’s the point of all this? Simply put, the higher the refresh rate on the <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html">best gaming monitors</a>, the smoother everything looks on screen. For competitive gamers, matching a game’s frame rate to a high refresh rate makes your actions feel fast and responsive. But even if you’re just a regular gamer, you can still benefit from a higher refresh rate.</p><p>I’m currently testing the LG UltraGear 27GX790B-B (<a href="https://www.amazon.com/27GX790B-B-Ultragear-TrueBlack-Compatible-DisplayPort/dp/B0G5R2QK24" target="_blank" rel="nofollow">$994 on Amazon</a>), a dual-mode monitor that can switch between 540Hz at 1440p and 720Hz at 720p. This monitor completely blows away the <a href="https://www.tomsguide.com/reviews/alienware-500hz-gaming-monitor-aw2524h">Alienware 500Hz monitor</a> I reviewed a couple of years ago. While testing it, I can’t help but ask the obvious question: Do such high refresh rates truly benefit gamers, or is this all just flexing?</p><p>For this article, I’ve reached out to two Future colleagues: Brandon Hill from <a href="https://www.tomshardware.com/" target="_blank">Tom’s Hardware</a> and Dave James from <a href="https://www.pcgamer.com/" target="_blank">PC Gamer</a>. As hardware reviewers, they know their stuff and provided me with some great insight on this topic. Here’s what they had to say about high-refresh-rate gaming monitors, along with my own thoughts.</p><div class="product"><a data-dimension112="ef7b1647-3cc6-404b-9b6e-5ddf2e071706" data-action="Deal Block" data-label="The LG UltraGear 27GX790B-B is an incredibly fast gaming monitor thanks to its Dual Mode feature that lets you switch between 540Hz at 1440p and 720Hz at 720p. In addition, it has one of the brightest OLED panels available. It isn't for everyone, but hardcore gamers will appreciate the super high refresh rates." data-dimension48="The LG UltraGear 27GX790B-B is an incredibly fast gaming monitor thanks to its Dual Mode feature that lets you switch between 540Hz at 1440p and 720Hz at 720p. In addition, it has one of the brightest OLED panels available. It isn't for everyone, but hardcore gamers will appreciate the super high refresh rates." data-dimension25="$994" href="https://www.amazon.com/27GX790B-B-Ultragear-TrueBlack-Compatible-DisplayPort/dp/B0G5R2QK24" 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:99.60%;"><img id="AQ538Qcajvop4qXyJQq3JP" name="LG UltraGear 27GX790B-B" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/AQ538Qcajvop4qXyJQq3JP.jpg" mos="" align="middle" fullscreen="" width="1500" height="1494" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The LG UltraGear 27GX790B-B is an incredibly fast gaming monitor thanks to its Dual Mode feature that lets you switch between 540Hz at 1440p and 720Hz at 720p. In addition, it has one of the brightest OLED panels available. It isn't for everyone, but hardcore gamers will appreciate the super high refresh rates.<a class="view-deal button" href="https://www.amazon.com/27GX790B-B-Ultragear-TrueBlack-Compatible-DisplayPort/dp/B0G5R2QK24" target="_blank" rel="nofollow" data-dimension112="ef7b1647-3cc6-404b-9b6e-5ddf2e071706" data-action="Deal Block" data-label="The LG UltraGear 27GX790B-B is an incredibly fast gaming monitor thanks to its Dual Mode feature that lets you switch between 540Hz at 1440p and 720Hz at 720p. In addition, it has one of the brightest OLED panels available. It isn't for everyone, but hardcore gamers will appreciate the super high refresh rates." data-dimension48="The LG UltraGear 27GX790B-B is an incredibly fast gaming monitor thanks to its Dual Mode feature that lets you switch between 540Hz at 1440p and 720Hz at 720p. In addition, it has one of the brightest OLED panels available. It isn't for everyone, but hardcore gamers will appreciate the super high refresh rates." data-dimension25="$994">View Deal</a></p></div><h2 id="high-refresh-rates-can-be-beneficial">High refresh rates can be beneficial</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="XDeUGMueMJVqnUsJFc3wW6" name="LG-UltraGear-27GX790B-B--7" alt="LG-UltraGear-27GX790B-B" src="https://cdn.mos.cms.futurecdn.net/XDeUGMueMJVqnUsJFc3wW6.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>Not everyone chasing ultra-high refresh rates is doing it purely for bragging rights. I checked in with my colleague Brandon Hill, senior editor at Tom’s Hardware, and he’s a firm believer that high-refresh-rate monitors are a boon for gaming — so long as you have the hardware to push them and the personal drive to take advantage of them.</p><div><blockquote><p>“I prefer eye candy over insane refresh rates.”</p><p>Brandon Hill, senior editor at Tom’s Hardware</p></blockquote></div><p>He regularly games on a massive 49-inch 240Hz DQHD QD-OLED paired with an RTX 5090. Even with that kind of power, he often hovers around 180 FPS in Battlefield 6 while keeping the graphics settings high. “I prefer eye candy over insane refresh rates,” he told me.</p><p>The same thinking carries over to today’s dual-mode monitors. Brandon gets why the most hardcore esports players “would kill to eke out every possible frame to gain the upper hand online,” especially when you’re talking pixel response times in the 2ms range and super-low input lag. But he’s quick to admit he’s not in that camp. “I play for fun, not for competitive aspirations.”</p><div><blockquote><p>If I had the choice of running a monitor at 540 Hz at QHD versus 720 Hz at 720p, I'd choose the former every single time — and twice on Sundays.</p><p>Brandon Hill, Tom's Hardware</p></blockquote></div><p>Given the choice between 540Hz at crisp 1440p or 720Hz at 720p on something like the Sony Inzone M10S II, his pick is an easy one: “I’d choose the former every single time — and twice on Sundays.”</p><p>I agree with Brandon’s take here. While you certainly want games to run as smoothly as possible, it shouldn’t be at the expense of visual fidelity. My eyes scream whenever I switch to the LG UltraGear’s 720Hz mode since it’s locked to 720p resolution. And since I legit cannot tell or feel the difference with 720Hz gaming, sacrificing visuals really makes no sense.</p><h2 id="bragging-rights">Bragging rights?</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="vY8dJzHWXHpJ64JKHxCDUF" name="LG-UltraGear-27GX790B-B--16" alt="LG-UltraGear-27GX790B-B" src="https://cdn.mos.cms.futurecdn.net/vY8dJzHWXHpJ64JKHxCDUF.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>Dave James, Editor-in-Chief of Hardware at PC Gamer, has a similar perspective about the benefit of insane refresh rates on gaming monitors. They can surely be beneficial, but they do feel like companies flexing what their hardware can achieve.</p><div><blockquote><p>Beyond genuinely achievable frame rates, these extra high refresh rates become less about gaming and more about numbers on a spec sheet you can use for marketing.</p><p>Dave James, Editor-in-Chief of Hardware at PC Gamer</p></blockquote></div><p>Dave says it largely depends on who you are and what kind of games you play. For those of us who mostly enjoy single-player or co-op experiences, he argues that 144Hz is still a fantastic refresh rate, with 240Hz now a realistic and worthwhile target. He understands why competitive players want to chase the absolute highest refresh rates they can manage, but stresses that they only become relevant “if you have a system that can drive frame rates to match.” This is something that’s getting easier thanks to upscaling technologies.</p><p>When you can actually keep up with the monitor, Dave says playing a competitive shooter on a super-fast screen “almost becomes like looking through a window.”</p><p>That said, Dave is much more skeptical about the other end of the spectrum. Once you get to numbers like 720Hz that are extremely difficult to fully utilize, he believes it shifts away from actual benefit. “Beyond genuinely achievable frame rates, these extra high refresh rates become less about gaming and more about numbers on a spec sheet you can use for marketing and one-upping the competition,” Dave told me. “At this level, those numbers aren't for us gamers.”</p><p>This is where I fall on this topic. I find it very impressive that LG and others can achieve such lofty refresh rates on their respective gaming monitors. However, it’s hard to see how this benefits anyone but the most hardcore professional gamers.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XkG6aX"></div>                            </div>                            <script src="https://kwizly.com/embed/XkG6aX.js" async></script><h2 id="bottom-line-6">Bottom line</h2><p>After hearing Brandon and Dave’s thoughts and spending time with the LG UltraGear 27GX790B-B, my stance hasn’t changed much. These insanely high refresh rates are impressive, but they’re not essential for most gamers.</p><p>If you’re an esports competitor, monitors like this can give you a real edge. For everyone else? 144Hz or 240Hz at crisp resolution still delivers smooth gameplay and great picture quality without any sacrifice.</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/computing/laptops/acer-swift-16-ai-2026-review">The Acer Swift 16 AI’s touchpad is just too large</a></li><li><a href="https://www.tomsguide.com/gaming/handheld-gaming/panther-lake-handhelds-could-put-amd-on-notice-but-theres-a-big-hurdle-to-overcome">Panther Lake handhelds could put AMD on notice</a></li><li><a href="https://www.tomsguide.com/computing/laptops/buying-a-laptop-in-2026-is-complicated-heres-a-survival-guide-to-help-you-make-the-best-choice">Buying a laptop in 2026 is complicated</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Panther Lake handhelds could put AMD on notice, but there’s a big hurdle to overcome ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/handheld-gaming/panther-lake-handhelds-could-put-amd-on-notice-but-theres-a-big-hurdle-to-overcome</link>
                                                                            <description>
                            <![CDATA[ Rumors claim that Intel could unveil its reported Panther Lake handheld chips during Computex 2026. While that's exciting, there's one huge potential catch. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">EWdyJ5i8UTUKWnccq4TFmZ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/4aWYPNMcmmMtJjaUCQrdLh-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 22 Apr 2026 11:45:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Handheld Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/4aWYPNMcmmMtJjaUCQrdLh-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[MSI Claw 8 AI+ - Hero]]></media:description>                                                            <media:text><![CDATA[MSI Claw 8 AI+ - Hero]]></media:text>
                                <media:title type="plain"><![CDATA[MSI Claw 8 AI+ - Hero]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/4aWYPNMcmmMtJjaUCQrdLh-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Intel’s <a href="https://www.tomsguide.com/gaming/handheld-gaming/watch-out-amd-intels-arc-g3-and-arc-g3-extreme-handheld-chips-expected-for-computex-reveal">Arc G3 and Arc G3 Extreme </a>handheld chips are expected for a Computex reveal, and I couldn’t be more excited. AMD has dominated this space, with its processors powering the <a href="https://www.tomsguide.com/round-up/best-handheld-gaming-consoles">best handheld consoles</a> like the <a href="https://www.tomsguide.com/opinion/steam-deck-oled-is-the-must-buy-handheld-of-2023-and-the-perfect-holiday-gift-for-gamers">Steam Deck OLED</a>, <a href="https://www.tomsguide.com/reviews/asus-rog-ally">Asus ROG Ally</a>, <a href="https://www.tomsguide.com/gaming/handheld-gaming/lenovo-legion-go-2-review">Lenovo Legion Go 2</a>, and more. While handhelds like the <a href="https://www.tomsguide.com/gaming/handheld-gaming/msi-claw-8-ai-plus-review">MSI Claw 8 AI+</a> have used Intel chips, they’re still behind their AMD-powered counterparts. But with Panther Lake-driven handhelds, we could finally see the balance of power shift.</p><p>I’ve tested many Panther Lake laptops, including the <a href="https://www.tomsguide.com/computing/laptops/dell-xps-14-2026-review">Dell XPS 14</a>, <a href="https://www.tomsguide.com/computing/laptops/samsung-galaxy-book-6-pro-review">Samsung Galaxy Book 6 Pro</a>, and <a href="https://www.tomsguide.com/computing/laptops/msi-prestige-14-flip-ai-review">MSI Prestige 14 Flip AI+</a>, and I’ve never failed to be impressed by their gaming performance—especially since these aren’t gaming machines. That experience has led me to wonder what Panther Lake could do for handhelds. If the leap between Intel Core Ultra Series 1 and Series 2 in handhelds is any indication, Series 3 should deliver significant performance and efficiency gains.</p><p>Nothing is official yet, but since Intel already announced custom chips for handhelds are coming, it’s not unreasonable to expect we’ll hear something soon, especially with Computex just around the corner. While the prospect of Panther Lake handhelds is exciting, there is one thing that concerns me.</p><h2 id="panther-lake-power">Panther Lake power</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="VurWWtGVgPihK6JFckWoYA" name="Intel Panther Lake" alt="Intel Panther Lake" src="https://cdn.mos.cms.futurecdn.net/VurWWtGVgPihK6JFckWoYA.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>To be fair, there will be performance differences between a laptop and a gaming handheld. While both prioritize energy efficiency, handhelds have to nail it so folks can play games for more than a few minutes. I wanted to make that clear before moving on, as I’m not expecting a 1:1 experience from a Panther Lake handheld. That said, my experience with laptops running Intel’s latest chipsets sets expectations for what we could see.</p><p>The three laptops I mentioned in the intro all have the Intel Core Ultra X7 358H CPU, an upper-mid-range chip in the Panther Lake lineup. In our gaming performance test, which uses the built-in benchmark tool with the game’s graphics settings set to high and the resolution set to 1080p, we recorded impressive results across the games we tested.</p><div ><table><caption>Gaming performance @ 1080p (XeSS enabled)</caption><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>MSI Prestige 14 Flip AI+</strong></p></th><th  ><p><strong>Dell XPS 14 (2026)</strong></p></th><th  ><p><strong>Samsung Galaxy Book 6 Pro</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Cyberpunk 2077</strong></p></td><td  ><p>37 fps</p></td><td  ><p>60 fps</p></td><td  ><p>80 fps</p></td></tr><tr><td class="firstcol " ><p><strong>Shadow of the Tomb Raider</strong></p></td><td  ><p>65 fps</p></td><td  ><p>78 fps</p></td><td  ><p>107 fps</p></td></tr><tr><td class="firstcol " ><p><strong>Total War: Warhammer III</strong></p></td><td  ><p>29 fps</p></td><td  ><p>42 fps</p></td><td  ><p>48</p></td></tr></tbody></table></div><p>The key here is that we enabled Intel XeSS 3.0, which is the company’s version of the upscaling tech Nvidia and AMD use to boost performance. For example, Cyberpunk 2077’s performance went from an abysmal 19 frames per second to a comparatively ultra-smooth 80 fps on the Galaxy Book 6 Pro. XeSS, like Nvidia DLSS and AMD FSR, is a literal game-changer and is vital for smoother performance.</p><p>Rumors suggest that the Panther Lake handheld chips are stripped-down versions of the Intel Core Ultra X7 358H, with fewer P-cores to improve power management. This makes sense for the reason I stated at the start of this section — you don’t want a chip that’s so powerful it drains the battery too quickly.</p><p>If the rumored Arc G3 and Arc G3 Extreme chips can match the performance we’ve seen in Panther Lake laptops, handhelds are about to get a whole lot more interesting.</p><h2 id="intel-arc-g3-chips">Intel Arc G3 chips</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="gcvvryaccM9BNNoKqC3Ape" name="Intel Panther Lake" alt="Intel Panther Lake" src="https://cdn.mos.cms.futurecdn.net/gcvvryaccM9BNNoKqC3Ape.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>Speaking of the Arc G3 chips, here’s what we’ve heard so far. According to <a href="https://videocardz.com/newz/intel-arc-g3-and-arc-g3-extreme-handhelds-expected-to-debut-at-computex" target="_blank">VideoCardz</a>, Intel could debut two handheld chips at Computex 2026. The Arc G3 and Arc G3 Extreme are reportedly tied to a Q2 2026 window and are expected to have a lifecycle through Q2 2027.</p><p>On X, a leaker named <a href="https://x.com/9550pro/status/2046044166535405947" target="_blank">@9550Pro</a> posted what is reportedly a CPU-Z screenshot of the Intel Core G3 Extreme (via <a href="https://www.notebookcheck.net/Arc-G3-Extreme-and-Arc-G3-slated-to-arrive-as-Intel-s-newest-handheld-console-chips.1278203.0.html" target="_blank">Notebookcheck</a>). However, another insider, <a href="https://x.com/jaykihn0/status/2046069426059903043" target="_blank">Jaykihn,</a> claims the listing is false and that the Core G3 Extreme will be renamed the Intel Arc G3 Extreme. Regardless, the chip appears to be a stripped-down version of the Intel Core Ultra X7 358H, as I mentioned earlier.</p><p>According to VideoCardz, the chips have reportedly undergone internal testing, and MSI and OneXPlayer are expected to be the first to use Intel’s handheld processor. MSI is a logical choice, as the company has used Intel chips in its MSI Claw handhelds. There’s no evidence that Asus or Lenovo will update their handhelds with Intel’s chip, but it’s not out of the realm of possibility.</p><h2 id="the-big-catch">The big catch</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:986px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="zNviMu5gMGfq9wfeskjxXG" name="uUbdizcsnwBrWE7pkxThXE" alt="A man counting money by hand" src="https://cdn.mos.cms.futurecdn.net/zNviMu5gMGfq9wfeskjxXG.jpg" mos="" align="middle" fullscreen="" width="986" height="555" 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 I’m certainly looking forward to handhelds powered by Intel’s Panther Lake chip, that enthusiasm is tempered by the issue that’s plagued consumer tech since late last year. Thanks to <a href="https://www.tomsguide.com/computing/ram-price-crisis-2026-everything-you-need-to-know" target="_blank">RAMageddon</a>, handheld gaming prices are out of control.</p><p>The most extreme example of handheld price hikes is the <a href="https://www.tomsguide.com/gaming/handheld-gaming/lenovo-legion-go-2-review" target="_blank">Legion Go 2</a> with 2TB of storage, <a href="https://videocardz.com/newz/lenovo-raises-legion-go-2-z2-extreme-2tb-price-to-2849-99-on-official-store" target="_blank">which now costs $2,849</a> (up from $1,479). The original asking price was already steep, but paying nearly $3,000 for a gaming handheld is wild, given that most of these devices used to hover around $600-$900. Those days are very much over.</p><p>Given these conditions, I’m scared to even think about how much any handheld with an Intel Panther Lake chip will cost. I doubt a Legion Go 2 variant with these chips would have radically different pricing. Maybe it costs less, maybe a little more, but either way, we have a good (or bad) idea of what to expect in terms of cost.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-eJ7pyW"></div>                            </div>                            <script src="https://kwizly.com/embed/eJ7pyW.js" async></script><h2 id="outlook-7">Outlook</h2><p>With no official word on Panther Lake handhelds, we’ll have to wait for Intel to finally reveal what it has cooking. As I said, with Computex starting on June 2, it might not be long before we get to see something.</p><p>We should also keep in mind that the AMD Ryzen Z2 and Z2 Extreme are out there to ensure Intel doesn’t have an easy time of it. And this is perhaps wishful thinking on my part, but it would also be interesting if Qualcomm decided to put its Snapdragon X2 chips in handhelds.</p><p>Regardless, the handheld market should experience a significant shake-up sooner rather than later. Can Intel gain a firm foothold in this space? We’ll just have to wait and see.</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/computing/microsofts-new-surface-laptop-could-pack-an-oled-panel-but-how-much-will-it-cost">Microsoft’s new Surface Laptop could pack an OLED panel</a></li><li><a href="https://www.tomsguide.com/computing/laptops/buying-a-laptop-in-2026-is-complicated-heres-a-survival-guide-to-help-you-make-the-best-choice">Buying a laptop in 2026 is complicated — here's a survival guide</a></li><li><a href="https://www.tomsguide.com/computing/peripherals/i-just-tested-this-keyboard-thats-also-a-windows-computer-and-its-like-a-modern-commodore-64">I just tested this keyboard that’s also a Windows computer</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Watch out, AMD — Intel’s Arc G3 and Arc G3 Extreme handheld chips expected for Computex reveal ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/gaming/handheld-gaming/watch-out-amd-intels-arc-g3-and-arc-g3-extreme-handheld-chips-expected-for-computex-reveal</link>
                                                                            <description>
                            <![CDATA[ A new report from VideoCardz claims that Intel will officially announce its Arc G3 and Arc G3 Extreme handheld chips during Computex 2026. Here's what we know. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">zYY6Jr37iARBEd6kNn96Mc</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/qU9Pz7F6SVcowAMfZJSkZK-1280-80.png" type="image/png" length="0"></enclosure>
                                                                        <pubDate>Mon, 20 Apr 2026 15:21:52 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Handheld Gaming]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/qU9Pz7F6SVcowAMfZJSkZK-1280-80.png">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[MSI Claw 8AI+ - Playing Cyberpunk 2077]]></media:description>                                                            <media:text><![CDATA[MSI Claw 8AI+ - Playing Cyberpunk 2077]]></media:text>
                                <media:title type="plain"><![CDATA[MSI Claw 8AI+ - Playing Cyberpunk 2077]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/qU9Pz7F6SVcowAMfZJSkZK-1280-80.png" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Intel could debut two handheld chips at Computex 2026. That’s according to <a href="https://videocardz.com/newz/intel-arc-g3-and-arc-g3-extreme-handhelds-expected-to-debut-at-computex" target="_blank">VideoCardz</a>, which obtained information about a possible announcement at this year’s big Taipei-based tech conference.</p><p>It appears the chips in question will be called Arc G3 and Arc G3 Extreme—with the former presumably being the base model and the latter being the more powerful version. VideoCardz says the chips are tied to a Q2 2026 window and are expected to have a lifecycle through Q2 2027. If that’s accurate, then a Computex 2026 reveal makes sense.</p><p>An X leaker named <a href="https://x.com/9550pro/status/2046044166535405947" target="_blank">@9550Pro</a> posted what is reportedly a CPU-Z screenshot of what could be the Intel Core G3 Extreme (via <a href="https://www.notebookcheck.net/Arc-G3-Extreme-and-Arc-G3-slated-to-arrive-as-Intel-s-newest-handheld-console-chips.1278203.0.html" target="_blank">Notebookcheck</a>). Earlier leaks claim this chip has 14 CPU cores total, including two P-cores, eight E-cores, and four LPE-cores. That said, another notable insider, <a href="https://x.com/jaykihn0/status/2046069426059903043" target="_blank">Jaykihn</a>, claims the listing is fake and that the Core G3 Extreme will be called the Intel Arc G3 Extreme. Regardless, the chip appears to be a stripped-down version of the Intel Core Ultra X7 358H chip we recently tested in the <a href="https://www.tomsguide.com/computing/laptops/i-played-on-the-kojima-edition-asus-rog-flow-z13-and-this-2-in-1-gaming-tablet-belongs-in-a-museum">Kojima Edition of the Asus ROG Flow Z13</a>.</p><p>VideoCardz says that the chips have already undergone internal testing and that MSI and OneXPlayer are expected to be the first to use Intel’s handheld chip. MSI certainly makes sense, as the company used Intel chips for its <a href="https://www.tomsguide.com/gaming/handheld-gaming/i-finally-tried-the-msi-claw-8-ai-and-it-makes-other-handheld-gaming-pcs-look-boring">MSI Claw</a> handhelds. Right now, there is no evidence that Asus or Lenovo is joining the Arc G3 party. However, the likes of Acer and Microsoft might, as their respective logos appeared during Intel’s “handhelds unleashed” reveal at this year’s CES.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OLQKgX"></div>                            </div>                            <script src="https://kwizly.com/embed/OLQKgX.js" async></script><p>As always, take this news with a grain of salt as these chips haven’t officially been announced. That said, given how Intel had a dedicated talk about handhelds during CES, it’s a safe bet we’ll hear more soon—whether at Computex or elsewhere.</p><p>We’ll keep an eye on this story and hope that any potential handhelds featuring these chips aren’t insanely expensive. Stay tuned!</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/computing/microsofts-new-surface-laptop-could-pack-an-oled-panel-but-how-much-will-it-cost">Microsoft’s new Surface Laptop could pack an OLED panel</a></li><li><a href="https://www.tomsguide.com/computing/laptops/buying-a-laptop-in-2026-is-complicated-heres-a-survival-guide-to-help-you-make-the-best-choice">Buying a laptop in 2026 is complicated — here's a survival guide</a></li><li><a href="https://www.tomsguide.com/computing/peripherals/i-just-tested-this-keyboard-thats-also-a-windows-computer-and-its-like-a-modern-commodore-64">I just tested this keyboard that’s also a Windows computer</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tried the Minisforum G1 Pro and this console-sized mini PC works just as well in the living room as it does at your desk  ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/desktop-computers/mini-pcs/minisforum-g1-pro-review</link>
                                                                            <description>
                            <![CDATA[ The Minisforum G1 Pro might resemble a PS5 but this mini gaming PC is packed with power and almost fully upgradeable. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">WqRq4TYQjKFZ5dcgZ7cBuP</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/5besxxjRfLc7CvG5UjqGtG-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 18 Apr 2026 10:15:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Mini PCs]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Desktop Computers]]></category>
                                                                                                <author><![CDATA[ anthony.spadafora@futurenet.com (Anthony Spadafora) ]]></author>                    <dc:creator><![CDATA[ Anthony Spadafora ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/z73LEoj7FkUjNG85GcWHtH.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Anthony Spadafora is the managing editor for security and home office furniture at Tom’s Guide where he covers everything from data breaches and malware to password managers and the best way to cover your whole home or business with a strong Wi-Fi signal.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Before joining the team, he spent three years covering cybersecurity and B2B tech for ITProPortal while living in South Korea. After moving back to the US. Anthony joined the TechRadar Pro team where he covered these topics along with VPNs, web hosting, online collaboration software and video conferencing for four years. Anthony also has his ears to the ground and is on the lookout for the next major cyberattack or data breach.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Based in Houston, Texas, Anthony also handles VPN testing for both Tom’s Guide and TechRadar. As someone who has worked from home exclusively since 2018, he has reviewed dozens of standing desks as well as office chairs and has taken a closer look at other essential remote working accessories. As part of these reviews, Anthony frequently builds intricate desk setups which is why he’s such a big advocate for cable management and keeping things organized. When he’s not writing, he can be found tinkering with PCs and game consoles, managing cables and making upgrades to his smart home.&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/5besxxjRfLc7CvG5UjqGtG-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Minisforum G1 Pro next to a PS5 Pro on a table]]></media:description>                                                            <media:text><![CDATA[The Minisforum G1 Pro next to a PS5 Pro on a table]]></media:text>
                                <media:title type="plain"><![CDATA[The Minisforum G1 Pro next to a PS5 Pro on a table]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/5besxxjRfLc7CvG5UjqGtG-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Minisforum G1 Pro isn’t your typical mini PC. Instead, it feels like a true small form factor (SFF) rig thanks to its internal, desktop-grade power supply and its dedicated GPU. We aren’t dealing with a power-limited laptop chip here; instead, you’re getting a low-profile Nvidia GeForce RTX 5060.</p><p>After seeing the <a href="https://www.tomsguide.com/computing/desktop-computers/i-didnt-expect-this-mini-pc-that-looks-like-a-ps5-to-be-this-powerful-or-customizable-and-now-i-cant-wait-to-try-it-out">G1 Pro at Computex</a> last summer, I knew I had to get one in for testing. I’ve been using it for both work and play for almost two months now, and it hasn’t disappointed on either front. With an AMD Ryzen 9 8945HX processor and 32GB of DDR5 RAM under the hood, the G1 Pro handled my daily workload with ease. Then, when work was done for the day, it transformed into a console-like gaming powerhouse capable of playing the latest AAA releases with the settings cranked.</p><p>Still, at $1,439, the G1 Pro is more expensive than your average mini PC — though it’s still significantly cheaper than the Asus ROG NUC. There are also some trade-offs to consider: its small footprint means a sparse port selection for accessories, and the G1 Pro can get loud when you push its hardware to the limit.</p><p>My Minisforum G1 Pro review will help you decide if this is the <a href="https://www.tomsguide.com/us/best-mini-pc.html">best mini PC</a> for your setup and if it really packs enough of a punch to make you consider ditching your console for good.</p><h3 class="article-body__section" id="section-minisforum-g1-pro-cheat-sheet"><span>Minisforum G1 Pro: Cheat Sheet</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="ydb5Cr6zFJBeAzSK7KkKHM" name="Minisforum G1 Pro-5" alt="The Minisforum G1 Pro unboxed on a table" src="https://cdn.mos.cms.futurecdn.net/ydb5Cr6zFJBeAzSK7KkKHM.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><ul><li><strong>What is it? </strong>A gaming-focused mini PC with a desktop-grade power supply and GPU.</li><li><strong>Who is it for? </strong>Gamers who don’t have the space for a full tower, those who like to travel with their gaming PC and people who want workstation power in a small form factor with the option to play demanding games too.</li><li><strong>What does it cost? </strong>The Minisform G1 Pro costs $1,439 at <a href="https://store.minisforum.com/products/minisforum-g1-pro-gaming-pc" target="_blank" rel="nofollow">Minisforum</a> and <a href="https://www.amazon.com/MINISFORUM-PCIe4-0-Desktop-Computer-Graphics/dp/B0GLYNP4DK" target="_blank" rel="nofollow">Amazon</a>.</li><li><strong>What do we like? </strong>Its console-like design, the fact that it uses desktop-grade components, that you can swap in more RAM or storage, how there’s no bulky power brick and that you can even upgrade its GPU.</li><li><strong>What don’t we like? </strong>The form factor limits port availability and it can get loud when playing demanding games cranked up to max settings.</li></ul><h3 class="article-body__section" id="section-minisforum-g1-pro-specs"><span>Minisforum G1 Pro: Specs</span></h3><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p>$1,439</p></td></tr><tr><td class="firstcol " ><p><strong>CPU</strong></p></td><td  ><p>AMD Ryzen 9 8945HX</p></td></tr><tr><td class="firstcol " ><p><strong>GPU</strong></p></td><td  ><p>Nvidia RTX 5060 8GB, AMD Radeon G10M</p></td></tr><tr><td class="firstcol " ><p><strong>RAM</strong></p></td><td  ><p>32GB DDR5 (supports up to 96GB)</p></td></tr><tr><td class="firstcol " ><p><strong>Storage</strong></p></td><td  ><p>1TB M.2 2280 PCIe 4.0 SSD (expandable up to 8TB)</p></td></tr><tr><td class="firstcol " ><p><strong>OS</strong></p></td><td  ><p>Windows 11</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>1x USB-A, 1 x USB-C, 3.5 audio jack (front), 2 x USB-A, 1 x USB-C, 2 x DisplayPort 2.1, 1 x DisplayPort 1.4a,  2 x HDMI 2.1, 1 x 5 Gigabit Ethernet (rear)</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Wi-Fi 7, Bluetooth 5.4</p></td></tr><tr><td class="firstcol " ><p><strong>Size</strong></p></td><td  ><p>12.4 x 8.5 x 2.25 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>8.3 pounds</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-minisforum-g1-pro-the-ups"><span>Minisforum G1 Pro: The Ups</span></h3><p>The Minisforum G1 Pro is far from your standard mini PC. However, its powerful components and upgradability make it just as useful in your living room as it is in the office.</p><h2 id="even-sleeker-than-a-console">Even sleeker than a console</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="5besxxjRfLc7CvG5UjqGtG" name="Minisforum G1 Pro-6" alt="The Minisforum G1 Pro next to a PS5 Pro on a table" src="https://cdn.mos.cms.futurecdn.net/5besxxjRfLc7CvG5UjqGtG.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 12.4 x 8.5 x 2.25 inches with a white outer shell, it’s hard not to draw comparisons between the G1 Pro and Sony’s PS5. Personally, though, I prefer Minisforum’s more uniform design. On the left side of the G1 Pro’s case, there are two triangular sets of vent holes while the right side is completely flat.</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="aGCHRZ67iAmZHgij9cFSWR" name="Minisforum G1 Pro-2" alt="The Minisforum G1 Pro lying flat on a table showing off its front ports" src="https://cdn.mos.cms.futurecdn.net/aGCHRZ67iAmZHgij9cFSWR.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>A black strip runs between the two sides and on the front, there’s a high-speed USB-A port, a USB-C port (that can do video out), a 3.5mm audio jack and the power button. There are also customizable RGB lightstrips on either side of the G1 Pro’s front ports.</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="JKok389oGEc7RfvJp87f3U" name="Minisforum G1 Pro-4" alt="The rear ports of the Minisforum G1 Pro" src="https://cdn.mos.cms.futurecdn.net/JKok389oGEc7RfvJp87f3U.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>Now around back is where things get interesting. In the center, you get two more high-speed USB-A ports, another USB-C port (that can also do video out), an HDMI 2.1 port and surprisingly, a 5 Gigabit Ethernet port. Then on the left side, you get another HDMI 2.1 port, two DisplayPort 2.1b connections and a DisplayPort 1.4a one too from the G1 Pro’s dedicated GPU. Finally, there’s a standard PC power port along with an on/off switch on the right side.</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="8ssgY2G2txxTTZjMKro85Y" name="Minisforum G1 Pro-7" alt="A person installing the Minisforum G1 Pro's vertical stand" src="https://cdn.mos.cms.futurecdn.net/8ssgY2G2txxTTZjMKro85Y.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>Unlike with the PS5, the G1 Pro comes with a vertical stand in the box. It screws onto the bottom of the device using a thumb screw for additional support. While you can technically use the G1 Pro horizontally too, doing so is a bit awkward because when you flip it over to have its vents facing up, the Minisforum and AtomMan logos are upside down. Now if you were to mount it under your desk horizontally, this wouldn’t be the case and the device would still have plenty of airflow.</p><p>Just like with my PS5 Pro or Xbox Series X, one of my favorite things about the G1 Pro is that it doesn’t have a bulky power supply like the <a href="https://www.tomsguide.com/computing/desktop-computers/mini-pcs/geekom-a9-max-review">Geekom A9 Max</a> and many of the other mini PCs I’ve tested. In fact, the only other mini PC I’ve tried that uses an internal power supply is Apple’s <a href="https://www.tomsguide.com/computing/desktop-computers/mac-mini-m4-review">Mac mini M4</a>.</p><p>Since standard PC power cables are incredibly cheap, I plugged one in at my desk and had another in the entertainment center under my TV. That way, when I did want to play some of the <a href="https://www.tomsguide.com/best-picks/best-PC-games">best PC games</a> on a large screen, I could just move the G1 Pro into my living room.</p><h2 id="console-aesthetic-workstation-performance">Console aesthetic, workstation performance</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="ZtKL7DXtMnnhzFTuTxaJva" name="Minisforum G1 Pro-9" alt="The Minisforum G1 Pro on a desk" src="https://cdn.mos.cms.futurecdn.net/ZtKL7DXtMnnhzFTuTxaJva.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 G1 Pro may have a more gamer-friendly aesthetic but unlike the <a href="https://www.tomsguide.com/computing/desktop-computers/atomman-g7-pt">AtomMan G7 PT</a>, it won’t look out of place in an office setting. Sure, its white shell and unique design will draw attention but not the unwanted kind.</p><p>While the G1 Pro may be marketed as a mini gaming PC first and foremost, it’s a surprisingly capable work machine too. A big reason for this is because of its upgradeability. For instance, while my review unit shipped with 32GB of DDR5 RAM, you can actually put up to 96GB of RAM in its small case — but more on that later.</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="tW7rxiZJc4tUkP8DdZhMyd" name="Minisforum G1 Pro-10" alt="A desk setup built around the Minisforum G1 Pro" src="https://cdn.mos.cms.futurecdn.net/tW7rxiZJc4tUkP8DdZhMyd.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>In terms of my daily workload which consists of dozens of Chrome tabs opened simultaneously and editing images in GIMP, the G1 Pro never missed a beat. It handled everything I threw at it with ease with plenty of power left over for more demanding tasks.</p><div ><table><caption>Performance Benchmarks</caption><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>Minisforum G1 Pro</strong></p></th><th  ><p><strong>Geekom A9 Max</strong></p></th><th  ><p><strong>Framework Desktop</strong></p></th><th  ><p><strong>AtomMan G7 Ti</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Geekbench 6.5 single-core</strong></p></td><td  ><p>2806</p></td><td  ><p>2976</p></td><td  ><p>2966</p></td><td  ><p>2864</p></td></tr><tr><td class="firstcol " ><p><strong>Geekbench 6.5 multi-core</strong></p></td><td  ><p>11612</p></td><td  ><p>15140</p></td><td  ><p>17574</p></td><td  ><p>15651</p></td></tr><tr><td class="firstcol " ><p><strong>25GB file copy test (MBps)</strong></p></td><td  ><p>1659.65</p></td><td  ><p>1749.79</p></td><td  ><p>2976.46</p></td><td  ><p>1445.75</p></td></tr><tr><td class="firstcol " ><p><strong>Handbrake (Mins:Secs)</strong></p></td><td  ><p>3:12</p></td><td  ><p>3:25</p></td><td  ><p>2:43</p></td><td  ><p>3:50</p></td></tr></tbody></table></div><p>In the table above, you can see how well the G1 Pro fared compared to the competition. It held its own in Geekbench’s single-core tests in our lab, but its multi-core results weren’t nearly as high as those from the A9 Max, <a href="https://www.tomsguide.com/computing/mini-pcs/framework-desktop-review">Framework Desktop</a> and even the Intel-powered <a href="https://www.tomsguide.com/computing/desktop-computers/atomman-g7-ti-review">AtomMan G7 Ti</a>. Still, when transcoding a 4K video to 1080p in our Handbrake test, the G1 Pro finished the task in just over three minutes.</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:3217px;"><p class="vanilla-image-block" style="padding-top:56.23%;"><img id="5PcKnRz4dL4UhrWBsgoUPh" name="minisforum-g1-pro-speed-test" alt="The results of a Wi-Fi speed test run on the Minisforum G1 Pro" src="https://cdn.mos.cms.futurecdn.net/5PcKnRz4dL4UhrWBsgoUPh.jpg" mos="" align="middle" fullscreen="" width="3217" height="1809" 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>Another area where the G1 Pro really excels is with connectivity. In addition to Bluetooth 5.4, you also get full <a href="https://www.tomsguide.com/reference/wi-fi-7-explained">Wi-Fi 7</a> support. When connected to one of the <a href="https://www.tomsguide.com/best-picks/best-Wi-fi-7-routers">best Wi-Fi 7 routers</a> in the other room and running a speed test, I saw download speeds of 1.5 Gbps which is quite fast over Wi-Fi. Then again, if you have a real need for speed, you can always use an Ethernet cable to connect the G1 Pro directly to your router using the 5 Gigabit Ethernet port around back.</p><p>The biggest difference between the G1 Pro and the rest of these mini PCs though is in gaming performance, especially since it’s the only one with a dedicated, desktop-grade GPU.</p><h2 id="not-your-average-mini-pc-gpu">Not your average mini PC GPU</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="4HPmHESfNxQA8eBusjAyck" name="Minisforum G1 Pro-12" alt="A person playing Ratchet & Clank: Rift Apart on the Minisforum G1 Pro" src="https://cdn.mos.cms.futurecdn.net/4HPmHESfNxQA8eBusjAyck.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>Typically when gaming on a mini PC, you’re relegated to using either integrated graphics or a discrete laptop-style GPU. The latter is obviously better but with the G1 Pro, you don’t have to settle for either of these lesser options. Instead, you have the power of a discrete, desktop-grade Nvidia RTX 5060 GPU at your disposal.</p><p>The G1 Pro is mainly designed for playing games at 1440p. However, as I had it hooked up to a 4K gaming monitor, I leveraged <a href="https://www.tomsguide.com/computing/gaming-laptops/i-just-experienced-dlss-4-and-now-i-can-never-go-back-heres-why">Nvidia DLSS 4</a> — and then later <a href="https://www.tomsguide.com/computing/gpus/i-went-eyes-on-with-nvidias-dlss-4-5-dynamic-multi-frame-generation-launching-march-31-and-its-a-game-changer">DLSS 4.5</a> — to bump up the framerate in more demanding games.</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="g9F3QatvNDTJetdfLqDyYo" name="Minisforum G1 Pro-13" alt="A person playing Death Stranding 2 on the Minisforum G1 Pro" src="https://cdn.mos.cms.futurecdn.net/g9F3QatvNDTJetdfLqDyYo.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>With Super Resolution enabled, <a href="https://www.tomsguide.com/gaming/death-stranding-2-is-the-most-beautiful-game-ive-ever-played-and-its-everything-id-hope-for-in-a-sequel">Death Stranding 2</a> ran like a charm on this smaller, console-sized mini PC. I also played through a bit of <a href="https://www.tomsguide.com/reviews/ratchet-and-clank-rift-apart">Ratchet & Clank: Rift Apart</a> with DLSS enabled for equally impressive results. As it’s still in development, I even ran the demo for the upcoming skateboarding sim <a href="https://www.tomsguide.com/computing/mini-pcs/i-gave-my-favorite-pocketable-mini-pc-an-instant-upgrade-with-this-docking-station-and-now-its-a-full-fledged-gaming-rig">Skate Style</a> natively and even at 4K, it looked and ran great.</p><div ><table><caption>Gaming Benchmarks (in FPS, @ 1080p)</caption><thead><tr><th class="firstcol empty" ></th><th  ><p>Minisforum G1 Pro</p></th><th  ><p>Framework Desktop</p></th><th  ><p>AtomMan G7 Ti</p></th><th  ><p>AtomMan G7 PT</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Metro Exodus</strong></p></td><td  ><p>51.45</p></td><td  ><p>56.56</p></td><td  ><p>91.63</p></td><td  ><p>86.12</p></td></tr><tr><td class="firstcol " ><p><strong>Cyberpunk 2077</strong></p></td><td  ><p>45.21</p></td><td  ><p>22.09</p></td><td  ><p>39.90</p></td><td  ><p>21.35</p></td></tr><tr><td class="firstcol " ><p><strong>Red Dead Redemption 2</strong></p></td><td  ><p>90.66</p></td><td  ><p>56.57</p></td><td  ><p>73</p></td><td  ><p>58.78</p></td></tr></tbody></table></div><p>In our lab tests, the G1 Pro performed well across the board without DLSS enabled. We saw 90 fps in <a href="https://www.tomsguide.com/us/red-dead-redemption-2,review-5905.html">Red Dead Redemption 2</a> at 1080p, while <a href="https://www.tomsguide.com/reviews/cyberpunk-2077-phantom-liberty">Cyberpunk 2077</a> saw a less than ideal but still playable 45 fps at native resolution. With DLSS and upscaling enabled, though, you can easily push past 60 fps in the most demanding AAA titles.</p><p>Having a desktop-grade Nvidia RTX 5060 installed from the get-go is one of the most compelling things about the G1 Pro. However, just like its RAM and storage, you can actually swap out your GPU later on if you need even more power.</p><h2 id="small-but-surprisingly-expandable">Small but surprisingly expandable</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="2FHnzfvzYG4smrLZ6b6N75" name="Minisforum G1 Pro-14" alt="The Minisforum G1 Pro open on a table with its lid visible" src="https://cdn.mos.cms.futurecdn.net/2FHnzfvzYG4smrLZ6b6N75.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>Opening up the G1 Pro to make upgrades is surprisingly simple. After removing the vertical stand and two screws on the base of the machine, the vented side panel just slides right off.</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="zfwjqYUMCVUWV7S7skuLr8" name="Minisforum G1 Pro-15" alt="The Minisforum G1 Pro open on a table" src="https://cdn.mos.cms.futurecdn.net/zfwjqYUMCVUWV7S7skuLr8.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>Doing so lets you see the Nvidia RTX 5060 from Gigabyte on the left, a large blower-style fan above the CPU in the center and the 350W power supply on the right. Despite the G1 Pro’s smaller size, Minisforum managed to pack a lot of powerful components into this case with well-managed cables to boot.</p><p>Now you can add more memory or storage, but doing so requires unplugging the power supply’s main connector and removing the CPU fan. While one of the M.2 SSD slots is occupied with a 1TB drive, there’s a free one next to it. In total, you can add up to 8TB of storage with a 4TB SSD in each slot. Minisforum even includes an extra SSD heatsink in the box, which is a nice touch for those adding a second high-speed drive.</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="FTWhofRTgocWsSvY42pApB" name="Minisforum G1 Pro-16" alt="A close up shot of the Minisforum G1 Pro's internals" src="https://cdn.mos.cms.futurecdn.net/FTWhofRTgocWsSvY42pApB.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>Although you can’t see it here, there’s a single stick of 32GB DDR5 RAM underneath the CPU cooler. However, there’s a second, free slot next to it. Once <a href="https://www.tomsguide.com/computing/ram-price-crisis-2026-everything-you-need-to-know">RAMaggedon</a> is behind us, you could utilize both to configure the G1 Pro with a whopping 96GB of memory.</p><p>A quick note on the single-channel RAM configuration my review unit shipped with: running a PC in single-channel mode does lead to a bottleneck, which is likely why those Geekbench multi-core scores from earlier were lower than expected. However, if you do decide to upgrade the G1 Pro’s RAM, you can just add another 32GB stick; if you had two 16GB sticks, you’d have to ditch them entirely to reach 64GB or more.</p><p>Though 96GB of RAM will definitely be overkill for most, if you’re using this mini PC for 8K video editing or running LLMs locally, it’s nice to know that you have plenty of room to expand in the future. Speaking of which, since the G1 Pro uses a standard GPU — albeit a low-profile one — you could theoretically swap out the included RTX 5060 with an RTX 6060 once Nvidia’s next-gen GPUs hit the market.</p><h3 class="article-body__section" id="section-minisforum-g1-pro-the-downs"><span>Minisforum G1 Pro: The Downs</span></h3><p>The Minisforum G1 Pro is truly a remarkable mini PC that breaks new ground. However, it’s not without its downsides, which include a sparse port selection for your accessories and fans that can get quite noisy when running demanding workloads or graphically-intensive games.</p><h2 id="port-shortage-but-not-for-video">Port shortage (but not for video)</h2><p>Just like with the AtomMan G7 Ti, I wish the G1 Pro had a few more USB-A ports. Since I switch between computers so much, I prefer using a 2.4 GHz USB dongle for my mouse and keyboard as opposed to Bluetooth. This lets me quickly get up and running when setting up a new PC.</p><p>You do get three USB-A ports — one on the front and two on the back — with the G1 Pro. However, since I have a pair of <a href="https://www.tomsguide.com/audio/speakers/kanto-ora">Kanto Ora</a> bookshelf speakers hooked up via USB along with the dongles for my mouse and keyboard, I found myself at a loss when I wanted to plug in the dongle for a controller. One more USB-A port to get the total up to four would have been a nice addition here.</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="5Gr9uV3a9QGvpzUvJCgdXF" name="Minisforum G1 Pro-3" alt="The rear video out ports from the GPU on the Minisforum G1 Pro" src="https://cdn.mos.cms.futurecdn.net/5Gr9uV3a9QGvpzUvJCgdXF.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>While you don’t get quite as many USB-A ports as you do on a machine like the Geekom A9 Max, you do get loads of video out ports. Both the front and back USB-C ports are capable of video out, but the G1 Pro also features two HDMI 2.1 ports and two DisplayPort connections. </p><p>If you want to run a multi-monitor setup, the G1 Pro is more than capable of doing so with ease. However, if you have a lot of older accessories that use USB-A, then you’ll likely need to pair this mini PC with a hub to get all the ports you need.</p><h2 id="the-beast-unleashed">The beast unleashed</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="8o7vER3qxPHWuZuPurYecJ" name="Minisforum G1 Pro-8" alt="An overhead shot of the Minisforum G1 Pro showing off its top exhaust" src="https://cdn.mos.cms.futurecdn.net/8o7vER3qxPHWuZuPurYecJ.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>Let’s face it: mini PCs can get noisy due to their smaller size, and the G1 Pro certainly suffers from this, but only when pushing the machine with demanding games or intensive workloads. With my sound meter, I measured 40dB when using this mini PC for work which is roughly as loud as a quiet library. However, when I booted up a resource-intensive game like Death Stranding 2, I saw sound levels reach as high as 60dB.</p><p>Although 60dB is quite loud if you have the G1 Pro sitting right next to you on a desk, switching to a pair of <a href="https://www.tomsguide.com/audio/headphones/apples-cheapest-accessory-helped-me-get-through-a-13-hour-flight-this-is-a-life-saver">wired USB-C headphones</a> did the trick and made that extra fan noise a lot less noticeable. One of the <a href="https://www.tomsguide.com/best-picks/best-gaming-headsets">best gaming headsets</a> would have worked just as well.</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:2850px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="qQyHmZtBviGnHxmTfDSn8N" name="minisforum-app" alt="A screenshot showing off the included software for tweaking the performance of the Minisforum G1 Pro" src="https://cdn.mos.cms.futurecdn.net/qQyHmZtBviGnHxmTfDSn8N.jpg" mos="" align="middle" fullscreen="" width="2850" height="1603" 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 help manage the noise, Minisforum’s pre-installed software allows you to switch between Work, Gaming, and Beast modes. These modes adjust the Ryzen 9's power limit from 60W all the way up to a staggering 100W. Depending on which one you use, the G1 Pro will prioritize either a quiet workspace or raw performance. While the software is intuitive and easy to use, I would have liked to see a dedicated physical mode switch on the front of the case, similar to the one on the AtomMan G7 Ti or G7 Pt.</p><h3 class="article-body__section" id="section-minisforum-g1-pro-verdict"><span>Minisforum G1 Pro: Verdict</span></h3><p>The Minisforum G1 Pro certainly lived up to the initial early impression I had when I first saw it at Computex last summer. It’s sleek, small and packed with powerful but more importantly upgradeable components and this really helps set it apart from other mini PCs as well as Minisforum’s previous devices.</p><p>At $1,439, it is more expensive than a console as well as most other mini PCs. However, for the price, you’re getting a dedicated Nvidia GPU which gives you access to DLSS and loads of other features. At the same time, you’re not stuck with soldered RAM and also have the ability to add more storage or even to swap out its low-profile GPU for a more powerful one down the line.</p><p>Despite its small package, the G1 Pro delivers both as a gaming machine and as a workstation. While I would have loved a few more USB-A ports, that’s by no means a dealbreaker. The same is true for heightened noise levels under heavy load since wearing a pair of headphones completely drowned out all that extra sound.</p><p>If you’re looking for a mini PC you can also game on and don’t want to be stuck with a laptop GPU or an external GPU dock, the G1 Pro is an innovative and fantastic machine for both work and play.</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/computing/mini-pcs/forget-consoles-i-spent-a-week-with-this-mini-pc-in-my-living-room-and-i-cant-believe-how-well-it-performs">I took the Framework Desktop out to my living room and I can’t believe I’m actually gaming in 4K on an iGPU</a></li><li><a href="https://www.tomsguide.com/computing/mini-pcs/i-tried-this-ai-powered-mini-pc-for-a-week-and-this-unique-feature-earned-it-a-permanent-spot-on-my-desk">I spent a week with this AI-powered mini PC and the buttons on the front earned it a permanent spot on my desk</a></li><li><a href="https://www.tomsguide.com/computing/i-paired-a-pocketable-mini-pc-with-a-pair-of-ar-glasses-and-even-i-was-surprised-when-it-became-my-go-to-travel-setup">I paired a pocketable mini PC with a pair of AR glasses and even I was surprised when it became my go-to travel setup</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested this $349 Alienware gaming monitor — and it's so good that I'm buying 2 for myself ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/alienware-aw2726dm-review</link>
                                                                            <description>
                            <![CDATA[ The Alienware AW2726DM delivers thanks to its smooth performance and sharp OLED display. For $349, it's the best value gaming monitor right now. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">kyEZ3VUpzS6ewVghNYKaSk</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/eMqRDYd8iwbZ88uYx3wYtW-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 17 Apr 2026 05:15:00 +0000</pubDate>                                                                                                                                <updated>Tue, 09 Jun 2026 10:32:30 +0000</updated>
                                                                                                                                            <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing Peripherals]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/eMqRDYd8iwbZ88uYx3wYtW-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Alienware AW2726DM gaming monitor on a desk.]]></media:description>                                                            <media:text><![CDATA[Alienware AW2726DM gaming monitor on a desk.]]></media:text>
                                <media:title type="plain"><![CDATA[Alienware AW2726DM gaming monitor on a desk.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/eMqRDYd8iwbZ88uYx3wYtW-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Alienware AW2726DM ($349) is something that’s becoming rarer these days: a premium device that won’t break your bank account. Sure, there are similarly-priced or even cheaper gaming monitors out there, but few have all the features you’ll find here.</p><p>So what do you get for $349? For starters, a 240Hz refresh rate that helps your games run buttery-smooth, along with a super low 0.03ms response time that offers virtually no lag. The 1440p resolution ensures a clear and sharp image on the 27-inch display, and the OLED panel delivers excellent contrast levels and vivid colors.</p><p>Aside from the relatively dim HDR and lack of RGB lighting, you’re not dealing with many trade-offs. The AW2726DM is so good, I’m half tempted to tell you to stop reading here and go out and buy one now. Of course, if you want to know more, then keep reading. Suffice it to say that the AW2726DM is one of the <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html">best gaming monitors</a> you can buy — and good enough to find a home in my personal setup.</p><h3 class="article-body__section" id="section-alienware-aw2726dm-review-cheat-sheet"><span>Alienware AW2726DM review: Cheat sheet</span></h3><ul><li><strong>What is it?</strong> The Alienware AW2726DM is a 27-inch OLED gaming monitor featuring a 240Hz refresh rate, 0.03ms response time, and a 1440p resolution.</li><li><strong>Who is it for?</strong> For anyone who wants a decent-sized and feature-rich gaming monitor that’s extremely affordable.</li><li><strong>What does it cost?</strong> The Alienware AW2726DM costs $349 and is available now on <a href="https://www.dell.com/en-us/shop/alienware-27-240hz-qd-oled-gaming-monitor-aw2726dm/apd/210-bvrc/monitors-monitor-accessories#techspecs_section" target="_blank" rel="nofollow"><u>Dell’s website</u></a>.</li><li><strong>What do we like?</strong> We like the affordable price, vibrant image quality, small footprint, and its host of gamer-friendly features.</li><li><strong>What don’t we like?</strong> We don’t like the relatively dim HDR and lack of RGB.</li></ul><h3 class="article-body__section" id="section-alienware-aw2726dm-review-specs"><span>Alienware AW2726DM review: Specs</span></h3><div ><table><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Alienware AW2726DM</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p>$349</p></td></tr><tr><td class="firstcol " ><p><strong>Display</strong></p></td><td  ><p>27-inch</p></td></tr><tr><td class="firstcol " ><p><strong>Resolution</strong></p></td><td  ><p>2560 x 1440</p></td></tr><tr><td class="firstcol " ><p><strong>Aspect ratio</strong></p></td><td  ><p>16:9</p></td></tr><tr><td class="firstcol " ><p><strong>Refresh rate</strong></p></td><td  ><p>240Hz</p></td></tr><tr><td class="firstcol " ><p><strong>Response time</strong></p></td><td  ><p>0.03ms</p></td></tr><tr><td class="firstcol " ><p><strong>Panel type</strong></p></td><td  ><p>OLED</p></td></tr><tr><td class="firstcol " ><p><strong>Ports</strong></p></td><td  ><p>2x HDMI ports, 1x DisplayPort, 1x 3.5mm headphone jack</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>23.99 x 20.60 x 9.19 (with stand)</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>13.01 pounds</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-alienware-aw2726dm-review-the-ups"><span>Alienware AW2726DM review: The ups</span></h3><p>The Alienware AW2726DM is a spectacular gaming monitor thanks to its rich feature set and jaw-dropping low price.</p><h2 id="vibrant-oled-panel">Vibrant OLED panel</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="2dkYtcjGWtfRhAuPdw5HnD" name="Alienware AW2726DM Part 2---1-LIST" alt="Alienware AW2726DM gaming monitor on a desk." src="https://cdn.mos.cms.futurecdn.net/2dkYtcjGWtfRhAuPdw5HnD.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 OLED panel is the star of the show, especially at this price. At 27 inches, you get just enough space to see everything clearly, even small text. The sharp 2560 x 1440 resolution also helps everything appear nice and sharp, even if it’s half the pixels of a 4K monitor. Thanks to the screen size, you also have enough space to place several open windows or apps.</p><p>When I tested <a href="https://www.tomsguide.com/reviews/cyberpunk-2077-phantom-liberty">Cyberpunk 2077</a> on the AW2726DM, I was impressed by the richness of the colors and the overall sharp image quality. The holographic fish floating above Night City’s busy financial district, along with the towering buildings and bustling streets, made you feel like you were in the middle of this cyberpunk dystopia.</p><div ><table><caption>Display benchmark results</caption><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>Alienware AW2725DM</strong></p></td><td  ><p><strong>Alienware AW2725QF</strong></p></td><td  ><p><strong>HP Omen Transcend 32</strong></p></td></tr><tr><td class="firstcol " ><p><strong>sRGB</strong></p></td><td  ><p>190%</p></td><td  ><p>141.7%</p></td><td  ><p>187.6%</p></td></tr><tr><td class="firstcol " ><p><strong>DCI-P3</strong></p></td><td  ><p>140.9%</p></td><td  ><p>100.4%</p></td><td  ><p>132.9%</p></td></tr><tr><td class="firstcol " ><p><strong>Delta-E</strong></p></td><td  ><p>0.24</p></td><td  ><p>0.23</p></td><td  ><p>0.29</p></td></tr></tbody></table></div><p>As you can see in the table above, the AW2726DM delivers oversaturated hues on its standard setting. Color representation (sRGB and DCI-P3) is well above the target 100%, which makes the colors very rich. Color accuracy (0.24) is also quite strong. The numbers don’t lie, this monitor delivers some truly vivid colors.</p><p>The Alienware AW2726DM has 11 display modes. This includes modes dedicated to game genres like FPS, RPG, and Sports. The modes are only slightly different from one another, depending on their function. If you’re not happy with any of the preset modes, the “custom color” option allows you to create one from scratch.</p><h2 id="understated-design">Understated design</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="asjJewVqVrmVHR7GYQTJrf" name="Alienware AW2726DM Part 2---6" alt="The back of the Alienware AW2726DM gaming monitor." src="https://cdn.mos.cms.futurecdn.net/asjJewVqVrmVHR7GYQTJrf.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 Alienware AW2726DM has an understated all-black design that makes it look more like a standard monitor than a gaming device. While it won’t draw attention when you’re using it around others, I personally love its simple, elegant chassis.</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="dfUrVBJyh3QuUPaV4UM8Vn" name="Alienware AW2726DM Part 2---9" alt="The circular stand of the Alienware AW2726DM." src="https://cdn.mos.cms.futurecdn.net/dfUrVBJyh3QuUPaV4UM8Vn.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 27-inch monitor rests on a sturdy 8.80-inch stand that doesn’t take up much space on your desk. Since the stand is flat, you’re able to place items like a game controller or phone to keep your desk even tidier. The bearing ring on the base of the stand lets you turn the entire thing 360 degrees.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Kjm8NqLy4yUFgGxF6R3BSc" name="aw5" alt="Alienware AW2726DM backside" src="https://cdn.mos.cms.futurecdn.net/Kjm8NqLy4yUFgGxF6R3BSc.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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’s easy to move the monitor up or down 5.2 inches along the shaft’s stand with minimal force. You can also rotate the display a full 90 degrees if you need it to be vertical. The display tilts 5 degrees forward and 21 degrees backward. All of this lets you achieve your desired viewing angle.</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="Ww9Yfodn3SoD5f6ybrr7zU" name="Alienware AW2726DM Part 2---11" alt="Alienware AW2726DM ports" src="https://cdn.mos.cms.futurecdn.net/Ww9Yfodn3SoD5f6ybrr7zU.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>Lastly, there's the port selection, which includes a pair of HDMI ports, a lone DisplayPort, and a 3.5mm headphone jack. Reaching the ports is easy since you can turn the monitor 360 degrees on its base. While the port selection isn't extensive, you get the bare basics.</p><h2 id="excellent-performance-2">Excellent performance</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="FDKHztadJAFEgpBHcmSkFa" name="Alienware AW2726DM Part 2---4" alt="Alienware AW2726DM performance" src="https://cdn.mos.cms.futurecdn.net/FDKHztadJAFEgpBHcmSkFa.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 AW2726DM delivers phenomenal performance thanks to its buttery-smooth 240Hz refresh rate and fast 0.03ms response time. Keep in mind, those are features you usually get with more expensive gaming monitors. Compatibility with Nvidia G-Sync and AMD FreeSync also helps deliver smooth gaming performance.</p><p>For my testing, I had the AW2726DM connected to the new Razer Blade 16 gaming laptop packing an Intel Core Ultra 9 “Panther Lake” CPU, an Nvidia GeForce RTX 5090 mobile GPU, and 32GB of RAM. You don’t need such a powerful gaming laptop or gaming PC for Alienware’s monitor, but that type of rig can help you utilize it to its full potential.</p><p>Cyberpunk 2077 ran like a dream thanks to the 240Hz refresh rate. I also didn’t notice input lag since the response time is a low 0.03ms. Professional gamers who are used to playing on something like the <a href="https://www.tomsguide.com/reviews/alienware-500hz-gaming-monitor-aw2524h">Alienware AW2524H</a> with its insane 500Hz refresh rate might notice a difference, but average gamers like myself won’t. Trust me, you won’t be disappointed by the AW2726DM’s performance.</p><h2 id="clean-interface">Clean interface</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="vkGF2zEYd4hi2sAb6VvJGg" name="Alienware AW2726DM Part 2---7" alt="Alienware AW2726DM interface" src="https://cdn.mos.cms.futurecdn.net/vkGF2zEYd4hi2sAb6VvJGg.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 Alienware AW2726DM has the same basic interface as other Alienware gaming monitors I’ve reviewed, such as the <a href="https://www.tomsguide.com/computing/monitors/alienware-aw3425dw-review">Alienware AW3425DW</a>.</p><p>The user interface maintains its familiar look, featuring a black-and-gray background contrasted with blue-and-white text. Despite the extensive array of options, including display modes and various lighting adjustments, the clean layout ensures that navigating the settings is straightforward.</p><p>The OSD joystick used for sorting through menus is very responsive and easy to reach. Its flat, concave top allows you to have a firm hold as you’re clicking through the menus.</p><h3 class="article-body__section" id="section-alienware-aw2726dm-review-the-downs"><span>Alienware AW2726DM review: The downs</span></h3><p>You’re getting fantastic value with the Alienware AW2726DM, but some compromises were made to keep its price affordable.</p><h2 id="not-the-brightest-oled">Not the brightest OLED</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9HKYRw9E4E7TU4BkqS68r5" name="aw1" alt="Alienware AW2726DM on a desk." src="https://cdn.mos.cms.futurecdn.net/9HKYRw9E4E7TU4BkqS68r5.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>This is an issue with virtually all OLED gaming monitors I’ve ever reviewed, but the AW2726DM doesn’t deliver overly bright HDR. In fact, SDR brightness is overall dim across its various display modes.</p><div ><table><caption>HDR test results</caption><tbody><tr><td class="firstcol empty" ></td><td  ><p><strong>SDR / HDR brightness</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Alienware AW2725DM</strong></p></td><td  ><p>181 / 342</p></td></tr><tr><td class="firstcol " ><p><strong>Alienware AW2725QF</strong></p></td><td  ><p>388 / 675</p></td></tr><tr><td class="firstcol " ><p><strong>HP Omen Transcend 32</strong></p></td><td  ><p>245 / 241</p></td></tr></tbody></table></div><p>As you can see above, the HDR brightness is about 340 nits at 10% of the display, so you do get good contrast between dark and light elements. Still, don’t expect eye-scorching levels of brightness even in the dedicated HDR modes. SDR brightness is also lower than the competition.</p><p>While I wish the display got brighter, you won’t exactly be squinting when using the monitor. Our office is pretty well lit, but the monitor’s lighting was suitable for the environment. I imagine it would look just right in my comparatively darker apartment.</p><h2 id="no-rgb">No RGB</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="qgDugx9fzgtdsx6wVDnrwA" name="Alienware AW2726DM Part 2---12" alt="Alienware AW2726DM" src="https://cdn.mos.cms.futurecdn.net/qgDugx9fzgtdsx6wVDnrwA.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>Alienware and RGB lighting are pretty synonymous, so it’s interesting that the AW2726DM has no RGB lighting of any kind. Even the Alienware logo on the back remains dark.</p><p>The lack of RGB isn’t a big deal for me since I’m neither for nor against it. And even if there were some RGB lighting on the back, it’s not like I’d be able to see it when I’m in front of the display. However, if you do like RGB, you might be disappointed.</p><h3 class="article-body__section" id="section-alienware-aw2726dm-review-verdict"><span>Alienware AW2726DM review: Verdict</span></h3><p>On its own, the Alienware AW2726DM is a brilliant gaming monitor that ticks all the right boxes for picture quality and performance. The fact that it only costs $349 just makes it all the better, especially during a time when gaming devices are becoming so expensive.</p><p>While you’re not getting bright HDR or RGB lighting, the AW2726DM’s faults are easy to overlook given its generous asking price. If you’re looking to upgrade your gaming den with a new or extra monitor, don’t pass up on this one. Right now, it’s the best value gaming monitor out there. As I said in the headline, it's so good that I'm buying two for myself!</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I stress-tested Pragmata’s path tracing — it looks like a dream and Nvidia’s DLSS 4 makes it play like one (provided you use it right) ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/gpus/i-stress-tested-pragmatas-path-tracing-it-looks-like-a-dream-and-nvidias-dlss-4-makes-it-play-like-one-provided-you-use-it-right</link>
                                                                            <description>
                            <![CDATA[ Can the RTX 5080 and 5060 Ti handle Pragmata at 4K with Path Tracing? See the real-world FPS and latency benchmarks to find your DLSS sweet spot. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">qJrXFqfEsTfDMcJSGjTYAZ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/tYYWxutnbryVKW3kUM72iR-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 16 Apr 2026 12:05:43 +0000</pubDate>                                                                                                                                <updated>Thu, 16 Apr 2026 12:08:23 +0000</updated>
                                                                                                                                            <category><![CDATA[GPUs]]></category>
                                                    <category><![CDATA[PC Gaming]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                    <category><![CDATA[Gaming]]></category>
                                                                                                                    <dc:creator><![CDATA[ Jason England ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/v4fSq5U4uZUEtGY2BwNuJ6.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Jason brings a decade of tech and gaming journalism experience to his role as a Managing Editor of Computing at Tom&#039;s Guide. He has previously written for Laptop Mag, Tom&#039;s Hardware, Kotaku, Stuff and BBC Science Focus. In his spare time, you&#039;ll find Jason looking for good dogs to pet or thinking about eating pizza if he isn&#039;t already.&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/tYYWxutnbryVKW3kUM72iR-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Pragmata]]></media:description>                                                            <media:text><![CDATA[Pragmata]]></media:text>
                                <media:title type="plain"><![CDATA[Pragmata]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/tYYWxutnbryVKW3kUM72iR-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As you may have seen, we rather love <a href="https://www.tomsguide.com/gaming/pragmata-review">Pragmata </a>right now, and I can give all you PC gamers out there the lowdown on how well it’ll run on your rigs. Spoiler alert: just like <a href="https://www.tomsguide.com/gaming/pc-gaming/resident-evil-requiem-with-path-tracing-is-horrifying-and-i-mean-that-as-a-compliment-to-nvidia-and-dlss-4">Resident Evil Requiem</a>, path tracing adds a night and day difference.</p><p>So I threw it at my pricey RTX 5080 and mid-range <a href="https://www.tomsguide.com/computing/gpus/nvidia-geforce-rtx-5060-ti-review">RTX 5060 Ti </a>rigs to see how far I can stretch those fidelity settings with DLSS 4, and how well it performs with this incredibly demanding graphical tech running.</p><h2 id="what-settings-should-you-use">What settings should you use?</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="cAd2NbVJsFsDYTeHHftGUe" name="PRAGMATA_SS_10" alt="Pragmata" src="https://cdn.mos.cms.futurecdn.net/cAd2NbVJsFsDYTeHHftGUe.png" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Capcom)</span></figcaption></figure><p>As I always say, Nvidia’s DLSS is a helluva tool for extracting more gameplay value out of your GPU — provided you use it the right way. Because sure, a game can <em>look </em>smooth, but if you’re adding all the AI trickery on top of a game that is running at 20 FPS, it will not <em>feel </em>smooth to play.</p><p>That’s why you’ll need to go into the settings to tinker the base rate a little before overlaying DLSS features. Just as a general reminder:</p><ul><li>If your game is a slower-paced single-player title, aim for 40 FPS</li><li>Need quick reflexes? Aim for 60 FPS</li><li>For competitive multiplayer, either don’t use it or aim for 120 FPS</li></ul><p>From mine and Tony’s time playing Pragmata, you can safely put it in that <strong>40 FPS target</strong> category. There is combat that requires you to dodge attacks and shoot, but with plenty of time to telegraph enemy moves, the really fun puzzle elements and button-based quick-time events, you’ll still get a game that feels good to play at this level.</p><h2 id="by-the-numbers">By the numbers</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="FWossYL79mdN98DFinTXZ7" name="PRAGMATA_SS_Gamescom_05" alt="Pragmata screenshot" src="https://cdn.mos.cms.futurecdn.net/FWossYL79mdN98DFinTXZ7.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: Capcom)</span></figcaption></figure><p>So allow me to introduce you to the machines that will be taking this on (quite proud of my rebuilds):</p><ul><li>Remember that PC I built for myself at <a href="scan.co.uk" target="_blank" rel="nofollow">Scan computers</a>? I’ve done a transplant into the gorgeous Micro ATX case you see in the top image — doing some space saving while preserving power. It packs an AMD Ryzen 7 9800X3D, RTX 5080 and 32GB of DDR5 RAM. <a href="https://youtu.be/uZRH_P_qs_I" target="_blank">You can watch the whole big build here</a>.</li><li>The second is a modified <a href="https://www.tomsguide.com/computing/gaming-desktops/ibuypower-rdy-element-9-pro-r07-review">RDY Element 9 Pro R07</a> — sporting an <a href="https://www.tomsguide.com/computing/cpus/intel-core-ultra-7-270k-plus-5-250k-plus-review">Intel Core Ultra 7 270K Plus</a>, RTX 5060 Ti (16GB) and 32GB of DDR5 RAM.</li></ul><p>Same rules apply as my Requiem testing, so I’m stress testing at resolutions fair to each card (4K for the 5080 and 1440p for the 5060 Ti) at maxed out path tracing settings. Of course, as I said above, you can tweak some graphical settings to squeeze even more frames out of the base rate.</p><iframe allow="" height="600px" width="100%" id="" style="width:100%;height:600px;" class="position-center" data-lazy-priority="low" data-lazy-src="https://flo.uri.sh/story/3649145/embed"></iframe><p>And as you can see, the multipliers really start to pile on the additional frames nicely here — making the game look silky smooth. </p><h2 id="latency-checker">Latency checker</h2><iframe allow="" height="600px" width="100%" id="" style="width:100%;height:600px;" class="position-center" data-lazy-priority="low" data-lazy-src="https://flo.uri.sh/visualisation/28554338/embed"></iframe><p>So there’s big frame rates happening up above, but that’s half the story. As I said up above, the game’s got to feel smooth too, and in this stress test (just like what happened with Requiem), this is where it becomes clear that DLSS 4.5 performance is your go-to option if you wanna go all-out in the settings.</p><p>DLSS always comes with a small penalty to that base frame rate, as the GPU’s attention is turned to the AI background work. And while these are mostly playable, Quality or Balanced upscaling does lead to some noticeable latency. <strong>Performance is your sweet spot.</strong></p><h2 id="path-traced-sci-fi-fun">Path traced sci-fi fun</h2><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/GoqZb8GxwEbnWpufX5zqg8.png" alt="Pragmata" /><figcaption>Path tracing<small role="credit">Future</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/iYqZMYdgtFPoGiNjwhgMn8.png" alt="Pragmata" /><figcaption>No path tracing<small role="credit">Future</small></figcaption></figure></figure><p>If you follow my advice from up above, you’ll have a great experience with what has become one of my personal surprise favorite games of 2026. Path tracing really does make a material difference to the visual fidelity here and draws you into the immersion of this fascinating sci-fi world.</p><p>I demoed this game a few months ago and immediately fell in love with the hybrid shooter/puzzler gameplay, but I did feel a little nervous about how far this could go before it becomes tiresome. Turns out the answer is it never gets old! New layers of complication are added over time and discoverable elements keep things fresh. Oh, and the boss battles are epic.</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/computing/pc-sales-are-up-but-dont-be-fooled-idc-report-warns-ramageddon-is-just-getting-started">PC sales are up, but don’t be fooled — IDC report warns RAMageddon is just getting started</a></li><li><a href="https://www.tomsguide.com/computing/gpus/i-tested-dlss-4-5-dynamic-multi-frame-generation-its-not-just-ai-trickery-its-nvidias-cheat-code-for-4k-240hz-and-a-true-console-killer">I tested DLSS 4.5 Dynamic Multi Frame Generation: It’s not just AI trickery, it’s Nvidia’s cheat code for 4K 240Hz and a true console killer</a></li><li><a href="https://www.tomsguide.com/computing/gaming-laptops/asus-tuf-gaming-a14-2026-review">I really wanted to love the Asus TUF Gaming A14 (2026), but it’s an expensive heartbreaker</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested Alienware’s new $349 gaming monitor — and it’s too good to be true ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/computing/monitors/i-just-tested-alienwares-new-usd349-gaming-monitor-and-its-too-good-to-be-true</link>
                                                                            <description>
                            <![CDATA[ The Alienware AW2726DM might only be $349, but it packs all the features you'd need for an awesome gaming experience. Here are my initial thoughts. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">kCgawZdzbF8mUFZxBeJwFA</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/9HKYRw9E4E7TU4BkqS68r5-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 15 Apr 2026 11:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Monitors]]></category>
                                                    <category><![CDATA[Computing]]></category>
                                                    <category><![CDATA[Computing Hardware]]></category>
                                                                                                <author><![CDATA[ tony.polanco@futurenet.com (Tony Polanco) ]]></author>                    <dc:creator><![CDATA[ Tony Polanco ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/atzRNqFt5wYgEUPBDahWsD.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/9HKYRw9E4E7TU4BkqS68r5-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Alienware AW2726DM on a desk.]]></media:description>                                                            <media:text><![CDATA[Alienware AW2726DM on a desk.]]></media:text>
                                <media:title type="plain"><![CDATA[Alienware AW2726DM on a desk.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/9HKYRw9E4E7TU4BkqS68r5-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Alienware AW2726DM is the gaming monitor we need right now. With <a href="https://www.tomsguide.com/computing/ram-price-crisis-2026-everything-you-need-to-know">RAMageddon</a> driving up the price of electronics, a $349 device that’s so feature-rich is almost miraculous. Yes, there are similar monitors out there, but none offer this kind of  bang for your buck.</p><p>I’ve been testing the new Alienware monitor for a week after first seeing it at a press event, and it’s been a revelation. You get a sharp 27-inch 1440p QD-OLED  panel with a smooth 240Hz refresh rate and an ultra-low 0.03ms response time. Thanks to those specs, everything looks and runs like a dream. The fact that there are virtually no compromises for the price is wild.</p><p>I’ll have my full Alienware AW2726DM review for you soon. Right now, here’s why this affordable gaming monitor has won me over and why I’m ready to buy at least two of them for my own home setup.</p><div class="product"><a data-dimension112="72d06b5e-2637-4d61-a4b8-a11ea6f0375e" data-action="Deal Block" data-label="The Alienware AW2726DM is a feature-rich gaming monitor that only costs $349. It has a sharp 27-inch QD-OLED 2560 x 1440 display, a smooth 240Hz refresh rate, and a low 0.03ms response time. Though it lacks RGB lighting, the monitor's features and irresistible price more than make up for that." data-dimension48="The Alienware AW2726DM is a feature-rich gaming monitor that only costs $349. It has a sharp 27-inch QD-OLED 2560 x 1440 display, a smooth 240Hz refresh rate, and a low 0.03ms response time. Though it lacks RGB lighting, the monitor's features and irresistible price more than make up for that." data-dimension25="$349" href="https://www.dell.com/en-us/shop/alienware-27-240hz-qd-oled-gaming-monitor-aw2726dm/apd/210-bvrc/monitors-monitor-accessories" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:872px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="6hKjeF6zKBNrGq7XAv6Roe" name="Alienware AW2726DM" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/6hKjeF6zKBNrGq7XAv6Roe.jpg" mos="" align="middle" fullscreen="" width="872" height="872" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Alienware AW2726DM is a feature-rich gaming monitor that only costs $349. It has a sharp 27-inch QD-OLED 2560 x 1440 display, a smooth 240Hz refresh rate, and a low 0.03ms response time. Though it lacks RGB lighting, the monitor's features and irresistible price more than make up for that.<a class="view-deal button" href="https://www.dell.com/en-us/shop/alienware-27-240hz-qd-oled-gaming-monitor-aw2726dm/apd/210-bvrc/monitors-monitor-accessories" target="_blank" rel="nofollow" data-dimension112="72d06b5e-2637-4d61-a4b8-a11ea6f0375e" data-action="Deal Block" data-label="The Alienware AW2726DM is a feature-rich gaming monitor that only costs $349. It has a sharp 27-inch QD-OLED 2560 x 1440 display, a smooth 240Hz refresh rate, and a low 0.03ms response time. Though it lacks RGB lighting, the monitor's features and irresistible price more than make up for that." data-dimension48="The Alienware AW2726DM is a feature-rich gaming monitor that only costs $349. It has a sharp 27-inch QD-OLED 2560 x 1440 display, a smooth 240Hz refresh rate, and a low 0.03ms response time. Though it lacks RGB lighting, the monitor's features and irresistible price more than make up for that." data-dimension25="$349">View Deal</a></p></div><h2 id="display">Display</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="i2knkVAebanbUSpCa73rxF" name="aw9" alt="Alienware AW2726DM display" src="https://cdn.mos.cms.futurecdn.net/i2knkVAebanbUSpCa73rxF.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>Naturally, the star of the show is the display.</p><p>While I’m slightly more partial to 34-inch monitors, I won’t say no to a more compact 27-inch display — especially when it looks this good. This size helps the 2560 x 1440 resolution look sharp and lets you clearly see everything on the screen. For work, you also get plenty of space to comfortably keep several windows open.</p><p><a href="https://www.tomsguide.com/opinion/now-is-the-best-time-to-play-cyberpunk-2077">Cyberpunk 2077</a> ran buttery-smooth on this monitor, thanks to the 240Hz refresh rate. I also didn’t notice input lag, since the response time is a low 0.03ms. I’ve only seen that on much more expensive monitors. Unless you’re a professional gamer who needs an even higher refresh rate, you won’t be disappointed with the performance.</p><div ><table><caption>Alienware AW2726DM test results</caption><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>Standard</strong></p></th><th  ><p><strong>FPS</strong></p></th><th  ><p><strong>RPG</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Nits (brightness)</strong></p></td><td  ><p>181.8</p></td><td  ><p>160.8</p></td><td  ><p>161.6</p></td></tr><tr><td class="firstcol " ><p><strong>sRGB</strong></p></td><td  ><p>190%</p></td><td  ><p>201%</p></td><td  ><p>192.2%</p></td></tr><tr><td class="firstcol " ><p><strong>DCI-P3</strong></p></td><td  ><p>140.9%</p></td><td  ><p>142.4%</p></td><td  ><p>136.2%</p></td></tr><tr><td class="firstcol " ><p><strong>Delta-E</strong></p></td><td  ><p>0.24</p></td><td  ><p>0.26</p></td><td  ><p>0.24</p></td></tr></tbody></table></div><p>There are nine main display modes, and each delivers generally oversaturated colors that make games look vibrant. You can see a handful of the modes in the table above for reference.</p><div ><table><caption>HDR test results</caption><thead><tr><th class="firstcol empty" ></th><th  ><p><strong>HDR brightness (10% of display)</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Smart HDR Desktop</strong></p></td><td  ><p>342</p></td></tr><tr><td class="firstcol " ><p><strong>Smart HDR Movie</strong></p></td><td  ><p>340</p></td></tr><tr><td class="firstcol " ><p><strong>Smart HDR Game</strong></p></td><td  ><p>340</p></td></tr></tbody></table></div><p>HDR brightness isn’t all that bright, but that’s something I’ve come to expect from OLED gaming monitors. As you can see above, the brightness is about 340 nits at 10% of the display, so you do get good contrast between dark and light elements. Still, don’t expect eye-scorching levels of brightness even in the dedicated HDR modes.</p><h2 id="design">Design</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Kjm8NqLy4yUFgGxF6R3BSc" name="aw5" alt="Alienware AW2726DM backside" src="https://cdn.mos.cms.futurecdn.net/Kjm8NqLy4yUFgGxF6R3BSc.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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>Since the Alienware AW2726DM is a 27-inch gaming monitor, it’s easy to find a spot for it in just about any gaming or office setup. I’ve been using it at the office, and no one has caught on that it’s a gaming monitor.</p><p>The square 8.80-inch stand provides sturdy support. Its flat design lets you easily place items like your phone or an extra controller on it, helping keep your desk tidy. You can glide the monitor 5.2 inches along the stand’s shaft, rotate it 90 degrees, and tilt it 5/21 degrees. There’s also a bearing ring on the base that lets you turn the entire thing 360 degrees.</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:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="oP9gUNWYN2MfBi3A8Nn4a5" name="aw7" alt="Alienware AW2726DM" src="https://cdn.mos.cms.futurecdn.net/oP9gUNWYN2MfBi3A8Nn4a5.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" 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 monitor has a simple, all-black design that I quite like. There’s an understated Alienware logo on the right side, but nothing else beyond that. One concern is that there is no RGB lighting, even for the logo. I personally don’t mind this since I’m somewhat neutral on RGB lighting, but it’s worth noting as one of the few trade-offs.</p><h2 id="alienware-aw2726dm-outlook">Alienware AW2726DM Outlook</h2><p>I still need to test more games before rendering my final verdict, but given what you get for the price, I can already see the Alienware AW2726DM finding a spot on our <a href="https://www.tomsguide.com/us/best-gaming-monitors,review-3114.html">best gaming monitors</a> guide. You get a sharp, vivid display with excellent performance in an easy-to-manage design. It ticks all the right boxes.</p><p>At the risk of undermining my own review, I say just go out and buy the Alienware AW2726DM now. As I said, I’m seriously considering buying a pair for myself. That price is extremely enticing. But if you’d rather wait for my full review before pulling the trigger, keep it locked here. Stay tuned!</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/gaming/pragmata-review">Pragmata is my favorite surprise game of 2026</a></li><li><a href="https://www.tomsguide.com/computing/ive-used-a-macbook-as-my-primary-computer-for-two-weeks-and-im-not-going-back-to-windows">I’ve used a MacBook as my primary computer for two weeks</a></li><li><a href="https://www.tomsguide.com/computing/laptops/dell-xps-16-2026-review">I just tested the Dell XPS 16 and it’s my new favorite Windows laptop</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
            </channel>
</rss>