Gilded Spatula’s 2026 SEO Survival Guide

Listen to this article · 10 min listen

The digital storefront of ‘The Gilded Spatula,’ a charming but struggling artisanal bakery in Atlanta’s Grant Park neighborhood, was a ghost town. Sarah Chen, the bakery’s owner, poured her heart into her sourdoughs and pastries, but her online presence felt as flat as an unproofed brioche. “People tell me our croissants are the best they’ve ever had,” she confided to me over a coffee last spring, “but if they can’t find us when they search for ‘best bakeries Grant Park,’ what good is it?” Her dilemma perfectly encapsulates why mastering on-page SEO in 2026 isn’t just an advantage—it’s survival for any business vying for online visibility. How do you make sure your digital doors are wide open, not just for search engines, but for your future customers?

Key Takeaways

  • Prioritize user intent mapping for every page, ensuring content directly answers specific search queries to capture relevant traffic.
  • Implement structured data markup like Schema.org for product pages and local business listings to enhance search engine understanding and featured snippets.
  • Conduct a thorough content audit to identify and refresh outdated or underperforming content, focusing on topical authority and comprehensive coverage.
  • Optimize internal linking strategies to distribute “link equity” and guide users through your site, improving crawlability and user experience.
  • Regularly monitor Core Web Vitals and address any technical issues to maintain optimal page experience, which directly impacts search rankings.
68%
of traffic from organic search
2.7x
higher conversion rate for optimized pages
55%
of businesses prioritizing on-page SEO
1st Page
90% of clicks go to top results

The Gilded Spatula’s Digital Dough Dilemma: A Case Study in On-Page SEO

Sarah’s problem wasn’t unique. The Gilded Spatula had a beautiful website, designed by a friend, but it lacked any real strategic thought for how search engines would interpret its offerings. Her primary keywords, like “artisan bread Atlanta” or “French pastries Grant Park,” were buried deep within paragraphs, if they appeared at all. The site was visually appealing, yes, but to a search engine bot, it was a beautiful, unindexed book.

Our initial audit revealed several immediate red flags. The page titles were generic—”Home,” “About Us,” “Products”—rather than descriptive, keyword-rich phrases. Meta descriptions were either missing or auto-generated gibberish, offering no compelling reason for a user to click from the search results page. This is a common oversight; many business owners think a pretty site is enough. It’s not. Google, and other search engines, need clear signals about what your page is actually about. If you don’t tell them, they guess, and often, they guess wrong.

Step 1: Unearthing User Intent with Keyword Research

My first recommendation to Sarah was to stop guessing what her customers searched for and start knowing. We used a combination of tools, including Ahrefs and Semrush, to dig into the actual search queries people in Atlanta, specifically around the Grant Park, East Atlanta Village, and Ormewood Park neighborhoods, were using to find bakeries. We looked for terms like “sourdough starter Atlanta,” “custom cakes Grant Park,” and “gluten-free bakery near me.” This wasn’t just about finding high-volume keywords; it was about understanding the user intent behind those searches. Was someone looking for a recipe, a supplier, or a local shop to buy from? We needed to answer that.

What we found was illuminating. While “bakery Atlanta” had high volume, “best sourdough Grant Park” or “croissants delivery Atlanta” indicated a much stronger purchase intent and less competition. This became our focus. It’s not just about getting traffic; it’s about getting the right traffic.

Step 2: Crafting Compelling Content and Optimizing On-Page Elements

With our keyword research in hand, we began the overhaul. Each page title ( tag) was rewritten to be concise, descriptive, and include primary keywords. For instance, the “Products” page became <strong>“Artisan Sourdough Breads & Pastries | The Gilded Spatula | Grant Park, Atlanta.”</strong> The meta descriptions were crafted to be miniature advertisements, enticing clicks by highlighting unique selling points like “Hand-laminated croissants, naturally leavened sourdough, and custom cakes baked fresh daily in Grant Park. Order online for pickup or local delivery!”</p> <p>We then tackled the actual content. This is where many businesses falter, thinking keyword stuffing is still the way to go. It absolutely is not. Google’s algorithms in 2026 are incredibly sophisticated, prioritizing natural language and comprehensive topic coverage. We focused on creating content that genuinely answered user questions. For the sourdough page, we didn’t just list products; we talked about the fermentation process, the local grains Sarah sourced, and even linked to a blog post about the health benefits of sourdough. This builds <strong>topical authority</strong>, signaling to search engines that your site is a definitive resource.</p> <p>We also paid close attention to heading structures (H1, H2, H3 tags). The main heading (H1) on each page was a clear statement of purpose, incorporating the primary keyword. Subsequent H2 and H3 tags broke down the content into easily digestible sections, often using variations of our target keywords. For the “Custom Cakes” page, an H2 might be “Designing Your Dream Cake in Atlanta,” with H3s for “Flavor Combinations” or “Delivery Options in Fulton County.”</p> <p>One editorial aside: I’ve seen countless businesses spend thousands on paid ads, only to have users land on a poorly optimized page and bounce immediately. That’s like paying for a billboard that directs people to a closed store. Your on-page SEO is the foundation; without it, all other marketing efforts are built on sand.</p> <h3>Step 3: The Power of Structured Data and Local SEO Signals</h3> <p>For a local business like The Gilded Spatula, <strong>structured data markup</strong> was non-negotiable. We implemented <a href="https://schema.org/" target="_blank" rel="noopener">Schema.org</a> markup for the bakery’s address, phone number (a real local number, (404) 555-0198), operating hours, and product listings. This code, invisible to users but readable by search engines, helps Google understand exactly what information is on the page. This is critical for appearing in things like Google’s Local Pack and rich snippets. When someone searches “bakery near me,” we want Sarah’s business to stand out with stars, hours, and direct links.</p> <p>We also ensured the bakery’s Google Business Profile (GBP) was meticulously updated and consistent with the website information. This includes photos, services offered, and regularly responding to reviews. Consistency across all online properties—website, GBP, local directories—sends strong signals of legitimacy and relevance to search engines. I can’t stress enough how often a simple mismatch in opening hours can derail local rankings. For more on maximizing local search, read our guide on <a href="https://rankanddiscover.com/atlanta-s-2026-seo-5-steps-to-dominate-search/">Atlanta’s 2026 SEO: 5 Steps to Dominate Search</a>.</p> <h3>Step 4: Internal Linking and Site Structure</h3> <p>A well-structured website acts like a well-organized library. Users can easily find what they need, and search engine bots can efficiently crawl and index all your content. We improved The Gilded Spatula’s <strong>internal linking strategy</strong>, connecting related pages with descriptive anchor text. For example, from the “Sourdough Breads” page, we linked to a blog post about “Pairing Sourdough with Local Cheeses” and back to the “About Us” page where Sarah discussed her baking philosophy. This not only helps distribute “link equity” (the authority passed between pages) but also keeps users engaged on the site longer, reducing bounce rates—another positive signal to search engines.</p> <p>I had a client last year, a boutique clothing store in Buckhead, who had an amazing blog but no internal links back to their product pages. It was a content island! Once we implemented a strategic internal linking plan, their product pages saw a 20% increase in organic traffic within three months, simply because we were guiding users and bots more effectively.</p> <aside class="related-callout"><span class="related-callout-label">Related Reading</span><a href="https://rankanddiscover.com/on-page-seo-2026-s-5-new-ranking-rules/">On-Page SEO: 2026’s 5 New Ranking Rules</a></p> <p class="related-callout-excerpt">Discover the evolving landscape of on-page SEO and the critical rules you need to follow for success in the coming year.</p> </aside> <h3>Step 5: Technical SEO and Page Experience</h3> <p>Even the most perfectly optimized content won’t rank if the website itself is slow or difficult to use. In 2026, <strong>Core Web Vitals</strong> are more important than ever. We ran audits using <a href="https://pagespeed.web.dev/" target="_blank" rel="noopener">Google’s PageSpeed Insights</a> and <a href="https://developers.google.com/search/docs/fundamentals/core-web-vitals" target="_blank" rel="noopener">Lighthouse reports</a> to identify and fix issues impacting load speed, interactivity, and visual stability. This included optimizing image sizes, minifying CSS and JavaScript, and ensuring the site was fully responsive across all devices—especially mobile. A significant portion of Sarah’s potential customers were searching on their phones while out and about, so a clunky mobile experience was a deal-breaker.</p> <p>We also ensured the site had an XML sitemap submitted to <a href="https://search.google.com/search-console/" target="_blank" rel="noopener">Google Search Console</a> and that there were no crawl errors. These technical aspects are often overlooked, but they form the backbone of a healthy, rankable website. For a deeper dive into ensuring your site is technically sound, explore our article on <a href="https://rankanddiscover.com/technical-seo-winning-strategies-for-2026/">Technical SEO: Winning Strategies for 2026</a>.</p> <h2 id="section-3">The Sweet Taste of Success: Resolution and Lessons Learned</h2> <p>The results for The Gilded Spatula were, well, delicious. Within six months, Sarah saw a 180% increase in organic traffic to her site. More importantly, her local search rankings soared. Searches like “best croissants Grant Park” now prominently featured The Gilded Spatula, often with a rich snippet showing her average 4.9-star rating. Online orders for pickup and local delivery through her integrated e-commerce platform (<a href="https://shopify.com/" target="_blank" rel="noopener">Shopify</a>) jumped by 150%. She even had to hire two new bakers to keep up with demand.</p> <p>Sarah’s story isn’t just about a local bakery; it’s a testament to the enduring power of meticulous on-page SEO. It’s about understanding that search engines are designed to serve users the best possible results. By focusing on user intent, crafting high-quality, relevant content, implementing structured data, maintaining a clean site structure, and ensuring a stellar page experience, you’re not just pleasing an algorithm—you’re serving your customers. And that, my friends, is the real secret to sustainable online growth. The digital landscape will always evolve, but the principles of providing value and clarity remain constant. For further insights on how to improve your site’s discoverability, consider reading about <a href="https://rankanddiscover.com/2026-discoverability-is-your-brand-invisible/">2026 Discoverability: Is Your Brand Invisible?</a></p> <div class="faq-section"> <div class="faq-item"> <h3 class="faq-question">What is the most critical on-page SEO factor in 2026?</h3> <div class="faq-answer"> <p>The most critical on-page SEO factor in 2026 is understanding and addressing <strong>user intent</strong>. Your content must comprehensively answer the specific questions or needs implied by a search query to rank effectively.</p> </div> </div> <div class="faq-item"> <h3 class="faq-question">How often should I update my on-page content?</h3> <div class="faq-answer"> <p>You should conduct a content audit at least once a year to identify outdated or underperforming pages. High-performing, evergreen content might need minor refreshes every 6-12 months, while time-sensitive content may require more frequent updates.</p> </div> </div> <div class="faq-item"> <h3 class="faq-question">Do meta descriptions still matter for SEO?</h3> <div class="faq-answer"> <p>While meta descriptions aren’t a direct ranking factor, they are extremely important for <strong>click-through rate (CTR)</strong>. A well-crafted meta description can entice users to click your result over competitors, signaling to search engines that your page is highly relevant.</p> </div> </div> <div class="faq-item"> <h3 class="faq-question">What role do Core Web Vitals play in on-page SEO?</h3> <div class="faq-answer"> <p>Core Web Vitals (Largest Contentful Paint, First Input Delay, Cumulative Layout Shift) are direct ranking factors that measure user experience. Poor scores indicate a slow or unstable page, which can negatively impact your search rankings and lead to higher bounce rates.</p> </div> </div> <div class="faq-item"> <h3 class="faq-question">Is keyword density still a relevant metric?</h3> <div class="faq-answer"> <p>No, focusing on a specific “keyword density” is an outdated and potentially harmful practice. Instead, concentrate on natural language, semantic relevance, and comprehensive topic coverage, ensuring your content genuinely addresses the user’s query without stuffing keywords.</p> </div> </div> </div> </div> <div class="share-buttons"> <span class="share-label">Share:</span> <a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Frankanddiscover.com%2Fgilded-spatula-s-2026-seo-survival-guide%2F" class="share-btn facebook" target="_blank" rel="noopener noreferrer" aria-label="Share on Facebook"> <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"/></svg> <span>Facebook</span> </a> <a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Frankanddiscover.com%2Fgilded-spatula-s-2026-seo-survival-guide%2F&text=Gilded+Spatula%26%238217%3Bs+2026+SEO+Survival+Guide" class="share-btn twitter" target="_blank" rel="noopener noreferrer" aria-label="Share on Twitter"> <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg> <span>Twitter</span> </a> <a href="https://pinterest.com/pin/create/button/?url=https%3A%2F%2Frankanddiscover.com%2Fgilded-spatula-s-2026-seo-survival-guide%2F&media=https%3A%2F%2Frankanddiscover.com%2Fwp-content%2Fuploads%2Fsites%2F30%2F2026%2F03%2Fsearch-rankings-your-2026-marketing-edge-featured.png&description=Gilded+Spatula%26%238217%3Bs+2026+SEO+Survival+Guide" class="share-btn pinterest" target="_blank" rel="noopener noreferrer" aria-label="Share on Pinterest"> <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.373 0 0 5.372 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738a.36.36 0 01.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.632-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z"/></svg> <span>Pinterest</span> </a> <a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Frankanddiscover.com%2Fgilded-spatula-s-2026-seo-survival-guide%2F&title=Gilded+Spatula%26%238217%3Bs+2026+SEO+Survival+Guide" class="share-btn linkedin" target="_blank" rel="noopener noreferrer" aria-label="Share on LinkedIn"> <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M16 8a6 6 0 016 6v7h-4v-7a2 2 0 00-2-2 2 2 0 00-2 2v7h-4v-7a6 6 0 016-6zM2 9h4v12H2zM4 6a2 2 0 100-4 2 2 0 000 4z"/></svg> <span>LinkedIn</span> </a> <button class="share-btn copy-link" onclick="navigator.clipboard.writeText('https://rankanddiscover.com/gilded-spatula-s-2026-seo-survival-guide/').then(function(){this.querySelector('span').textContent='Copied!'}.bind(this))"> <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg> <span>Copy Link</span> </button> </div> <div class="article-feedback" id="article-feedback"> <span class="feedback-question">Was this article helpful?</span> <button class="feedback-btn feedback-yes" data-vote="yes" aria-label="Yes"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 9V5a3 3 0 00-3-3l-4 9v11h11.28a2 2 0 002-1.7l1.38-9a2 2 0 00-2-2.3H14z"/><path d="M7 22H4a2 2 0 01-2-2v-7a2 2 0 012-2h3"/></svg> Yes </button> <button class="feedback-btn feedback-no" data-vote="no" aria-label="No"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 15v4a3 3 0 003 3l4-9V2H5.72a2 2 0 00-2 1.7l-1.38 9a2 2 0 002 2.3H10z"/><path d="M17 2h2.67A2.31 2.31 0 0122 4v7a2.31 2.31 0 01-2.33 2H17"/></svg> No </button> </div> <script> (function(){ var fb = document.getElementById('article-feedback'); if(!fb) return; fb.querySelectorAll('.feedback-btn').forEach(function(btn){ btn.addEventListener('click', function(){ var vote = this.dataset.vote; fetch('/wp-json/satellite/v1/feedback', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({post_id:13209,vote:vote}) }); fb.innerHTML = '<span class="feedback-thanks">Thanks for your feedback!</span>'; }); }); })(); </script> <div class="author-bio"> <div class="author-bio-avatar"> <img fetchpriority="low" loading="lazy" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/rankanddkaimatsumoto-headshot-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/rankanddkaimatsumoto-headshot-150x150.png 2x' class='avatar avatar-72 photo' height='72' width='72' decoding='async'/> </div> <div class="author-bio-info"> <h4 class="author-bio-name"> <a href="https://rankanddiscover.com/author/rankanddkaimatsumoto/"> Kai Matsumoto </a> </h4> <span class="author-bio-title">Digital Marketing Strategist</span> <span class="author-bio-credentials">MBA, University of California, Berkeley; Google Ads Certified; Bing Ads Accredited Professional</span> <p class="author-bio-description">Kai Matsumoto is a seasoned Digital Marketing Strategist with 15 years of experience specializing in advanced SEO and SEM strategies. As the former Head of Search at Horizon Digital Group, he spearheaded campaigns that consistently delivered double-digit growth in organic traffic and conversion rates for Fortune 500 clients. Kai is particularly adept at leveraging AI-driven analytics for predictive keyword modeling and competitive intelligence. His insights have been featured in 'Search Engine Journal,' and he is recognized for his groundbreaking work in semantic search optimization</p> <div class="author-bio-links"> <a href="https://skillshop.withgoogle.com/" target="_blank" rel="noopener noreferrer" class="author-link-badge"> Credentials </a> <span class="author-experience">15+ years experience</span> </div> </div> </div> </div> <aside class="single-post-sidebar"> <div class="sidebar-sticky"> <div class="sidebar-share"> <span class="sidebar-share-label">Share</span> <div class="sidebar-share-icons"> <a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Frankanddiscover.com%2Fgilded-spatula-s-2026-seo-survival-guide%2F" target="_blank" rel="noopener noreferrer" class="sidebar-share-icon facebook" aria-label="Facebook"> <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"/></svg> </a> <a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Frankanddiscover.com%2Fgilded-spatula-s-2026-seo-survival-guide%2F&text=Gilded+Spatula%26%238217%3Bs+2026+SEO+Survival+Guide" target="_blank" rel="noopener noreferrer" class="sidebar-share-icon twitter" aria-label="Twitter"> <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg> </a> <a href="https://pinterest.com/pin/create/button/?url=https%3A%2F%2Frankanddiscover.com%2Fgilded-spatula-s-2026-seo-survival-guide%2F&description=Gilded+Spatula%26%238217%3Bs+2026+SEO+Survival+Guide" target="_blank" rel="noopener noreferrer" class="sidebar-share-icon pinterest" aria-label="Pinterest"> <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.373 0 0 5.372 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738a.36.36 0 01.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.632-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z"/></svg> </a> <a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Frankanddiscover.com%2Fgilded-spatula-s-2026-seo-survival-guide%2F&title=Gilded+Spatula%26%238217%3Bs+2026+SEO+Survival+Guide" target="_blank" rel="noopener noreferrer" class="sidebar-share-icon linkedin" aria-label="LinkedIn"> <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M16 8a6 6 0 016 6v7h-4v-7a2 2 0 00-2-2 2 2 0 00-2 2v7h-4v-7a6 6 0 016-6zM2 9h4v12H2zM4 6a2 2 0 100-4 2 2 0 000 4z"/></svg> </a> </div> </div> <div class="sidebar-top-posts"> <h3 class="sidebar-section-title">Top Posts</h3> <a href="https://rankanddiscover.com/aeo-marketing-data-automation-for-2026-success/" class="sidebar-post-card"> <div class="sidebar-post-thumb"> <img width="300" height="200" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/aeo-marketing-data-automation-for-2026-success-featured-300x200.webp?v=1773617301" class="attachment-satellite-thumb size-satellite-thumb wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/aeo-marketing-data-automation-for-2026-success-featured-300x200.webp?v=1773617301 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/aeo-marketing-data-automation-for-2026-success-featured-600x400.webp?v=1773617301 600w" sizes="auto, (max-width: 300px) 100vw, 300px" /> </div> <div class="sidebar-post-info"> <h4 class="sidebar-post-title">AEO Marketing: Data & Automation for 2026 Success</h4> <div class="sidebar-post-meta"> <time datetime="2026-03-15T23:28:21+00:00">15/03/2026</time> <span class="sidebar-post-views">148 Views</span> </div> </div> </a> <a href="https://rankanddiscover.com/ai-search-visibility-dominate-2026-with-brightedge/" class="sidebar-post-card"> <div class="sidebar-post-thumb"> <img width="300" height="200" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/ai-search-visibility-dominate-2026-with-brightedge-featured-300x200.webp?v=1776203161" class="attachment-satellite-thumb size-satellite-thumb wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/ai-search-visibility-dominate-2026-with-brightedge-featured-300x200.webp?v=1776203161 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/ai-search-visibility-dominate-2026-with-brightedge-featured-600x400.webp?v=1776203161 600w" sizes="auto, (max-width: 300px) 100vw, 300px" /> </div> <div class="sidebar-post-info"> <h4 class="sidebar-post-title">AI Search Visibility: Dominate 2026 with BrightEdge</h4> <div class="sidebar-post-meta"> <time datetime="2026-04-13T20:24:23+00:00">13/04/2026</time> <span class="sidebar-post-views">142 Views</span> </div> </div> </a> <a href="https://rankanddiscover.com/keyword-strategy-in-2026-marketings-new-rules/" class="sidebar-post-card"> <div class="sidebar-post-thumb"> <img width="300" height="200" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/keyword-strategy-in-2026-marketing-s-new-rules-featured-300x200.webp?v=1773833559" class="attachment-satellite-thumb size-satellite-thumb wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/keyword-strategy-in-2026-marketing-s-new-rules-featured-300x200.webp?v=1773833559 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/keyword-strategy-in-2026-marketing-s-new-rules-featured-600x400.webp?v=1773833559 600w" sizes="auto, (max-width: 300px) 100vw, 300px" /> </div> <div class="sidebar-post-info"> <h4 class="sidebar-post-title">Keyword Strategy in 2026: Marketing’s New Rules</h4> <div class="sidebar-post-meta"> <time datetime="2026-03-18T11:32:39+00:00">18/03/2026</time> <span class="sidebar-post-views">136 Views</span> </div> </div> </a> </div> </div> </aside> </div> <nav class="post-navigation"> <a href="https://rankanddiscover.com/2026-marketing-llm-visibility-and-3-content-pillars/" class="post-nav-link prev"> <div class="post-nav-label">« Previous</div> <div class="post-nav-title">2026 Marketing: LLM Visibility & 3 Content Pillars</div> </a> <div></div> </nav> </article> <section class="related-posts"> <div class="section-header"> <h2 class="section-title">Related Articles</h2> <div class="carousel-nav"> <button class="carousel-btn carousel-prev" aria-label="Previous">‹</button> <button class="carousel-btn carousel-next" aria-label="Next">›</button> </div> </div> <div class="related-carousel" id="related-carousel"> <div class="carousel-track"> <article class="article-card"> <a href="https://rankanddiscover.com/91-fail-smart-link-building-for-2026/" class="article-card-image" aria-label="91% Fail: Smart Link Building for 2026"> <img width="768" height="419" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/91-fail-smart-link-building-for-2026-featured-768x419.webp?v=1782760893" class="attachment-medium_large size-medium_large wp-post-image" alt="" loading="lazy" decoding="async" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/91-fail-smart-link-building-for-2026-featured-768x419.webp 768w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/91-fail-smart-link-building-for-2026-featured-300x164.webp 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/91-fail-smart-link-building-for-2026-featured-1024x559.webp 1024w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/91-fail-smart-link-building-for-2026-featured.webp 1408w" sizes="auto, (max-width: 768px) 100vw, 768px" /> </a> <div class="article-card-body"> <a href="https://rankanddiscover.com/category/seo-sem/" class="article-card-category" style="color:#334155"> SEO & SEM </a> <h3 class="article-card-title"> <a href="https://rankanddiscover.com/91-fail-smart-link-building-for-2026/">91% Fail: Smart Link Building for 2026</a> </h3> <p class="article-card-excerpt">Listen to this article · 9 min listen1.0xAudio playback not supported in this browser. Key Takeaways Prioritize niche-specific, high-authority domains for link acquisition over general high-DA sites,…</p> <div class="article-card-meta"> <img fetchpriority="low" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/rankanddkeonvelasquez-headshot-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/rankanddkeonvelasquez-headshot-150x150.png 2x' class='avatar avatar-22 photo' height='22' width='22' loading='lazy' decoding='async'/> <span class="author-name">Keon Velasquez</span> <span class="dot">·</span> <time datetime="2026-06-29T17:23:50+00:00">29/06/2026</time> <span class="dot">·</span> <span>7 min read</span> </div> </div> </article> <article class="article-card"> <a href="https://rankanddiscover.com/link-building-in-2026-3-8x-more-backlinks/" class="article-card-image" aria-label="Link Building in 2026: 3.8X More Backlinks"> <img width="768" height="419" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/link-building-in-2026-3-8x-more-backlinks-featured-768x419.webp?v=1782787429" class="attachment-medium_large size-medium_large wp-post-image" alt="" loading="lazy" decoding="async" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/link-building-in-2026-3-8x-more-backlinks-featured-768x419.webp 768w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/link-building-in-2026-3-8x-more-backlinks-featured-300x164.webp 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/link-building-in-2026-3-8x-more-backlinks-featured-1024x559.webp 1024w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/link-building-in-2026-3-8x-more-backlinks-featured.webp 1408w" sizes="auto, (max-width: 768px) 100vw, 768px" /> </a> <div class="article-card-body"> <a href="https://rankanddiscover.com/category/seo-sem/" class="article-card-category" style="color:#334155"> SEO & SEM </a> <h3 class="article-card-title"> <a href="https://rankanddiscover.com/link-building-in-2026-3-8x-more-backlinks/">Link Building in 2026: 3.8X More Backlinks</a> </h3> <p class="article-card-excerpt">Listen to this article · 9 min listen1.0xAudio playback not supported in this browser. Key Takeaways Websites with more backlinks consistently rank higher in search engine results,…</p> <div class="article-card-meta"> <img fetchpriority="low" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/rankanddkaimatsumoto-headshot-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/rankanddkaimatsumoto-headshot-150x150.png 2x' class='avatar avatar-22 photo' height='22' width='22' loading='lazy' decoding='async'/> <span class="author-name">Kai Matsumoto</span> <span class="dot">·</span> <time datetime="2026-06-29T14:24:56+00:00">29/06/2026</time> <span class="dot">·</span> <span>7 min read</span> </div> </div> </article> <article class="article-card"> <a href="https://rankanddiscover.com/aeo-marketing-data-automation-for-2026-success/" class="article-card-image" aria-label="AEO Marketing: Data & Automation for 2026 Success"> <img width="768" height="419" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/aeo-marketing-data-automation-for-2026-success-featured-768x419.webp?v=1773617301" class="attachment-medium_large size-medium_large wp-post-image" alt="" loading="lazy" decoding="async" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/aeo-marketing-data-automation-for-2026-success-featured-768x419.webp?v=1773617301 768w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/aeo-marketing-data-automation-for-2026-success-featured-300x164.webp?v=1773617301 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/aeo-marketing-data-automation-for-2026-success-featured-1024x559.webp?v=1773617301 1024w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/aeo-marketing-data-automation-for-2026-success-featured.webp?v=1773617301 1408w" sizes="auto, (max-width: 768px) 100vw, 768px" /> </a> <div class="article-card-body"> <a href="https://rankanddiscover.com/category/marketing-tech/" class="article-card-category" style="color:#b13a1d"> Marketing Tech </a> <h3 class="article-card-title"> <a href="https://rankanddiscover.com/aeo-marketing-data-automation-for-2026-success/">AEO Marketing: Data & Automation for 2026 Success</a> </h3> <p class="article-card-excerpt">Listen to this article · 7 min listen1.0xAudio playback not supported in this browser.Are you ready to take your aeo strategies to the next level? In the…</p> <div class="article-card-meta"> <img fetchpriority="low" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankandddavidlee-headshot-1-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankandddavidlee-headshot-1-150x150.png 2x' class='avatar avatar-22 photo' height='22' width='22' loading='lazy' decoding='async'/> <span class="author-name">Amanda Gill</span> <span class="dot">·</span> <time datetime="2026-03-15T23:28:21+00:00">15/03/2026</time> <span class="dot">·</span> <span>6 min read</span> </div> </div> </article> <article class="article-card"> <a href="https://rankanddiscover.com/ai-search-visibility-dominate-2026-with-brightedge/" class="article-card-image" aria-label="AI Search Visibility: Dominate 2026 with BrightEdge"> <img width="768" height="419" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/ai-search-visibility-dominate-2026-with-brightedge-featured-768x419.webp?v=1776203161" class="attachment-medium_large size-medium_large wp-post-image" alt="" loading="lazy" decoding="async" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/ai-search-visibility-dominate-2026-with-brightedge-featured-768x419.webp?v=1776203161 768w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/ai-search-visibility-dominate-2026-with-brightedge-featured-300x164.webp?v=1776203161 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/ai-search-visibility-dominate-2026-with-brightedge-featured-1024x559.webp?v=1776203161 1024w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/ai-search-visibility-dominate-2026-with-brightedge-featured.webp?v=1776203161 1408w" sizes="auto, (max-width: 768px) 100vw, 768px" /> </a> <div class="article-card-body"> <a href="https://rankanddiscover.com/category/marketing-analytics/" class="article-card-category" style="color:#0369a1"> Marketing Analytics </a> <h3 class="article-card-title"> <a href="https://rankanddiscover.com/ai-search-visibility-dominate-2026-with-brightedge/">AI Search Visibility: Dominate 2026 with BrightEdge</a> </h3> <p class="article-card-excerpt">Listen to this article · 10 min listen1.0xAudio playback not supported in this browser.Are you struggling to make your mark in the crowded digital space? Mastering AI…</p> <div class="article-card-meta"> <img fetchpriority="low" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankanddjohnsmith-headshot-3-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankanddjohnsmith-headshot-3-150x150.png 2x' class='avatar avatar-22 photo' height='22' width='22' loading='lazy' decoding='async'/> <span class="author-name">Amanda Davis</span> <span class="dot">·</span> <time datetime="2026-04-13T20:24:23+00:00">13/04/2026</time> <span class="dot">·</span> <span>8 min read</span> </div> </div> </article> <article class="article-card"> <a href="https://rankanddiscover.com/2026-marketing-llm-visibility-and-3-content-pillars/" class="article-card-image" aria-label="2026 Marketing: LLM Visibility & 3 Content Pillars"> <img width="768" height="419" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/llm-search-is-your-brand-visible-featured-768x419.webp?v=1776685237" class="attachment-medium_large size-medium_large wp-post-image" alt="" loading="lazy" decoding="async" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/llm-search-is-your-brand-visible-featured-768x419.webp?v=1776685237 768w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/llm-search-is-your-brand-visible-featured-300x164.webp?v=1776685237 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/llm-search-is-your-brand-visible-featured-1024x559.webp?v=1776685237 1024w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/04/llm-search-is-your-brand-visible-featured.webp?v=1776685237 1408w" sizes="auto, (max-width: 768px) 100vw, 768px" /> </a> <div class="article-card-body"> <a href="https://rankanddiscover.com/category/digital-marketing/" class="article-card-category" style="color:#9a3412"> Digital Marketing </a> <h3 class="article-card-title"> <a href="https://rankanddiscover.com/2026-marketing-llm-visibility-and-3-content-pillars/">2026 Marketing: LLM Visibility & 3 Content Pillars</a> </h3> <p class="article-card-excerpt">Listen to this article · 11 min listen1.0xAudio playback not supported in this browser.The digital marketing arena of 2026 demands more than just a website; it requires…</p> <div class="article-card-meta"> <img fetchpriority="low" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankandddavidlee-headshot-1-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankandddavidlee-headshot-1-150x150.png 2x' class='avatar avatar-22 photo' height='22' width='22' loading='lazy' decoding='async'/> <span class="author-name">Amanda Gill</span> <span class="dot">·</span> <time datetime="2026-06-30T02:15:26+00:00">30/06/2026</time> <span class="dot">·</span> <span>9 min read</span> </div> </div> </article> <article class="article-card"> <a href="https://rankanddiscover.com/video-tsunami-80-traffic-by-2028/" class="article-card-image" aria-label="Video Tsunami: 80% Traffic by 2028?"> <img width="768" height="419" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/video-tsunami-80-traffic-by-2028-featured-768x419.webp?v=1782787390" class="attachment-medium_large size-medium_large wp-post-image" alt="" loading="lazy" decoding="async" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/video-tsunami-80-traffic-by-2028-featured-768x419.webp 768w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/video-tsunami-80-traffic-by-2028-featured-300x164.webp 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/video-tsunami-80-traffic-by-2028-featured-1024x559.webp 1024w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/06/video-tsunami-80-traffic-by-2028-featured.webp 1408w" sizes="auto, (max-width: 768px) 100vw, 768px" /> </a> <div class="article-card-body"> <a href="https://rankanddiscover.com/category/content-strategy/" class="article-card-category" style="color:#be185d"> Content Strategy </a> <h3 class="article-card-title"> <a href="https://rankanddiscover.com/video-tsunami-80-traffic-by-2028/">Video Tsunami: 80% Traffic by 2028?</a> </h3> <p class="article-card-excerpt">Listen to this article · 9 min listen1.0xAudio playback not supported in this browser.Did you know that by 2028, over 80% of all internet traffic will be…</p> <div class="article-card-meta"> <img fetchpriority="low" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankanddmariagarcia-headshot-1-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankanddmariagarcia-headshot-1-150x150.png 2x' class='avatar avatar-22 photo' height='22' width='22' loading='lazy' decoding='async'/> <span class="author-name">Amanda Erickson</span> <span class="dot">·</span> <time datetime="2026-06-29T15:09:11+00:00">29/06/2026</time> <span class="dot">·</span> <span>7 min read</span> </div> </div> </article> <article class="article-card"> <a href="https://rankanddiscover.com/seo-in-2026-ai-discoverability-and-marketing/" class="article-card-image" aria-label="SEO in 2026: AI, Discoverability, and Marketing"> <img width="768" height="419" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/seo-in-2026-ai-discoverability-and-marketing-featured-768x419.webp?v=1773735437" class="attachment-medium_large size-medium_large wp-post-image" alt="" loading="lazy" decoding="async" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/seo-in-2026-ai-discoverability-and-marketing-featured-768x419.webp?v=1773735437 768w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/seo-in-2026-ai-discoverability-and-marketing-featured-300x164.webp?v=1773735437 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/seo-in-2026-ai-discoverability-and-marketing-featured-1024x559.webp?v=1773735437 1024w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/seo-in-2026-ai-discoverability-and-marketing-featured.webp?v=1773735437 1408w" sizes="auto, (max-width: 768px) 100vw, 768px" /> </a> <div class="article-card-body"> <a href="https://rankanddiscover.com/category/seo-sem/" class="article-card-category" style="color:#334155"> SEO & SEM </a> <h3 class="article-card-title"> <a href="https://rankanddiscover.com/seo-in-2026-ai-discoverability-and-marketing/">SEO in 2026: AI, Discoverability, and Marketing</a> </h3> <p class="article-card-excerpt">Listen to this article · 9 min listen1.0xAudio playback not supported in this browser.Understanding the Evolving Search Landscape The internet has evolved far beyond simple keyword matching.…</p> <div class="article-card-meta"> <img fetchpriority="low" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankanddjanedoe-headshot-1-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankanddjanedoe-headshot-1-150x150.png 2x' class='avatar avatar-22 photo' height='22' width='22' loading='lazy' decoding='async'/> <span class="author-name">Amanda Clarke</span> <span class="dot">·</span> <time datetime="2026-03-17T08:17:18+00:00">17/03/2026</time> <span class="dot">·</span> <span>7 min read</span> </div> </div> </article> <article class="article-card"> <a href="https://rankanddiscover.com/keyword-strategy-2026-dominate-search-marketing/" class="article-card-image" aria-label="Keyword Strategy 2026: Dominate Search & Marketing"> <img width="768" height="419" src="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/keyword-strategy-2026-dominate-search-marketing-featured-768x419.webp?v=1773640642" class="attachment-medium_large size-medium_large wp-post-image" alt="" loading="lazy" decoding="async" srcset="https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/keyword-strategy-2026-dominate-search-marketing-featured-768x419.webp?v=1773640642 768w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/keyword-strategy-2026-dominate-search-marketing-featured-300x164.webp?v=1773640642 300w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/keyword-strategy-2026-dominate-search-marketing-featured-1024x559.webp?v=1773640642 1024w, https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/keyword-strategy-2026-dominate-search-marketing-featured.webp?v=1773640642 1408w" sizes="auto, (max-width: 768px) 100vw, 768px" /> </a> <div class="article-card-body"> <a href="https://rankanddiscover.com/category/seo-sem/" class="article-card-category" style="color:#334155"> SEO & SEM </a> <h3 class="article-card-title"> <a href="https://rankanddiscover.com/keyword-strategy-2026-dominate-search-marketing/">Keyword Strategy 2026: Dominate Search & Marketing</a> </h3> <p class="article-card-excerpt">Listen to this article · 8 min listen1.0xAudio playback not supported in this browser.The Complete Guide to Keyword Strategy in 2026 Are you struggling to get your…</p> <div class="article-card-meta"> <img fetchpriority="low" alt='' src='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankanddjanedoe-headshot-1-150x150.png' srcset='https://rankanddiscover.com/wp-content/uploads/sites/30/2026/03/rankanddjanedoe-headshot-1-150x150.png 2x' class='avatar avatar-22 photo' height='22' width='22' loading='lazy' decoding='async'/> <span class="author-name">Amanda Clarke</span> <span class="dot">·</span> <time datetime="2026-03-16T05:57:22+00:00">16/03/2026</time> <span class="dot">·</span> <span>7 min read</span> </div> </div> </article> </div> </div> </section> <script> (function(){ var track = document.querySelector('.carousel-track'); if(!track) return; var prev = document.querySelector('.carousel-prev'); var next = document.querySelector('.carousel-next'); var cardW = track.querySelector('.article-card'); if(!cardW) return; var scrollAmt = cardW.offsetWidth + 24; if(prev) prev.addEventListener('click', function(){ track.scrollBy({left:-scrollAmt,behavior:'smooth'}); }); if(next) next.addEventListener('click', function(){ track.scrollBy({left:scrollAmt,behavior:'smooth'}); }); })(); </script> </main> </div> </div><!-- .container --> <footer class="site-footer" role="contentinfo"> <div class="footer-main"> <div class="footer-col footer-about"> <div class="widget"> <h3 class="widget-title">Rank & Discover</h3> <p>Expert insights, guides, and stories about marketing</p> </div> </div> <div class="footer-col"> <div class="widget"> <h3 class="widget-title">Categories</h3> <ul> <li class="cat-item cat-item-25"><a href="https://rankanddiscover.com/category/campaign-insights/">Campaign Insights</a> </li> <li class="cat-item cat-item-19"><a href="https://rankanddiscover.com/category/content-strategy/">Content Strategy</a> </li> <li class="cat-item cat-item-21"><a href="https://rankanddiscover.com/category/customer-experience/">Customer Experience</a> </li> <li class="cat-item cat-item-18"><a href="https://rankanddiscover.com/category/digital-marketing/">Digital Marketing</a> </li> <li class="cat-item cat-item-20"><a href="https://rankanddiscover.com/category/marketing-analytics/">Marketing Analytics</a> </li> <li class="cat-item cat-item-24"><a href="https://rankanddiscover.com/category/marketing-tech/">Marketing Tech</a> </li> <li class="cat-item cat-item-23"><a href="https://rankanddiscover.com/category/seo-sem/">SEO & SEM</a> </li> <li class="cat-item cat-item-22"><a href="https://rankanddiscover.com/category/social-media/">Social Media</a> </li> </ul> </div> </div> <div class="footer-col"> <div class="widget"> <h3 class="widget-title">Quick Links</h3> <ul> <li><a href="https://rankanddiscover.com/">Home</a></li> <li><a href="https://rankanddiscover.com/editorial-standards/">Editorial Standards</a></li> <li><a href="https://rankanddiscover.com/about/">About</a></li> <li><a href="https://rankanddiscover.com/contact/">Contact</a></li> <li><a href="https://rankanddiscover.com/privacy-policy/">Privacy Policy</a></li> <li><a href="https://rankanddiscover.com/terms-of-service/">Terms of Service</a></li> </ul> </div> </div> <div class="footer-col footer-col-authors"> <div class="widget"> <h3 class="widget-title">Our Authors</h3> <ul class="footer-authors-list" style="columns: 2; -webkit-columns: 2; -moz-columns: 2; column-gap: 1.5rem; padding-left: 0; list-style: none; margin: 0;"> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddjamilaowusu/">Deborah Ferguson</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddrenatachung/">Debbie Henderson</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddmarcuschen/">Dawn Ross</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddmateochavez/">Debbie Cline</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddmarcuskim/">Debra Cook</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddkeishamontgomery/">Debra Christian</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddjohnsmith/">Amanda Davis</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddseraphinacruz/">Seraphina Cruz</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddanyasharma/">Dawn Coleman</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddjenniferobrien/">Jennifer Obrien</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddjamaladeyemi/">Deanna Mitchell</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddrorychung/">Deborah Lynch</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddsashanguyen/">Debra Clark</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddrohanpatel/">Dean Morris</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddmariagarcia/">Amanda Erickson</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddkiarandlovu/">Kiara Ndlovu</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddjanedoe/">Amanda Clarke</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddzarakhan/">Deanna Hicks</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddjennifermurray/">Jennifer Murray</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddjaviermontoya/">David Willis</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddkeonvelasquez/">Keon Velasquez</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankandddevinchandra/">Deborah Santos</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddashleywilson/">Anne Merritt</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankandddavidlee/">Amanda Gill</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddkevinbrown/">Anne Hart</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddemilyjohnson/">Anne Reid</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddkeatonadetunji/">Keaton Adetunji</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddlenaokoro/">Debra Chavez</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddjennifermcdonald/">Jennifer Mcdonald</a></li> <li style="break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; padding: 2px 0;"><a href="https://rankanddiscover.com/author/rankanddkeishadubois/">Deanna Barry</a></li> </ul> </div> </div> </div> <div class="footer-bottom"> <div class="footer-bottom-inner"> <div class="footer-copyright"> © 2026 Rank & Discover. All rights reserved. </div> <nav class="footer-nav" role="navigation"> </nav> </div> </div> </footer> <script id="sat-tts-script"> (function(){ if (!('speechSynthesis' in window) || !('SpeechSynthesisUtterance' in window)) { document.querySelectorAll('.sat-tts-player').forEach(function(el){ el.setAttribute('data-state', 'unsupported'); var t = el.querySelector('.sat-tts-title-text'); var i18n = el.querySelector('.sat-tts-i18n'); if (t && i18n) t.textContent = i18n.dataset.unsupported; }); return; } var player = document.querySelector('.sat-tts-player[data-sat-tts]'); if (!player) return; var contentRoot = document.querySelector('.post-content') || document.querySelector('article .single-post-main') || document.querySelector('article'); if (!contentRoot) return; var toggleBtn = player.querySelector('.sat-tts-toggle'); var rateBtn = player.querySelector('.sat-tts-rate'); var titleText = player.querySelector('.sat-tts-title-text'); var progressEl = player.querySelector('.sat-tts-progress-fill'); var i18n = player.querySelector('.sat-tts-i18n'); var STORAGE_KEY = 'sat_tts_v1_' + (location.pathname || '/'); var RATE_CYCLE = [1, 1.25, 1.5, 2, 0.85]; // ── Build chunks ───────────────────────────────────────────── // Strip HTML to a clean, sequential text array. We skip elements // that read awkwardly aloud (figures, embedded video/audio, the // related-callout sidebars, FAQ schema-heavy sections, code). function buildChunks(root) { var clone = root.cloneNode(true); // Remove things we never want spoken. clone.querySelectorAll( 'script,style,figure,iframe,video,audio,svg,noscript,' + 'aside,.related-callout,.sidebar-share,.sat-tts-player,' + '.article-feedback,.author-bio,.post-tags,.read-next-bar,' + '.post-navigation,.related-posts,form,nav,.toc-container' ).forEach(function(n){ n.parentNode && n.parentNode.removeChild(n); }); var blockSel = 'h1,h2,h3,h4,h5,h6,p,li,blockquote,td,th,dt,dd'; var blocks = clone.querySelectorAll(blockSel); var chunks = []; blocks.forEach(function(b){ var t = (b.textContent || '').replace(/\s+/g, ' ').trim(); if (!t) return; // Long paragraphs: break on sentence boundaries so Chrome // doesn't silently drop after ~15s of a single utterance. if (t.length > 220) { var sentences = t.match(/[^.!?]+[.!?]+(?:\s|$)|[^.!?]+$/g) || [t]; var buf = ''; sentences.forEach(function(s){ s = s.trim(); if (!s) return; if ((buf + ' ' + s).trim().length > 220 && buf) { chunks.push(buf.trim()); buf = s; } else { buf = (buf ? buf + ' ' : '') + s; } }); if (buf.trim()) chunks.push(buf.trim()); } else { chunks.push(t); } }); return chunks; } var chunks = buildChunks(contentRoot); if (chunks.length === 0) return; var totalChars = chunks.reduce(function(a,c){ return a + c.length; }, 0); // ── State machine ─────────────────────────────────────────── var state = { playing: false, paused: false, chunkIndex: 0, charsSpoken: 0, rate: 1, voice: null, currentUtter: null, }; try { var saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || 'null'); if (saved && typeof saved.chunkIndex === 'number' && saved.chunkIndex < chunks.length) { state.chunkIndex = saved.chunkIndex; state.charsSpoken = saved.charsSpoken || 0; state.rate = saved.rate || 1; } } catch (e) {} applyRate(state.rate); updateProgress(); // ── Voice selection ───────────────────────────────────────── // speechSynthesis populates voices async on most browsers. The // picker: // 1. filters by html lang prefix (en/es/...) // 2. drops novelty/character voices (Apple ships ~30 of them // and they sort BEFORE the natural ones on macOS, which is // why an unguarded pool[0] fallback ends up reading // Spanish articles in Eddy/Flo/Reed instead of Mónica) // 3. ranks survivors by an explicit per-language preference // list of high-quality voices, with a fallback that prefers // `localService` (built-in premium) over remote voices. var NOVELTY_NAME_RE = /^(Albert|Bad News|Bahh|Bells|Boing|Bubbles|Cellos|Deranged|Good News|Hysterical|Pipe Organ|Trinoids|Whisper|Wobble|Zarvox|Eddy|Flo|Grandma|Grandpa|Jester|Junior|Kathy|Organ|Princess|Ralph|Reed|Rocko|Sandy|Shelley|Superstar|Vicki|Victoria|Bahh|Boing|Cellos)\b/i; var PREFERRED_BY_LANG = { es: [ // macOS / iOS premium Spanish voices (best quality) /^M[oó]nica/i, // es-ES, very natural /^Paulina/i, // es-MX, very natural /^Jorge\b/i, // es-ES /^Diego\b/i, // es-AR /^Juan\b/i, // Microsoft Edge / Windows neural Spanish voices /Microsoft.*\b(Elvira|Dalia|Alvaro|Jorge|Helena|Sabina)\b.*Online/i, /Microsoft.*\b(Elvira|Dalia|Alvaro)\b/i, // Google Spanish (Chrome desktop, Android) /^Google\s+espa[ñn]ol(?:\s+de\s+(?:M[eé]xico|Estados Unidos))?$/i, /^Google\s+espa[ñn]ol/i, ], en: [ /^Google\s.*(US|UK|English)/i, /^Microsoft.*(Aria|Jenny|Guy|Ryan|Davis)\b.*Online/i, /^Microsoft.*(Aria|Jenny|Guy|Ryan|Davis)\b/i, /^Samantha$/i, /^Alex$/i, /English/i, ], }; function scoreVoice(v, preferredList) { for (var i = 0; i < preferredList.length; i++) { if (preferredList[i].test(v.name)) { // Earlier list entries score higher. localService gets a // small bump so a built-in voice wins over a remote one // when both match the same pattern. return 1000 - i * 10 + (v.localService ? 1 : 0); } } // No name match — still prefer non-novelty + localService. return (v.localService ? 1 : 0); } function pickVoice() { var voices = speechSynthesis.getVoices() || []; if (voices.length === 0) return null; var lang = (document.documentElement.lang || 'en').toLowerCase().split('-')[0]; var pool = voices.filter(function(v){ return (v.lang || '').toLowerCase().indexOf(lang) === 0; }); if (pool.length === 0) pool = voices; // Strip novelty voices unless that leaves us with nothing. var filtered = pool.filter(function(v){ return !NOVELTY_NAME_RE.test(v.name); }); if (filtered.length > 0) pool = filtered; var preferredList = PREFERRED_BY_LANG[lang] || PREFERRED_BY_LANG.en; var best = null, bestScore = -Infinity; pool.forEach(function(v){ var s = scoreVoice(v, preferredList); if (s > bestScore) { bestScore = s; best = v; } }); return best || pool[0]; } if (typeof speechSynthesis.addEventListener === 'function') { speechSynthesis.addEventListener('voiceschanged', function(){ state.voice = pickVoice(); }); } state.voice = pickVoice(); // ── Utterance queue ───────────────────────────────────────── function speakNext() { if (state.chunkIndex >= chunks.length) { stopAll(true); return; } var u = new SpeechSynthesisUtterance(chunks[state.chunkIndex]); u.rate = state.rate; u.pitch = 1; u.volume = 1; // Setting `lang` explicitly is what triggers the Spanish // synthesis backend on Chrome/Edge (which shipped neural // Spanish voices that aren't always exposed via getVoices // until referenced). When `voice` is set we prefer the // voice's own lang to avoid a mismatch. if (state.voice) { u.voice = state.voice; if (state.voice.lang) u.lang = state.voice.lang; } else { u.lang = (document.documentElement.lang || 'en'); } u.onend = function() { if (!state.playing) return; state.charsSpoken += chunks[state.chunkIndex].length; state.chunkIndex += 1; persist(); updateProgress(); if (state.chunkIndex < chunks.length) { speakNext(); } else { stopAll(true); } }; u.onerror = function(ev) { if (ev && ev.error === 'interrupted') return; state.playing = false; state.paused = false; state.currentUtter = null; renderState(); }; u.onboundary = function(ev) { if (ev && typeof ev.charIndex === 'number') { var partial = state.charsSpoken + Math.min(ev.charIndex, chunks[state.chunkIndex].length); var pct = Math.min(100, (partial / totalChars) * 100); progressEl.style.width = pct + '%'; } }; state.currentUtter = u; speechSynthesis.speak(u); } function play() { if (state.paused) { speechSynthesis.resume(); state.paused = false; state.playing = true; renderState(); return; } // Some browsers leave the queue stuck after a previous error; // cancel before starting fresh. try { speechSynthesis.cancel(); } catch (e) {} state.playing = true; state.paused = false; renderState(); speakNext(); } function pause() { if (!state.playing) return; try { speechSynthesis.pause(); } catch (e) {} state.paused = true; state.playing = false; persist(); renderState(); } function stopAll(reset) { try { speechSynthesis.cancel(); } catch (e) {} state.playing = false; state.paused = false; state.currentUtter = null; if (reset) { state.chunkIndex = 0; state.charsSpoken = 0; progressEl.style.width = '0%'; try { localStorage.removeItem(STORAGE_KEY); } catch (e) {} } renderState(); } // ── Rate cycle ───────────────────────────────────────────── function applyRate(r) { state.rate = r; rateBtn.textContent = r.toFixed(2).replace(/\.?0+$/, '') + 'x'; persist(); } rateBtn.addEventListener('click', function(){ var i = RATE_CYCLE.indexOf(state.rate); var next = RATE_CYCLE[(i + 1) % RATE_CYCLE.length]; applyRate(next); // If currently playing, restart the current chunk at the // new rate (Web Speech doesn't let you change rate mid-utter). if (state.playing && state.currentUtter) { stopAll(false); state.playing = true; renderState(); speakNext(); } }); toggleBtn.addEventListener('click', function(){ if (state.playing) { pause(); } else { play(); } }); // ── Chrome 15-second cutoff workaround ───────────────────── // Chrome stops Web Speech after ~15s of continuous output. We // ping pause+resume every 10s while playing to keep the queue // alive. Harmless on browsers that don't need it. setInterval(function(){ if (state.playing && !state.paused) { try { speechSynthesis.pause(); speechSynthesis.resume(); } catch (e) {} } }, 10000); // ── Persistence + UI ─────────────────────────────────────── function persist() { try { localStorage.setItem(STORAGE_KEY, JSON.stringify({ chunkIndex: state.chunkIndex, charsSpoken: state.charsSpoken, rate: state.rate, })); } catch (e) {} } function updateProgress() { var pct = totalChars ? Math.min(100, (state.charsSpoken / totalChars) * 100) : 0; progressEl.style.width = pct + '%'; } function renderState() { if (!i18n) return; if (state.playing) { player.setAttribute('data-state', 'playing'); titleText.textContent = i18n.dataset.playing; toggleBtn.setAttribute('aria-label', 'Pause'); } else if (state.paused) { player.setAttribute('data-state', 'paused'); titleText.textContent = i18n.dataset.paused; toggleBtn.setAttribute('aria-label', 'Resume'); } else { player.removeAttribute('data-state'); titleText.textContent = i18n.dataset.listen; toggleBtn.setAttribute('aria-label', 'Play'); } } // ── GA4 listen events ───────────────────────────────────── // Fire a small custom event the first time a visitor presses // play, so we can answer "does the listen button move // engagement?" from the analytics dashboard. var firedFirstPlay = false; toggleBtn.addEventListener('click', function(){ if (firedFirstPlay) return; if (typeof window.gtag === 'function') { try { window.gtag('event', 'tts_listen_play', { event_category: 'engagement', event_label: location.pathname, value: 1, }); } catch (e) {} } firedFirstPlay = true; }); // Stop speech when the visitor leaves the page so it doesn't // continue narrating in the background after navigation. window.addEventListener('beforeunload', function(){ try { speechSynthesis.cancel(); } catch (e) {} }); })(); </script> <script type="speculationrules"> {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/sites/30/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/satellite-theme/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} </script> <script id="satellite-main-js-extra"> var satelliteAjax = {"ajaxurl":"https://rankanddiscover.com/wp-admin/admin-ajax.php","nonce":"21d0ae9886"}; //# sourceURL=satellite-main-js-extra </script> <script src="https://rankanddiscover.com/wp-content/themes/satellite-theme/assets/js/main.js?ver=4.9.0" id="satellite-main-js"></script> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=DM+Mono:wght@400;500&display=swap" onload="this.onload=null;this.rel='stylesheet'"> <noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=DM+Mono:wght@400;500&display=swap"></noscript> <style id="aeo-popup-styles"> #aeo-popup-root { --accent: #E8471A; --accent-dim: #C93C12; --accent-mid: #F07040; --accent-soft: #F9A07A; --card-bg: linear-gradient(105deg, #ffffff 0%, #fff4f0 40%, #ffeee7 70%, #ffffff 100%); --card-fade: #fff8f5; --bar-bg: linear-gradient(105deg, #ffffff 0%, #fff4f0 40%, #ffeee7 70%, #ffffff 100%); --cta-grad: linear-gradient(90deg, #E8471A 0%, #F07040 50%, #E8471A 100%); --cta-text: #ffffff; --shadow-rgb: 232,71,26; --ink: #111111; --ink-soft: #555555; --ink-faint: #999999; --border: #E2E4DC; --banner-h: 88px; /* "Google Sans" is in the stack as the brand fallback for installs that have it locally (e.g. internal Google environments); Inter is the loaded webfont and the de-facto free substitute. */ --font-display: 'Inter', 'Google Sans', system-ui, sans-serif; --font-body: 'Inter', 'Google Sans', system-ui, sans-serif; --font-mono: 'DM Mono', ui-monospace, Menlo, monospace; } #aeo-popup-root, #aeo-popup-root * { box-sizing: border-box; } @keyframes aeoPulse { 0%,100% { opacity:1; transform:scale(1); } 50% { opacity:.4; transform:scale(.7); } } @keyframes aeoCtaShimmer { 0% { background-position:0% 0%; } 50% { background-position:100% 0%; } 100% { background-position:0% 0%; } } @keyframes aeoBannerBreathe{ 0% { background-position:0% 50%; } 50% { background-position:100% 50%; } 100% { background-position:0% 50%; } } @keyframes aeoCardSlideUp { to { transform: translateY(0); opacity: 1; } } @keyframes aeoCardSlideDown{ to { transform: translateY(calc(100% + 32px)); opacity: 0; } } @keyframes aeoBarSlideUp { to { transform: translateY(0); opacity: 1; } } @keyframes aeoScTicker { 0% { transform: translateX(0); } 100% { transform: translateX(-33.3333%); } } /* ── STICKY CARD (bottom-left, initial state) ────────────────────── Default state is hidden -- JS adds .aeo-iframe-ready on the root once the modal iframe has finished loading in the background (or after a safety timeout), so the slide-up coincides with the funnel being click-ready. */ #aeo-popup-root .sticky-card { position: fixed; bottom: 24px; left: 24px; z-index: 9990; width: 340px; border-radius: 16px; overflow: hidden; border: 1px solid var(--border); box-shadow: 0 8px 40px rgba(var(--shadow-rgb),0.15), 0 2px 8px rgba(0,0,0,0.07); background: var(--card-bg); background-size: 300% 300%; transform: translateY(calc(100% + 32px)); opacity: 0; } #aeo-popup-root.aeo-iframe-ready .sticky-card { animation: aeoCardSlideUp 0.6s cubic-bezier(0.22,1,0.36,1) forwards, aeoBannerBreathe 5s ease-in-out 0.6s infinite; } #aeo-popup-root.aeo-skip-card .sticky-card { display: none; } #aeo-popup-root.aeo-lead-done .sticky-card, #aeo-popup-root.aeo-lead-done .sticky-banner { display: none; } #aeo-popup-root .sticky-card.hiding { animation: aeoCardSlideDown 0.4s cubic-bezier(0.4,0,1,1) forwards !important; } /* ── Border Beam ─────────────────────────────────────── A bright accent-coloured "comet" travels around the card perimeter. Implemented as a single ::before pseudo-element: 1. conic-gradient paints the comet (transparent for ~75% of the circle, then a soft -> bright -> soft fade across the last ~100°), 2. mask-composite:exclude cuts the inside out so only a 2px ring remains -- the comet appears to glide along the border, 3. @property animates the gradient's `from` angle so the rotation is on the gradient itself, not via transform (no sub-pixel shimmer, no GPU compositing cost, and the corners stay sharp). Browsers without @property (older Firefox <128, older Safari <16.4) render the gradient statically -- graceful degradation. */ @property --aeo-beam-angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; } #aeo-popup-root .sticky-card::before { content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 2px; background: conic-gradient( from var(--aeo-beam-angle), transparent 0deg, transparent 250deg, var(--accent-soft) 305deg, var(--accent) 340deg, var(--accent-soft) 360deg ); -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; z-index: 1; opacity: 0; transition: opacity .4s ease; } #aeo-popup-root.aeo-iframe-ready .sticky-card::before { opacity: 1; animation: aeoBeamRotate 5s linear infinite; } @keyframes aeoBeamRotate { to { --aeo-beam-angle: 360deg; } } #aeo-popup-root .sc-inner { padding: 18px 18px 20px; } #aeo-popup-root .sc-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } #aeo-popup-root .sc-label { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-dim); display: flex; align-items: center; gap: 6px; } #aeo-popup-root .sc-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: aeoPulse 2s ease-in-out infinite; flex-shrink: 0; } #aeo-popup-root .sc-close { width: 26px; height: 26px; border-radius: 50%; border: 1px solid var(--border); background: transparent; cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--ink-faint); font-size: 16px; line-height: 1; transition: border-color .2s, color .2s, background .2s; flex-shrink: 0; padding: 0; } #aeo-popup-root .sc-close:hover { border-color: var(--ink); color: var(--ink); background: #F5F6F2; } #aeo-popup-root .sc-headline { font-family: var(--font-display); font-size: 19px; font-weight: 800; color: var(--ink); letter-spacing: -0.4px; line-height: 1.25; margin: 0 0 8px; } #aeo-popup-root .sc-sub { font-size: 13px; color: var(--ink-faint); line-height: 1.5; margin: 0 0 12px; font-family: var(--font-body); } #aeo-popup-root .sc-ticker-wrap { position: relative; overflow: hidden; margin-bottom: 14px; height: 28px; } #aeo-popup-root .sc-ticker-wrap::before, #aeo-popup-root .sc-ticker-wrap::after { content: ''; position: absolute; inset-block: 0; width: 20px; z-index: 2; pointer-events: none; } #aeo-popup-root .sc-ticker-wrap::before { left: 0; background: linear-gradient(to right, var(--card-fade), transparent); } #aeo-popup-root .sc-ticker-wrap::after { right: 0; background: linear-gradient(to left, var(--card-fade), transparent); } #aeo-popup-root .sc-ticker { /* Marquee math (do not change without revisiting both this rule AND the aeoScTicker keyframe + the JS that builds the chip list): - Each chip is 28px wide with an 8px trailing margin = 36px slot. - We render 3 copies of the 6-engine ticker = 18 chips = 648px. - One copy width = 6 * 36 = 216px = exactly 1/3 of the total. - The keyframe translates -33.3333% (= -216px), so the moment the first copy finishes scrolling out, the second copy is already occupying its exact original position. Seamless loop. We use margin-right on the chip (not flex gap) on purpose: flex gap only sits *between* siblings, which is one short for the cycle to line up with translateX. margin-right counts on every chip, so the total width is N*(chip+gap) and -1/N translation hits the boundary cleanly. Three copies is also what keeps the right edge of the card from ever going empty mid-scroll -- a single copy (216px) is narrower than the visible card content area, so doubled content would leave a gap on the right at the end of every cycle. */ display: flex; width: max-content; animation: aeoScTicker 18s linear infinite; align-items: center; height: 100%; } #aeo-popup-root .sc-logo-chip { width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0; margin-right: 8px; display: flex; align-items: center; justify-content: center; overflow: hidden; /* Faint inset border. On dark/coloured chips it's invisible; on the white Copilot chip it's what keeps the icon from floating against the light card background. */ box-shadow: inset 0 0 0 1px rgba(0,0,0,0.06); } #aeo-popup-root .sc-logo-chip img { width: 18px; height: 18px; object-fit: contain; display: block; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.15)); } /* Copilot-specific override: Microsoft's multicolor ribbon mark has finer detail than any of the other engines' marks (which are single- colour silhouettes), and its lighter gradient tips (cyan, yellow, pink) wash out at small sizes on a white chip. Bumping the image to nearly fill the 28px chip restores legibility. We target by [title] so future engine additions don't accidentally pick this up. */ #aeo-popup-root .sc-logo-chip[title="Copilot"] img { width: 24px; height: 24px; /* No drop-shadow on the Copilot icon -- the soft glow muddies the gradient ribbon. */ filter: none; } #aeo-popup-root .sc-cta { display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; font-family: var(--font-body); font-size: 14px; font-weight: 600; color: var(--cta-text); background: var(--cta-grad); background-size: 200% 100%; border: none; border-radius: 100px; padding: 11px 20px; cursor: pointer; text-decoration: none; animation: aeoCtaShimmer 3s ease-in-out 2.4s infinite; transition: transform .15s, box-shadow .2s; } #aeo-popup-root .sc-cta:hover { transform: scale(1.02); box-shadow: 0 4px 20px rgba(var(--shadow-rgb),0.4); animation-play-state: paused; } #aeo-popup-root .sc-cta .arrow { font-size: 15px; transition: transform .2s; } #aeo-popup-root .sc-cta:hover .arrow { transform: translateX(3px); } /* ── STICKY BAR (after card dismissed) ──────────────────────────── */ #aeo-popup-root .sticky-banner { position: fixed; bottom: 0; left: 0; right: 0; z-index: 9990; transform: translateY(100%); opacity: 0; pointer-events: none; background: var(--bar-bg); background-size: 300% 300%; border-top: 1px solid var(--border); box-shadow: 0 -4px 32px rgba(var(--shadow-rgb),0.08), 0 -1px 0 rgba(var(--shadow-rgb),0.15); } #aeo-popup-root .sticky-banner.visible { pointer-events: all; animation: aeoBarSlideUp 0.5s cubic-bezier(0.22,1,0.36,1) forwards, aeoBannerBreathe 5s ease-in-out 0.5s infinite; } #aeo-popup-root .sticky-banner::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: linear-gradient(90deg, var(--accent) 0%, var(--accent-soft) 60%, transparent 100%); } #aeo-popup-root .banner-inner { max-width: 1240px; margin: 0 auto; padding: 0 32px; height: var(--banner-h); display: flex; align-items: center; gap: 24px; } #aeo-popup-root .banner-label { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-dim); white-space: nowrap; flex-shrink: 0; display: flex; align-items: center; gap: 6px; } #aeo-popup-root .banner-label::before { content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: aeoPulse 2s ease-in-out infinite; } #aeo-popup-root .banner-divider-v { width: 1px; height: 32px; background: var(--border); flex-shrink: 0; } #aeo-popup-root .banner-headline { font-family: var(--font-display); font-size: 15px; font-weight: 800; color: var(--ink); letter-spacing: -0.3px; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin: 0; } #aeo-popup-root .banner-sub { font-size: 13px; color: var(--ink-faint); flex-shrink: 0; white-space: nowrap; font-family: var(--font-body); } #aeo-popup-root .banner-cta { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-body); font-size: 14px; font-weight: 600; color: var(--cta-text); background: var(--cta-grad); background-size: 200% 100%; border: none; border-radius: 100px; padding: 11px 28px; cursor: pointer; text-decoration: none; white-space: nowrap; flex-shrink: 0; animation: aeoCtaShimmer 3s ease-in-out 0.5s infinite; transition: transform .15s, box-shadow .2s; } #aeo-popup-root .banner-cta:hover { transform: scale(1.03); box-shadow: 0 4px 20px rgba(var(--shadow-rgb),0.4); animation-play-state: paused; } #aeo-popup-root .banner-cta .arrow { font-size: 16px; line-height: 1; transition: transform .2s; } #aeo-popup-root .banner-cta:hover .arrow { transform: translateX(3px); } /* ── IFRAME MODAL (full-screen takeover) ────────────────────────── */ /* Matches the Verdict V2 full-page lead capture pattern: edge-to-edge shell, no card chrome, just a translucent floating top bar with "Back to article" and a close pill. The AEO funnel's own branding inside the iframe carries the visual weight. */ #aeo-popup-root .aeo-modal { position: fixed; inset: 0; z-index: 10000; background: #ffffff; display: flex; flex-direction: column; opacity: 0; pointer-events: none; transition: opacity .25s ease; } #aeo-popup-root .aeo-modal.open { opacity: 1; pointer-events: all; } #aeo-popup-root .aeo-modal-backdrop { display: none; } #aeo-popup-root .aeo-modal-shell { position: relative; z-index: 1; display: flex; flex-direction: column; width: 100%; height: 100%; background: #ffffff; } #aeo-popup-root .aeo-modal-bar { position: relative; z-index: 3; display: flex; align-items: center; justify-content: space-between; padding: 12px 20px; background: #ffffff; border-bottom: 1px solid rgba(0,0,0,0.06); flex-shrink: 0; } #aeo-popup-root .aeo-modal-back { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-body); font-size: 13px; font-weight: 500; color: var(--ink-soft); background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 8px; transition: background .15s, color .15s; } #aeo-popup-root .aeo-modal-back:hover { background: #F0F1EC; color: var(--ink); } #aeo-popup-root .aeo-modal-iframe-wrap { position: relative; flex: 1; background: #ffffff; overflow: hidden; } #aeo-popup-root .aeo-modal-iframe { width: 100%; height: 100%; border: 0; display: block; background: #ffffff; } #aeo-popup-root .aeo-modal-loading { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); background: #ffffff; transition: opacity .3s ease; z-index: 1; pointer-events: none; } #aeo-popup-root .aeo-modal-iframe-wrap.loaded .aeo-modal-loading { opacity: 0; } #aeo-popup-root .aeo-modal-loading .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: aeoPulse 1.2s ease-in-out infinite; margin-right: 8px; } /* lock background scroll when modal is open */ body.aeo-modal-open { overflow: hidden; } /* Bar collapses to headline + CTA on narrower viewports, but the card keeps its 340px bottom-left footprint all the way down to phone widths. Real phones (≤480px) get the full-width card so the CTA stays tappable. */ @media (max-width: 900px) { #aeo-popup-root .banner-inner { padding: 0 16px; gap: 12px; } #aeo-popup-root .banner-label, #aeo-popup-root .banner-divider-v, #aeo-popup-root .banner-sub { display: none; } #aeo-popup-root .banner-headline { font-size: 13px; } #aeo-popup-root .banner-cta { font-size: 13px; padding: 9px 18px; } } @media (max-width: 480px) { #aeo-popup-root .sticky-card { left: 12px; bottom: 12px; width: calc(100vw - 24px); } } @media (prefers-reduced-motion: reduce) { #aeo-popup-root .sticky-card, #aeo-popup-root .sticky-banner.visible, #aeo-popup-root .sc-cta, #aeo-popup-root .banner-cta { animation: none !important; } #aeo-popup-root.aeo-iframe-ready .sticky-card { transform: none; opacity: 1; } } </style> <div id="aeo-popup-root" data-variant="small-report" data-domain="rankanddiscover.com"> <div class="sticky-card" id="aeoStickyCard" role="complementary" aria-label="AI Visibility Radar — Free AEO Report"> <div class="sc-inner"> <div class="sc-header"> <span class="sc-label"><span class="sc-dot"></span>AI VISIBILITY RADAR</span> <button type="button" class="sc-close" id="aeoCardClose" aria-label="Dismiss">×</button> </div> <p class="sc-headline">Are AI engines recommending your brand?</p> <p class="sc-sub">Check your score on 5 AI engines — instantly.</p> <div class="sc-ticker-wrap"><div class="sc-ticker" id="aeoScTicker"></div></div> <a href="#" class="sc-cta" id="aeoCardCta"> Check for Free <span class="arrow">→</span> </a> </div> </div> <div class="sticky-banner" id="aeoStickyBanner" role="complementary" aria-label="AI Visibility Radar — Free AEO Report"> <div class="banner-inner"> <span class="banner-label">AI VISIBILITY RADAR</span> <div class="banner-divider-v"></div> <p class="banner-headline">Are AI engines recommending your brand?</p> <span class="banner-sub">Check your score on 5 AI engines — instantly.</span> <a href="#" class="banner-cta" id="aeoBarCta"> Check for Free <span class="arrow">→</span> </a> </div> </div> <div class="aeo-modal" id="aeoModal" role="dialog" aria-modal="true" aria-label="AI Visibility Radar — Free AEO Report" aria-hidden="true"> <div class="aeo-modal-backdrop" data-aeo-close></div> <div class="aeo-modal-shell"> <header class="aeo-modal-bar"> <button type="button" class="aeo-modal-back" data-aeo-close> <span aria-hidden="true">←</span> Back to article </button> </header> <div class="aeo-modal-iframe-wrap" id="aeoModalIframeWrap"> <div class="aeo-modal-loading"><span class="dot"></span>Loading report…</div> <iframe id="aeoModalIframe" class="aeo-modal-iframe" title="AI Visibility Radar — Free AEO Report" referrerpolicy="no-referrer-when-downgrade" allow="clipboard-write" src="https://aeo.prod-mobtools.com/aeo/small-report?embed=1&utm_source=rankanddiscover.com&utm_medium=satellite&utm_campaign=aeo-popup&utm_content=small-report"></iframe> </div> </div> </div> </div> <script id="aeo-popup-script"> (function () { var root = document.getElementById('aeo-popup-root'); if (!root) return; var card = document.getElementById('aeoStickyCard'); var bar = document.getElementById('aeoStickyBanner'); var modal = document.getElementById('aeoModal'); var iframe = document.getElementById('aeoModalIframe'); var wrap = document.getElementById('aeoModalIframeWrap'); var closeBtn = document.getElementById('aeoCardClose'); var cardCta = document.getElementById('aeoCardCta'); var barCta = document.getElementById('aeoBarCta'); var ticker = document.getElementById('aeoScTicker'); /* ---------- analytics -------------------------------- Posts to the existing /wp-json/satellite/v1/lead-event proxy, which forwards to the backend's POST /api/leads/event. Events here are prefixed with "aeo_" so the lawyer funnel chart on the same dashboard never picks them up. ----------------------------------------------------- */ var AEO_DOMAIN = "rankanddiscover.com"; var AEO_VARIANT = "small-report"; var AEO_NICHE = "marketing"; var AEO_EVENT_URL = "https:\/\/rankanddiscover.com\/wp-json\/satellite\/v1\/lead-event"; var AEO_EVENT_NONCE = "5756fe7ec0"; /* localStorage visitor_id so unique-clicker counts on the dashboard are stable across sessions on the same browser. UUIDv4-ish via random bytes; no PII, just a stable handle for COUNT(DISTINCT) on the backend. */ function aeoGetVisitorId() { try { var KEY = 'aeo_vid'; var existing = localStorage.getItem(KEY); if (existing) return existing; var b = (crypto && crypto.getRandomValues) ? crypto.getRandomValues(new Uint8Array(16)) : (function () { var arr = []; for (var i=0;i<16;i++) arr.push(Math.floor(Math.random()*256)); return arr; })(); b[6] = (b[6] & 0x0f) | 0x40; // version 4 b[8] = (b[8] & 0x3f) | 0x80; // variant var hex = Array.prototype.map.call(b, function (x) { return ('0' + x.toString(16)).slice(-2); }).join(''); var id = hex.slice(0,8)+'-'+hex.slice(8,12)+'-'+hex.slice(12,16)+'-'+hex.slice(16,20)+'-'+hex.slice(20,32); localStorage.setItem(KEY, id); return id; } catch (e) { return ''; // private mode / disabled storage -- silently drop } } var AEO_VISITOR_ID = aeoGetVisitorId(); function aeoTrack(eventType, extraMeta) { try { var meta = { variant: AEO_VARIANT, niche: AEO_NICHE }; if (extraMeta) for (var k in extraMeta) if (Object.prototype.hasOwnProperty.call(extraMeta, k)) meta[k] = extraMeta[k]; var payload = { domain: AEO_DOMAIN, event_type: eventType, visitor_id: AEO_VISITOR_ID, page_url: location.href, metadata_json: JSON.stringify(meta) }; var body = JSON.stringify(payload); if (navigator.sendBeacon) { navigator.sendBeacon( AEO_EVENT_URL + '?_wpnonce=' + encodeURIComponent(AEO_EVENT_NONCE), new Blob([body], { type: 'application/json' }) ); } else { fetch(AEO_EVENT_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': AEO_EVENT_NONCE }, body: body, keepalive: true }); } } catch (e) { /* analytics must never break the popup */ } } /* ---------- cookies ---------- */ function readCookie(name) { var m = document.cookie.match('(?:^|;)\\s*' + name + '=([^;]*)'); return m ? decodeURIComponent(m[1]) : ''; } function writeCookie(name, value, days) { var d = new Date(); d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000); document.cookie = name + '=' + encodeURIComponent(value) + '; expires=' + d.toUTCString() + '; path=/; SameSite=Lax'; } /* Cookie names are versioned. An earlier iteration of this script set aeo_lead_done from a 15s dwell-time heuristic (since removed); any tester who left the modal open during that period now carries a 30-day cookie that silently hides the popup forever. Bumping the name to _v2 retires that stale state without forcing anyone to clear browser cookies. */ var CARD_DISMISSED = 'aeo_card_dismissed_v2'; var LEAD_DONE = 'aeo_lead_done_v2'; if (readCookie(LEAD_DONE) === '1') { root.classList.add('aeo-lead-done'); return; } /* ---------- reveal the card (or bar) ---------- The iframe is preloading in the background regardless of card state, so we don't gate reveal on it -- we just slide the card up on a quick fixed timer so the popup is visible reliably on every refresh, even when the cross-origin iframe's load event is slow or never fires. By the time the user finishes reading the article and clicks the CTA, the iframe is virtually always fully loaded, so clicks still open the modal instantly. */ var revealed = false; var dismissedBefore = readCookie(CARD_DISMISSED) === '1'; if (dismissedBefore) root.classList.add('aeo-skip-card'); function reveal() { if (revealed) return; revealed = true; if (dismissedBefore) { if (bar) bar.classList.add('visible'); aeoTrack('aeo_bar_impression', { source: 'bar' }); } else { root.classList.add('aeo-iframe-ready'); aeoTrack('aeo_impression', { source: 'card' }); } } /* 600ms is long enough to feel intentional (not jarring on first paint), short enough that it always wins against a slow cross-origin iframe. */ setTimeout(reveal, 600); /* ---------- ticker ---------- Three full copies of the chip list, not two. The aeoScTicker keyframe translates by exactly one copy's width (-33.3333%) so the second copy slides into the first's position seamlessly; the third copy is there to keep the right edge of the card filled while the second is doing the heavy lifting -- one copy alone (216px) is narrower than the visible card content area, so a doubled ticker leaves a visible gap at the right edge near the end of every animation cycle. */ var TOOLS = [{"name":"Gemini","bg":"#1A73E8","logo":"https:\/\/rankanddiscover.com\/wp-content\/mu-plugins\/aeo-assets\/logos\/gemini.svg"},{"name":"Grok","bg":"#111111","logo":"https:\/\/rankanddiscover.com\/wp-content\/mu-plugins\/aeo-assets\/logos\/grok.svg"},{"name":"Perplexity","bg":"#1FB8CD","logo":"https:\/\/rankanddiscover.com\/wp-content\/mu-plugins\/aeo-assets\/logos\/perplexity.svg"},{"name":"ChatGPT","bg":"#10A37F","logo":"https:\/\/rankanddiscover.com\/wp-content\/mu-plugins\/aeo-assets\/logos\/chatgpt.svg"},{"name":"Copilot","bg":"#FFFFFF","logo":"https:\/\/rankanddiscover.com\/wp-content\/mu-plugins\/aeo-assets\/logos\/copilot.svg"},{"name":"Claude","bg":"#D97757","logo":"https:\/\/rankanddiscover.com\/wp-content\/mu-plugins\/aeo-assets\/logos\/claude.svg"}]; if (ticker) { var tripled = TOOLS.concat(TOOLS).concat(TOOLS); ticker.innerHTML = tripled.map(function (t) { return '<div class="sc-logo-chip" title="' + t.name + '" style="background:' + t.bg + ';">' + '<img src="' + t.logo + '" alt="' + t.name + '" loading="lazy" width="18" height="18">' + '</div>'; }).join(''); } /* ---------- card -> bar dismissal ---------- The slide-down animation is 0.4s. We use a matched setTimeout instead of animationend because Chrome occasionally swallows the event when another animation (the breathing background) is in flight on the same element. */ if (closeBtn) { closeBtn.addEventListener('click', function () { writeCookie(CARD_DISMISSED, '1', 30); aeoTrack('aeo_card_dismiss', { source: 'card' }); card.classList.add('hiding'); setTimeout(function () { card.style.display = 'none'; if (bar) bar.classList.add('visible'); }, 420); }); } /* ---------- modal open / close ---------- */ if (iframe && wrap) { if (iframe.complete) wrap.classList.add('loaded'); else iframe.addEventListener('load', function () { wrap.classList.add('loaded'); }, { once: true }); } function swapCardToBar() { if (!card || card.style.display === 'none' || card.classList.contains('hiding')) return; card.classList.add('hiding'); setTimeout(function () { card.style.display = 'none'; if (bar) bar.classList.add('visible'); }, 420); } function openModal(e) { if (e) e.preventDefault(); if (!modal) return; modal.setAttribute('aria-hidden', 'false'); requestAnimationFrame(function () { modal.classList.add('open'); }); document.body.classList.add('aeo-modal-open'); } function closeModal() { if (!modal || !modal.classList.contains('open')) return; modal.classList.remove('open'); document.body.classList.remove('aeo-modal-open'); setTimeout(function () { modal.setAttribute('aria-hidden', 'true'); }, 320); aeoTrack('aeo_modal_close'); /* If the card was still showing behind the modal, collapse it to the bar so the user has an obvious re-entry point. No cookie is set here -- only the explicit X on the card persists dismissal across page loads. */ swapCardToBar(); } if (cardCta) cardCta.addEventListener('click', function (e) { aeoTrack('aeo_cta_click', { source: 'card' }); openModal(e); }); if (barCta) barCta.addEventListener('click', function (e) { aeoTrack('aeo_cta_click', { source: 'bar' }); openModal(e); }); /* Generic trigger: any element with [data-aeo-open] opens the same modal. The in-article banner (aeo-inline-banner.php) uses this so it doesn't have to duplicate the modal HTML/JS -- it just renders a CTA with data-aeo-open + data-aeo-source="inline" and rides on the popup infrastructure that's already in the footer. Source is read from data-aeo-source so we can split CTR by surface in the analytics dashboard (card / bar / inline / future surfaces). */ document.querySelectorAll('[data-aeo-open]').forEach(function (el) { el.addEventListener('click', function (e) { var source = el.getAttribute('data-aeo-source') || 'external'; aeoTrack('aeo_cta_click', { source: source }); openModal(e); }); }); if (modal) { modal.querySelectorAll('[data-aeo-close]').forEach(function (el) { el.addEventListener('click', closeModal); }); } document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && modal && modal.classList.contains('open')) closeModal(); }); /* ---------- future postMessage handshake (stub) ---------- Listens for a "lead-complete" event from the iframe so we can flip the LEAD_DONE cookie immediately on real submission (not on dwell time). Wire this up on the AEO side and remove the dwell-time fallback above. */ window.addEventListener('message', function (e) { if (!e || !e.origin || e.origin.indexOf('aeo.prod-mobtools.com') === -1) return; var data = e.data || {}; if (data && data.type === 'aeo:lead-complete') { writeCookie(LEAD_DONE, '1', 30); root.classList.add('aeo-lead-done'); closeModal(); } }); })(); </script> <script> (function(){ var bar = document.getElementById('reading-progress'); if(!bar) return; var article = document.querySelector('.post-content'); if(!article) return; var milestones = {25:false,50:false,75:false,100:false}; var startTime = Date.now(); function sendGA4(name, params) { if (window.gtag) window.gtag('event', name, params); } window.addEventListener('scroll', function(){ var rect = article.getBoundingClientRect(); var total = article.offsetHeight - window.innerHeight; var progress = Math.min(100, Math.max(0, (-rect.top / total) * 100)); bar.style.width = progress + '%'; var pct = Math.floor(progress); [25,50,75,100].forEach(function(m){ if (pct >= m && !milestones[m]) { milestones[m] = true; sendGA4('scroll_depth', {percent: m, reading_seconds: Math.round((Date.now()-startTime)/1000)}); } }); }, {passive:true}); function sendReadingTime() { var seconds = Math.round((Date.now()-startTime)/1000); if (seconds > 3) sendGA4('reading_time', {seconds: seconds, scroll_reached: Math.max.apply(null, Object.keys(milestones).filter(function(k){return milestones[k];})) || 0}); } document.addEventListener('visibilitychange', function(){ if(document.visibilityState==='hidden') sendReadingTime(); }); window.addEventListener('beforeunload', sendReadingTime); })(); </script> <script> (function(){ var toc = document.querySelector('.toc-container'); if(!toc) return; var title = toc.querySelector('.toc-title'); if(window.innerWidth <= 768) { toc.classList.add('toc-collapsed'); title.addEventListener('click', function(){ toc.classList.toggle('toc-collapsed'); }); } var links = toc.querySelectorAll('.toc-list a'); var sections = []; links.forEach(function(a){ var id = a.getAttribute('href'); if(id) { var el = document.querySelector(id); if(el) sections.push({el:el,link:a}); } }); if(!sections.length) return; var raf; window.addEventListener('scroll', function(){ if(raf) return; raf = requestAnimationFrame(function(){ raf = null; var scrollY = window.scrollY + 120; var active = sections[0]; for(var i=0;i<sections.length;i++){ if(sections[i].el.offsetTop <= scrollY) active = sections[i]; } links.forEach(function(l){ l.classList.remove('toc-active'); }); if(active) active.link.classList.add('toc-active'); }); }, {passive:true}); })(); </script> </body> </html>