<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><!-- Consent Mode: defaults to denied until user accepts --><script>
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('consent', 'default', {
      analytics_storage: 'denied',
      ad_storage: 'denied',
      wait_for_update: 2000
    });
    // Restore consent for returning visitors before GTM loads
    if (typeof localStorage !== 'undefined' && localStorage.getItem('pie_consent') === 'granted') {
      gtag('consent', 'update', { analytics_storage: 'granted', ad_storage: 'granted' });
      dataLayer.push({ event: 'consent_granted' });
    }
  </script><!-- Google Tag Manager --><script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-W9SZ886K');</script><!-- End Google Tag Manager --><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Pie - The Quality Layer for AI-Speed Engineering</title><meta name="description" content="Pie watches every change your team pushes, tests the affected flows on your actual product, and opens PRs to fix what it finds. No scripts. No noise. Just results."><meta name="keywords" content="AI QA, automated testing, E2E testing, test automation, no-code testing, AI agents, fastest QA platform"><!-- Canonical URL --><link rel="canonical" href="https://pie.inc"><!-- Open Graph --><meta property="og:title" content="Pie - The Quality Layer for AI-Speed Engineering"><meta property="og:description" content="Pie watches every change your team pushes, tests the affected flows on your actual product, and opens PRs to fix what it finds. No scripts. No noise. Just results."><meta property="og:image" content="https://pie.inc/pie-og-image.jpg?v=2"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta property="og:image:type" content="image/jpeg"><meta property="og:url" content="https://pie.inc"><meta property="og:type" content="website"><meta property="og:site_name" content="Pie"><!-- Twitter Card --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="Pie - The Quality Layer for AI-Speed Engineering"><meta name="twitter:description" content="Pie watches every change your team pushes, tests the affected flows on your actual product, and opens PRs to fix what it finds. No scripts. No noise. Just results."><meta name="twitter:image" content="https://pie.inc/pie-og-image.jpg?v=2"><!-- Fonts --><!-- Satoshi (body) stays on Fontshare; Clash Display removed. --><link rel="preconnect" href="https://api.fontshare.com" crossorigin><link href="https://api.fontshare.com/v2/css?f[]=satoshi@400,500,700&display=swap" rel="stylesheet"><!-- Geist Sans (display/headline) and JetBrains Mono (code/eyebrow) from Google Fonts. --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg">  <script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","name":"Pie","legalName":"PieLabs, Inc.","url":"https://pie.inc","logo":"https://pie.inc/pielogo.avif","description":"The quality layer for AI-speed engineering. Pie watches every change, tests affected flows, and opens PRs to fix what it finds.","sameAs":["https://www.linkedin.com/company/pielabs-inc/"],"contactPoint":{"@type":"ContactPoint","contactType":"sales","url":"https://calendly.com/jinoo-pie/demo"}}</script> <link rel="stylesheet" href="/_astro/_slug_.DZH6utLf.css">
<link rel="stylesheet" href="/_astro/_slug_.vbTTtwsJ.css"></head> <body class="dotted-grid noise-overlay"> <!-- Google Tag Manager (noscript) --> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-W9SZ886K" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <!-- End Google Tag Manager (noscript) --> <!-- ========================================
       GRADIENT BLOBS (Background)
       ======================================== --> <div class="fixed inset-0 overflow-hidden pointer-events-none z-0"> <div class="gradient-blob blob-violet absolute -top-48 left-[10%]"></div> <div class="gradient-blob blob-magenta absolute top-[30%] -right-24"></div> <div class="gradient-blob blob-orange absolute bottom-[10%] left-[20%]"></div> </div> <!-- ========================================
       NAVIGATION
       ======================================== --> <nav class="nav"> <div class="max-w-1080 mx-auto px-6 md:px-16 lg:px-6 h-full flex items-center justify-between"> <!-- Logo + Nav Links --> <div class="flex items-center gap-8"> <a href="/" class="flex items-center gap-2"> <img src="/pielogo.avif" alt="Pie" class="h-8 w-auto"> </a> <div class="hidden md:flex items-center gap-8"> <!-- Product Dropdown --> <div class="relative" id="product-dropdown"> <button class="nav-link flex items-center gap-1" id="product-trigger">
Product
<svg class="w-4 h-4 transition-transform duration-200" id="product-chevron" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path> </svg> </button> <div class="absolute top-full left-0 mt-2 w-48 py-2 bg-canvas-elevated border border-canvas-subtle rounded-xl shadow-xl opacity-0 invisible transition-all duration-200 transform -translate-y-2" id="product-menu"> <a href="/product/pie-qa/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Pie QA</a> <a href="/product/overview/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Product Overview</a> <a href="/product/how-it-works/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">How Pie Works</a> <a href="/product/autonomous-discovery/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Autonomous Discovery</a> <a href="/product/self-healing-tests/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Self-Healing Tests</a> <a href="/product/integrations/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Integrations</a> <a href="/product/custom-tests/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Custom Tests</a> <a href="/product/security/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Security</a> </div> </div> <a href="https://docs.pie.inc/" target="_blank" class="nav-link">Docs</a> <!-- Resources Dropdown --> <div class="relative" id="resources-dropdown"> <button class="nav-link flex items-center gap-1" id="resources-trigger">
Resources
<svg class="w-4 h-4 transition-transform duration-200" id="resources-chevron" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path> </svg> </button> <div class="absolute top-full left-0 mt-2 w-48 py-2 bg-canvas-elevated border border-canvas-subtle rounded-xl shadow-xl opacity-0 invisible transition-all duration-200 transform -translate-y-2" id="resources-menu"> <a href="/blog/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Blog</a> <a href="/customers/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Case Studies</a> <a href="/resources/whitepapers/" class="block px-4 py-2 font-body text-sm text-text-secondary hover:text-text-primary hover:bg-canvas-subtle transition-colors">Whitepapers</a> </div> </div> </div> </div> <!-- Desktop CTA --> <div class="hidden md:flex items-center gap-4"> <a href="https://app.pie.inc/" target="_blank" class="nav-link">Login</a> <a href="https://app.pie.inc/start" target="_blank" class="nav-cta">Get Started</a> </div> <!-- Mobile Menu Button --> <button id="mobile-menu-btn" class="md:hidden flex items-center justify-center w-10 h-10 rounded-lg hover:bg-canvas-elevated transition-colors" aria-label="Toggle menu"> <svg class="w-6 h-6 text-text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path id="menu-icon" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path> </svg> </button> </div> <!-- Mobile Menu --> <div id="mobile-menu" class="hidden md:hidden absolute top-full left-0 right-0 bg-canvas-base/95 backdrop-blur-lg border-b border-canvas-subtle"> <div class="max-w-1080 mx-auto px-6 md:px-16 lg:px-6 py-6 flex flex-col gap-4"> <!-- Mobile Product Section --> <div class="py-2"> <span class="nav-link font-semibold">Product</span> <div class="pl-4 mt-2 flex flex-col gap-2"> <a href="/product/pie-qa/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Pie QA</a> <a href="/product/overview/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Product Overview</a> <a href="/product/how-it-works/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">How Pie Works</a> <a href="/product/autonomous-discovery/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Autonomous Discovery</a> <a href="/product/self-healing-tests/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Self-Healing Tests</a> <a href="/product/integrations/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Integrations</a> <a href="/product/custom-tests/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Custom Tests</a> <a href="/product/security/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Security</a> </div> </div> <a href="https://docs.pie.inc/" target="_blank" class="nav-link py-2">Docs</a> <!-- Mobile Resources Section --> <div class="py-2"> <span class="nav-link font-semibold">Resources</span> <div class="pl-4 mt-2 flex flex-col gap-2"> <a href="/blog/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Blog</a> <a href="/customers/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Case Studies</a> <a href="/resources/whitepapers/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors py-1">Whitepapers</a> </div> </div> <a href="https://app.pie.inc/" target="_blank" class="nav-link py-2">Login</a> <a href="https://app.pie.inc/start" target="_blank" class="nav-cta text-center mt-2">Get Started</a> </div> </div> </nav> <!-- Page Content -->   <div class="landing-home"> <section class="relative md:min-h-[90vh] md:flex md:items-center md:overflow-hidden"> <!-- Subtle grid background --> <div class="lh-grid-bg absolute inset-0 -z-10"></div> <div class="w-full max-w-1080 mx-auto px-6 md:px-16 lg:px-6 pt-32 pb-16 md:pt-40 md:pb-20 relative z-10"> <!-- Text block — centered (unchanged) --> <div class="max-w-4xl mx-auto text-center"> <div class="hero-badge mb-6 flex justify-center"> <span class="font-mono text-xs font-bold text-accent-violet uppercase tracking-[0.1em]">Tests What Code Review Can't</span> </div> <div class="hero-headline"> <h1 class="font-display font-bold text-5xl md:text-7xl xl:text-hero text-text-primary leading-[1.05] tracking-tight">
What if you never shipped <span class="text-gradient inline-block pb-1 pr-1">a bug again?</span> </h1> </div> <div class="hero-subline mt-6 max-w-[640px] mx-auto"> <p class="font-body text-lg md:text-body-lg text-text-secondary leading-[1.7]">
Pie connects to your repo, tests every commit like a real user,<br class="hidden md:inline"> and opens PRs to fix what breaks. No scripts. No noise. Just results.
</p> </div> <div class="hero-ctas mt-8"> <div class="flex flex-col items-center gap-4"> <a href="https://app.pie.inc/start" target="_blank" class="btn-primary justify-center"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-[18px] h-[18px]"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
Try Pie on my repo <span class="arrow-wrapper"><span class="arrow"></span></span> </a> </div> </div> </div> <!-- Variation B stage --> <div class="lh-v2-shell mt-14"> <div class="lh-v2-wrap" id="v2-wrap"> <!-- Step pill timeline --> <div class="lh-v2-timeline" aria-hidden="true"> <div class="lh-v2-pill" data-pill="1"> <span class="lh-v2-pill-ring"><span class="lh-v2-pill-ring-inner">1</span></span> <span class="lh-v2-pill-label">Read PR</span> </div> <div class="lh-v2-conn" data-conn="1"><span class="lh-v2-conn-fill"></span></div> <div class="lh-v2-pill" data-pill="2"> <span class="lh-v2-pill-ring"><span class="lh-v2-pill-ring-inner">2</span></span> <span class="lh-v2-pill-label">Test app</span> </div> <div class="lh-v2-conn" data-conn="2"><span class="lh-v2-conn-fill"></span></div> <div class="lh-v2-pill" data-pill="3"> <span class="lh-v2-pill-ring"><span class="lh-v2-pill-ring-inner">3</span></span> <span class="lh-v2-pill-label">Ship fix</span> </div> </div> <!-- Stage --> <div class="lh-v2-stage"> <!-- SCENE 1 — code diff --> <div class="lh-v2-scene lh-v2-scene--active" data-scene="1"> <div class="lh-v2-scene-inner lh-v2-scene-1"> <div class="lh-v2-s1-col"> <div class="lh-v2-scene-head"> <div class="lh-v2-eyebrow">PULL REQUEST</div> <div class="lh-v2-title">feat: proceed-to-cart button</div> </div> <div class="lh-v2-editor"> <div class="lh-v2-editor-chrome"> <div class="lh-v2-editor-dots"> <span style="background:#ff5f56"></span> <span style="background:#ffbd2e"></span> <span style="background:#27c93f"></span> </div> <div class="lh-v2-editor-tab"> <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"> <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> </svg> <span>CheckoutButton.tsx</span> </div> <div class="lh-v2-editor-status" id="v2-s1-status">scanning · 0%</div> </div> <div class="lh-v2-code" id="v2-code"> <div class="lh-v2-code-track" id="v2-code-track"> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">1</span><span class="lh-v2-code-tx">import { useState } from &#39;react&#39;;</span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">2</span><span class="lh-v2-code-tx">import { Button } from &#39;./ui&#39;;</span></div> <div class="lh-v2-code-line lh-v2-code-line--add"><span class="lh-v2-code-ln">3</span><span class="lh-v2-code-tx"><span class="lh-v2-code-plus">+</span>import { useCart } from &#39;./cart&#39;;</span></div> <div class="lh-v2-code-line lh-v2-code-line--blank"><span class="lh-v2-code-ln">4</span><span class="lh-v2-code-tx"></span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">5</span><span class="lh-v2-code-tx">interface Props { product: Product }</span></div> <div class="lh-v2-code-line lh-v2-code-line--blank"><span class="lh-v2-code-ln">6</span><span class="lh-v2-code-tx"></span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">7</span><span class="lh-v2-code-tx">export function CheckoutButton({ product }: Props) {</span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">8</span><span class="lh-v2-code-tx"> const { addItem } = useCart();</span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">9</span><span class="lh-v2-code-tx"> const [loading, setLoading] = useState(false);</span></div> <div class="lh-v2-code-line lh-v2-code-line--blank"><span class="lh-v2-code-ln">10</span><span class="lh-v2-code-tx"></span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">11</span><span class="lh-v2-code-tx"> const handleClick = async () =&gt; {</span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">12</span><span class="lh-v2-code-tx"> setLoading(true);</span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">13</span><span class="lh-v2-code-tx"> await addItem(product);</span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">14</span><span class="lh-v2-code-tx"> };</span></div> <div class="lh-v2-code-line lh-v2-code-line--blank"><span class="lh-v2-code-ln">15</span><span class="lh-v2-code-tx"></span></div> <div class="lh-v2-code-line lh-v2-code-crit"><span class="lh-v2-code-ln">16</span><span class="lh-v2-code-tx"> return &lt;Button onClick={handleClick} disabled={<span class="lh-v2-code-hl">loading</span>}&gt;Proceed to cart&lt;/Button&gt;;</span></div> <div class="lh-v2-code-line"><span class="lh-v2-code-ln">17</span><span class="lh-v2-code-tx">}</span></div> </div> <div class="lh-v2-code-scan" id="v2-code-scan"></div> <div class="lh-v2-code-fade"></div> </div> </div> </div> </div> </div> <!-- SCENE 2 — browser Lottie --> <div class="lh-v2-scene" data-scene="2"> <div class="lh-v2-scene-inner lh-v2-scene-2"> <div class="lh-v2-s2-col"> <div class="lh-v2-scene-head"> <div class="lh-v2-eyebrow">LIVE TEST</div> <div class="lh-v2-title">Walking through checkout like a user</div> </div> <div class="lh-v2-browser"> <div class="lh-v2-browser-chrome"> <div class="lh-v2-browser-dots"> <span style="background:#ff5f56"></span> <span style="background:#ffbd2e"></span> <span style="background:#27c93f"></span> </div> <div class="lh-v2-browser-url"> <svg width="9" height="9" viewBox="0 0 9 9" fill="none" stroke="currentColor" stroke-width="1.2"><rect x="2" y="4" width="5" height="4" rx="0.6"></rect><path d="M3 4V2.8a1.5 1.5 0 1 1 3 0V4"></path></svg> <span>staging.acme.com/checkout</span> </div> </div> <div class="lh-v2-browser-body"> <div id="v2-lottie" class="lh-v2-lottie" role="img" aria-label="Pie navigating a product page and detecting a broken proceed-to-cart button"></div> </div> </div> <div class="lh-v2-s2-sub"> <span class="lh-v2-s2-sub-dot"></span> <span>Proceed to cart button isn't clickable — users can't reach checkout</span> </div> </div> </div> </div> <!-- SCENE 3 — PR card + timeline --> <div class="lh-v2-scene" data-scene="3"> <div class="lh-v2-scene-inner lh-v2-scene-3"> <div class="lh-v2-s3-col"> <div class="lh-v2-scene-head"> <div class="lh-v2-eyebrow">FIX PR</div> <div class="lh-v2-title">Pie drafted the fix</div> </div> <div class="lh-v2-pr"> <div class="lh-v2-pr-head" data-r="0.05"> <div class="lh-v2-pr-avatar"> <svg viewBox="0 0 20 20" fill="none"><path d="M10 0C10.9147 0 11.7336.4047 12.292 1.043C12.5903 1.361 12.9455 1.622 13.3633 1.8C13.7976 1.984 14.2506 2.057 14.6924 2.036C15.5571 1.989 16.4238 2.281 17.0713 2.929C17.7177 3.575 18.0092 4.44 17.9531 5.285C17.9229 6.208 18.2865 7.088 18.9561 7.697C19.5967 8.271 20 9.088 20 10C20 10.912 19.5964 11.728 18.9609 12.286C18.2789 12.907 17.9109 13.796 17.9561 14.707C18.0098 15.559 17.7182 16.425 17.0713 17.071C16.4237 17.719 15.5571 18.011 14.71 17.953C14.2463 17.946 13.7949 18.019 13.3623 18.202C12.9468 18.379 12.5925 18.638 12.3066 18.951C11.7336 19.595 10.915 20 10 20C9.084 20 8.2644 19.594 7.706 18.954C7.405 18.638 7.0521 18.378 6.6377 18.202C6.2067 18.019 5.757 17.947 5.3184 17.966C4.4458 18.011 3.5781 17.72 2.9297 17.071C2.2808 16.423 1.9879 15.554 2.0469 14.705C2.0839 13.793 1.7199 12.911 1.0479 12.302C.4062 11.735 0 10.916 0 10C0 9.084.4059 8.264 1.0459 7.706C1.7122 7.084 2.0727 6.212 2.0342 5.316C1.9879 4.446 2.2798 3.578 2.9287 2.929C3.5773 2.28 4.4456 1.988 5.294 2.047C5.7521 2.056 6.2038 1.984 6.6367 1.8C7.0533 1.623 7.4072 1.362 7.6934 1.048C8.2644.405 9.0843 0 10 0Z" fill="#6B21A8"></path><path d="M9.83 5.017C10.517 5.017 11.145 5.182 11.711 5.514C12.285 5.837 12.734 6.287 13.057 6.86C13.38 7.426 13.541 8.058 13.541 8.753C13.541 9.446 13.39 10.081 13.085 10.654C12.789 11.219 12.375 11.665 11.844 11.989C11.32 12.314 10.733 12.477 10.088 12.477C9.568 12.477 9.081 12.368 8.63 12.151C8.3 11.993 8.006 11.788 7.749 11.538V14.635C7.749 14.865 7.677 15.066 7.524 15.219C7.371 15.372 7.171 15.443 6.94 15.443C6.716 15.443 6.52 15.37 6.361 15.222C6.204 15.066 6.133 14.865 6.133 14.635V8.753C6.133 8.058 6.294 7.426 6.617 6.859C6.948 6.286 7.392 5.838 7.948 5.515C8.514 5.182 9.143 5.017 9.83 5.017Z" fill="#EC4899"></path><path d="M10.23 4.617C10.917 4.617 11.545 4.782 12.111 5.114C12.685 5.437 13.134 5.887 13.457 6.46C13.78 7.026 13.941 7.658 13.941 8.353C13.941 9.046 13.79 9.681 13.485 10.254C13.189 10.819 12.775 11.265 12.244 11.589C11.72 11.914 11.133 12.077 10.488 12.077C9.968 12.077 9.481 11.968 9.03 11.751C8.7 11.593 8.406 11.388 8.149 11.138V14.235C8.149 14.465 8.077 14.666 7.924 14.819C7.771 14.972 7.571 15.043 7.34 15.043C7.116 15.043 6.92 14.97 6.761 14.822C6.604 14.666 6.533 14.465 6.533 14.235V8.353C6.533 7.658 6.694 7.026 7.017 6.459C7.348 5.886 7.792 5.438 8.348 5.115C8.914 4.782 9.543 4.617 10.23 4.617Z" fill="white"></path></svg> </div> <span class="lh-v2-pr-name">pie</span> <span class="lh-v2-pr-bot">BOT</span> <span class="lh-v2-pr-flex"></span> <span class="lh-v2-pr-time">opened just now</span> </div> <div class="lh-v2-pr-title" data-r="0.2">fix: reset loading state so Proceed to cart stays clickable</div> <div class="lh-v2-pr-block" data-r="0.4"> <div class="lh-v2-pr-label">ROOT CAUSE</div> <div class="lh-v2-pr-text"><code class="lh-v2-pr-inline">handleClick()</code> sets <code class="lh-v2-pr-inline">loading</code> to true but never resets it — button stays disabled after the first click.</div> </div> <div class="lh-v2-pr-block" data-r="0.6"> <div class="lh-v2-pr-label">FIX APPLIED</div> <div class="lh-v2-pr-code"><span class="lh-v2-pr-code-plus">+</span>await addItem(product); setLoading(false);</div> </div> <div class="lh-v2-pr-badges" data-r="0.8"> <span class="lh-v2-pr-badge lh-v2-pr-badge--green"><span class="lh-v2-pr-badge-ck">✓</span> CI passing</span> <span class="lh-v2-pr-badge lh-v2-pr-badge--blue"><span class="lh-v2-pr-badge-ck">✓</span> Ready to merge</span> </div> </div> </div> </div> </div> <!-- Cursor — hidden during scene 2 (Lottie has its own) --> <div class="lh-v2-cursor" id="v2-cursor" aria-hidden="true"> <svg width="22" height="26" viewBox="0 0 22 26" fill="none"> <path d="M2 1.2V22.5l5.3-5 3.6 7.2 3-1.5-3.5-7.1 7.5-.5L2 1.2Z" fill="#fff" stroke="#8B5CF6" stroke-width="1.3" stroke-linejoin="round"></path> </svg> <div class="lh-v2-cursor-label" id="v2-cursor-label"></div> <div class="lh-v2-cursor-pulse" id="v2-cursor-pulse"></div> </div> <!-- Bottom status bar --> <div class="lh-v2-statusbar"> <span class="lh-v2-statusbar-dot" id="v2-statusbar-dot"></span> <span class="lh-v2-statusbar-text" id="v2-statusbar-text">Pie is reading the diff</span> <span class="lh-v2-statusbar-flex"></span> <span class="lh-v2-statusbar-brand">pie · autonomous qa</span> </div> </div> </div> </div> </div> </section> <script>
(function() {
  var wrap = document.getElementById('v2-wrap');
  if (!wrap) return;

  // ── Mobile scale-to-fit ──────────────────────────────────────
  // CSS `zoom` had inconsistent browser support for calc()/min() values
  // and was causing overflow at mobile breakpoints, so we drive the
  // scaling from JS via `transform: scale()` + compensating shell height.
  // Runs on init, on resize, and after fonts load (layout can shift as
  // JetBrains Mono replaces the fallback font).
  var shell = wrap.parentElement;
  var NATIVE_W = 640;
  function fitMobile() {
    if (!shell) return;
    // < 360px = CSS media-query handles the static poster; skip JS.
    if (window.matchMedia('(max-width: 359px)').matches) {
      wrap.style.transform = '';
      shell.style.height = '';
      return;
    }
    var avail = shell.clientWidth;
    if (avail >= NATIVE_W) {
      wrap.style.transform = '';
      shell.style.height = '';
      return;
    }
    // Reset transform AND clear any prior shell height before measuring.
    // Without clearing shell.style.height, a previous stale value can
    // constrain the wrap's layout (flex stretch) and produce a bogus
    // naturalH on the next read — we'd then compound the bad value.
    wrap.style.transform = '';
    shell.style.height = '';
    // Force synchronous reflow so the height read below reflects the
    // unscaled layout. Without this, iOS Safari has been observed to
    // return the previously-scaled height.
    void wrap.offsetWidth;
    var naturalH = wrap.getBoundingClientRect().height;
    var scale = avail / NATIVE_W;
    wrap.style.transform = 'scale(' + scale + ')';
    // Math.ceil so we never undershoot (which would clip the wrap visually).
    shell.style.height = Math.ceil(naturalH * scale) + 'px';
  }
  fitMobile();
  // Reveal the wrap — the mobile CSS keeps it visibility:hidden until now
  // so viewers never see the unscaled 640px layout flash before the
  // transform is applied.
  wrap.classList.add('lh-v2-ready');
  // rAF-gate resize: a rapid window-drag fires dozens of events per second
  // and each fitMobile call forces layout twice (reset transform → read
  // offsetHeight → apply transform). One call per animation frame is plenty.
  var resizeRaf = 0;
  window.addEventListener('resize', function() {
    if (resizeRaf) return;
    resizeRaf = requestAnimationFrame(function() {
      resizeRaf = 0;
      fitMobile();
    });
  });
  if (document.fonts && document.fonts.ready) {
    document.fonts.ready.then(fitMobile);
  }

  // Note: we intentionally do NOT bail on `prefers-reduced-motion: reduce`.
  // iOS 17+ Safari reports that media query as `reduce` whenever Low Power
  // Mode is on, which silently froze the hero animation for any visitor on
  // low battery — the dominant case for mobile traffic. The hero IS the
  // page's main visual story, so we keep it running unconditionally.
  // (Previously this branch added `.lh-v2-reduced-motion` and returned.)

  // Posters on very narrow viewports (briefing: <360px = static scene-3 poster).
  var narrow = window.matchMedia('(max-width: 359px)');
  if (narrow.matches) {
    wrap.classList.add('lh-v2-narrow-poster');
    return;
  }

  // ── Element lookups ──
  var stage = wrap.querySelector('.lh-v2-stage');
  var scenes = wrap.querySelectorAll('.lh-v2-scene');
  var pills = wrap.querySelectorAll('.lh-v2-pill');
  var conns = wrap.querySelectorAll('.lh-v2-conn');
  var pillRings = wrap.querySelectorAll('.lh-v2-pill-ring');
  var connFills = wrap.querySelectorAll('.lh-v2-conn-fill');
  var codeTrack = document.getElementById('v2-code-track');
  var codeScan = document.getElementById('v2-code-scan');
  var s1Status = document.getElementById('v2-s1-status');
  var cursor = document.getElementById('v2-cursor');
  var cursorLabel = document.getElementById('v2-cursor-label');
  var cursorPulse = document.getElementById('v2-cursor-pulse');
  var statusbarDot = document.getElementById('v2-statusbar-dot');
  var statusbarText = document.getElementById('v2-statusbar-text');
  var prRevealEls = wrap.querySelectorAll('[data-r]');

  // ── Constants (ported from variation-b.jsx) ──
  var CYCLE = 17000;
  var P1 = [0, 5500];
  var P2 = [5500, 11000];
  var P3 = [11000, 17000];

  // Code diff geometry — container height 240, line height 22. CODE_TOTAL
  // is the rendered track height: normally 17*22 = 374, but line 16 wraps
  // to 2 visual rows at the editor's width, so actual height is ~396+. We
  // measure it on the first rAF tick (below) to stay robust against future
  // line changes, font-load shifts, and width tweaks.
  var CODE_CONTAINER = 240;
  var CODE_TOTAL = 17 * 22;

  // ── Per-tick state cache to avoid needless DOM writes ──
  var last = {
    active: -1, sceneTx: [null, null, null], sceneOp: [null, null, null],
    scrollProg: -1, criticalLit: null, statusText: '',
    p2Prog: -1, reveal: -1,
    cursorCx: NaN, cursorCy: NaN, cursorLabel: '', cursorHidden: null, cursorPulse: null,
    barText: '', barColor: '',
    pillStates: ['', '', ''], pillRings: [-1, -1, -1], connFills: [-1, -1]
  };

  // ── Helpers ──
  function clamp(v, lo, hi) { return v < lo ? lo : v > hi ? hi : v; }

  function sceneOffset(n, t, active) {
    if (active === n) {
      var localStart = n === 1 ? P1[0] : n === 2 ? P2[0] : P3[0];
      var since = t - localStart;
      if (since < 500) return { tx: (1 - since / 500) * 40, op: since / 500 };
      return { tx: 0, op: 1 };
    }
    return { tx: active > n ? -40 : 40, op: 0 };
  }

  // ── Cursor path (ported from VariationB cursor calc) ──
  function cursorPath(t, active, scrollProg, criticalLit, reveal) {
    var cx = 0, cy = 0, label = '', hidden = false, pulse = false;
    var pillY = 50;
    if (t < 400) {
      cx = 330; cy = pillY; label = '';
    } else if (t < P1[1] - 300) {
      if (criticalLit) {
        // Park the cursor at line 16's wrapped continuation row, where the
        // `loading` token actually lives after the line wraps. Label stays
        // in its default position (below the cursor) and falls into the
        // empty area past line 17's closing brace — no code overlap.
        cx = 190; cy = 238;
      } else {
        cx = 180 + scrollProg * 90; cy = 180 + scrollProg * 55;
      }
      label = criticalLit ? 'button stuck disabled' : 'reading code';
      pulse = !!criticalLit;
    } else if (t < P2[0] + 500) {
      cx = 420; cy = pillY; label = 'next →';
    } else if (t < P2[1] - 300) {
      // Hidden during scene 2 — Lottie shows its own cursor
      hidden = true;
    } else if (t < P3[0] + 500) {
      cx = 500; cy = pillY; label = '→';
    } else {
      cx = 340 + reveal * 100; cy = 250 + reveal * 70; label = 'writing PR';
    }
    return { cx: cx, cy: cy, label: label, hidden: hidden, pulse: pulse };
  }

  // ── Step pills + connectors ──
  function paintPills(active, progress) {
    var p = clamp(progress, 0, 1);
    for (var i = 0; i < pills.length; i++) {
      var n = i + 1;
      var state = n === active ? 'active' : (n < active ? 'done' : 'upcoming');
      if (last.pillStates[i] !== state) {
        pills[i].setAttribute('data-state', state);
        last.pillStates[i] = state;
      }
      var deg = n === active ? Math.round(p * 360) : (n < active ? 360 : 0);
      if (last.pillRings[i] !== deg) {
        pillRings[i].style.setProperty('--ring-deg', deg + 'deg');
        last.pillRings[i] = deg;
      }
    }
    for (var j = 0; j < conns.length; j++) {
      var connN = j + 1; // connector after pill connN
      var fill;
      if (active > connN) fill = 1;
      else if (active === connN) fill = p;
      else fill = 0;
      if (last.connFills[j] !== fill) {
        conns[j].setAttribute('data-state', active > connN ? 'done' : active === connN ? 'active' : 'upcoming');
        connFills[j].style.width = (fill * 100) + '%';
        last.connFills[j] = fill;
      }
    }
  }

  // ── Scene 1 paint ──
  function paintScene1(scrollProg, criticalLit) {
    if (last.scrollProg !== scrollProg) {
      var scroll = Math.max(0, scrollProg * (CODE_TOTAL - CODE_CONTAINER + 40));
      codeTrack.style.transform = 'translateY(' + (-scroll) + 'px)';
      // Scan line follows the bottom of the visible window
      var top = scrollProg > 0
        ? Math.min(CODE_CONTAINER - 4, Math.min(scrollProg, 1) * CODE_CONTAINER - 2)
        : 0;
      codeScan.style.top = top + 'px';
      last.scrollProg = scrollProg;
    }
    if (last.criticalLit !== criticalLit) {
      codeTrack.setAttribute('data-crit', criticalLit ? '1' : '0');
      codeScan.setAttribute('data-crit', criticalLit ? '1' : '0');
      last.criticalLit = criticalLit;
    }
    var statusText = criticalLit
      ? '⚠ button blocked on line 16'
      : 'scanning · ' + Math.floor(scrollProg * 100) + '%';
    if (last.statusText !== statusText) {
      s1Status.textContent = statusText;
      s1Status.setAttribute('data-alert', criticalLit ? '1' : '0');
      last.statusText = statusText;
    }
  }

  // ── Scene 2 paint — Lottie scrubbing ──
  function paintScene2(p2Prog, active) {
    if (active !== 2) return;
    var anim = window.__pieLottieAnim;
    if (!anim || !window.__pieLottieReady) return;
    var total = anim.totalFrames || 0;
    if (total <= 0) return;
    // Skip when progress barely changed (≈1 frame on a 324-frame Lottie).
    // Each goToAndStop triggers a full SVG re-render, so rate-limiting this
    // is the biggest per-tick win on low-end devices.
    if (Math.abs(p2Prog - last.p2Prog) < 0.003) return;
    last.p2Prog = p2Prog;
    anim.goToAndStop(clamp(p2Prog * (total - 1), 0, total - 1), true);
  }

  // ── Scene 3 paint — staggered reveals ──
  function paintScene3(reveal) {
    if (last.reveal === reveal) return;
    last.reveal = reveal;
    for (var i = 0; i < prRevealEls.length; i++) {
      var el = prRevealEls[i];
      var thr = parseFloat(el.getAttribute('data-r'));
      el.classList.toggle('lh-v2-reveal-on', reveal >= thr);
    }
  }

  // ── Cursor paint ──
  function paintCursor(t, active, scrollProg, criticalLit, reveal) {
    var cp = cursorPath(t, active, scrollProg, criticalLit, reveal);
    if (last.cursorHidden !== cp.hidden) {
      cursor.style.opacity = cp.hidden ? '0' : '1';
      last.cursorHidden = cp.hidden;
    }
    if (cp.hidden) return;
    if (last.cursorCx !== cp.cx || last.cursorCy !== cp.cy) {
      cursor.style.transform = 'translate3d(' + cp.cx + 'px,' + cp.cy + 'px,0)';
      last.cursorCx = cp.cx; last.cursorCy = cp.cy;
    }
    if (last.cursorLabel !== cp.label) {
      if (cp.label) {
        cursorLabel.textContent = cp.label;
        cursorLabel.style.opacity = '1';
      } else {
        cursorLabel.style.opacity = '0';
      }
      last.cursorLabel = cp.label;
    }
    if (last.cursorPulse !== cp.pulse) {
      cursorPulse.style.opacity = cp.pulse ? '1' : '0';
      last.cursorPulse = cp.pulse;
    }
  }

  // ── Bottom status bar ──
  var BAR_TEXT = {
    1: 'Pie is reading the diff',
    2: 'Pie is running your app',
    3: 'Pie is opening a fix PR'
  };
  var BAR_COLOR = {
    1: '#8B5CF6',
    2: '#EF4444',
    3: '#22C55E'
  };
  function paintBar(active) {
    var txt = BAR_TEXT[active];
    var clr = BAR_COLOR[active];
    if (last.barText !== txt) {
      statusbarText.textContent = txt;
      last.barText = txt;
    }
    if (last.barColor !== clr) {
      statusbarDot.style.background = clr;
      statusbarDot.style.boxShadow = '0 0 10px ' + clr;
      last.barColor = clr;
    }
  }

  // ── Scene push/pop ──
  function paintScenes(t, active) {
    for (var i = 0; i < scenes.length; i++) {
      var n = i + 1;
      var off = sceneOffset(n, t, active);
      if (last.sceneTx[i] !== off.tx || last.sceneOp[i] !== off.op) {
        scenes[i].style.transform = 'translateX(' + off.tx + 'px)';
        scenes[i].style.opacity = off.op;
        scenes[i].classList.toggle('lh-v2-scene--active', n === active);
        last.sceneTx[i] = off.tx; last.sceneOp[i] = off.op;
      }
    }
  }

  // Measure the actual rendered code-track height so the scroll formula
  // accounts for whatever wrapping happens at the editor's width. Runs
  // once now (DOM ready) and again when fonts finish loading, since text
  // metrics can shift between fallback fonts and JetBrains Mono.
  function measureCodeTotal() {
    if (!codeTrack) return;
    // Subtract the 10px top + 10px bottom padding on the track.
    var h = codeTrack.offsetHeight - 20;
    if (h > 0) CODE_TOTAL = h;
  }
  measureCodeTotal();
  if (document.fonts && document.fonts.ready) {
    document.fonts.ready.then(measureCodeTotal);
  }

  // ── Main rAF loop ──
  var start = performance.now();
  function tick(now) {
    var t = (now - start) % CYCLE;
    var active = t < P1[1] ? 1 : t < P2[1] ? 2 : 3;
    var p1t = t - P1[0];
    var p2t = t - P2[0];
    var p3t = t - P3[0];
    var scrollProg = clamp(p1t / 3500, 0, 1);
    var criticalLit = p1t > 3200 && t < P1[1];
    var p2Prog = clamp(p2t / (P2[1] - P2[0]), 0, 1);
    var reveal = clamp(p3t / 2800, 0, 1);

    if (last.active !== active) {
      last.active = active;
    }

    paintScenes(t, active);
    paintScene1(scrollProg, criticalLit);
    paintScene2(p2Prog, active);
    paintScene3(reveal);
    paintCursor(t, active, scrollProg, criticalLit, reveal);
    paintBar(active);
    paintPills(active, active === 1 ? scrollProg : active === 2 ? p2Prog : reveal);

    requestAnimationFrame(tick);
  }
  requestAnimationFrame(tick);
})();
</script> <script type="module">
  // Lottie (scene 2) — use lottie-web's SVG renderer for clean frame scrubbing
  // (goToAndStop). Matches the prototype's BrowserMock approach. Exposed on
  // window.__pieLottieAnim so the rAF loop can scrub in sync with p2Prog.
  import lottie from 'https://cdn.jsdelivr.net/npm/lottie-web@5.12.2/+esm';
  const container = document.getElementById('v2-lottie');
  if (container) {
    const anim = lottie.loadAnimation({
      container,
      renderer: 'svg',
      loop: false,
      autoplay: false,
      path: '/lottie/pie-panel2-checkout.json',
      rendererSettings: {
        preserveAspectRatio: 'xMidYMid meet',
        progressiveLoad: true,
      },
    });
    window.__pieLottieAnim = anim;
    anim.addEventListener('DOMLoaded', () => { window.__pieLottieReady = true; });
  }
</script> <section class="max-w-[1120px] mx-auto px-5 lg:px-8 py-10" data-reveal aria-label="Customers"> <div class="font-mono text-xs font-bold text-accent-violet tracking-[0.1em] uppercase text-center mb-8">
Trusted by fast-moving engineering teams
</div> <div class="logo-carousel overflow-hidden"> <div class="logo-carousel-track flex items-center gap-16"> <div class="logo-item shrink-0"> <img src="/Client logo/Fi.svg" alt="Fi" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0"> <img src="/Client logo/Quicksort-Rx.svg" alt="Quicksort Rx" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0"> <img src="/Client logo/Tilt.svg" alt="Tilt" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0"> <img src="/Client logo/Prado.svg" alt="Prado" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0"> <img src="/Client logo/Lumo.svg" alt="Lumo" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0"> <img src="/Client logo/Spark.svg" alt="Spark" class="h-8 w-auto" loading="lazy"> </div> <div class="logo-item shrink-0" aria-hidden="true"> <img src="/Client logo/Fi.svg" alt="" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0" aria-hidden="true"> <img src="/Client logo/Quicksort-Rx.svg" alt="" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0" aria-hidden="true"> <img src="/Client logo/Tilt.svg" alt="" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0" aria-hidden="true"> <img src="/Client logo/Prado.svg" alt="" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0" aria-hidden="true"> <img src="/Client logo/Lumo.svg" alt="" class="h-8 w-auto" loading="lazy"> </div><div class="logo-item shrink-0" aria-hidden="true"> <img src="/Client logo/Spark.svg" alt="" class="h-8 w-auto" loading="lazy"> </div> </div> </div> </section> <section class="max-w-[720px] mx-auto px-5 lg:px-8 py-[120px]" data-reveal> <div class="text-center mb-12"> <div class="font-mono text-xs font-bold text-accent-violet tracking-[0.1em] uppercase mb-4">Sound familiar?</div> <h2 class="font-display font-bold text-4xl md:text-5xl tracking-tight leading-[1.1] text-text-primary">
Code review approved it.<br><span class="text-gradient">The product broke anyway.</span> </h2> </div> <!-- Juxtaposition card --> <div class="lh-sf-card" id="sf-card" style="--split: 62%;"> <!-- RIGHT PANEL (production) — sits behind, full width --> <div class="lh-sf-panel lh-sf-right font-body" id="sf-right"> <div class="lh-sf-flash" aria-hidden="true"></div> <div class="lh-sf-status"> <span class="lh-sf-status-dot lh-sf-status-dot--red"></span> <span class="lh-sf-status-label lh-sf-status-label--red" id="sf-r-status">Production</span> </div> <p class="lh-sf-title lh-sf-title--red font-body" id="sf-r-title">Checkout total renders $0.00 for all orders</p> <p class="lh-sf-desc lh-sf-desc--red font-body" id="sf-r-desc">Discovered by a customer. 4 hours after deploy. CI was green.</p> <div class="lh-sf-pills lh-sf-pills--red" id="sf-r-pills"> <span class="lh-sf-pill lh-sf-pill--red font-body">847 errors in 30 min</span> <span class="lh-sf-pill lh-sf-pill--red font-body">12 customer reports</span> </div> </div> <!-- LEFT PANEL (CI/code) — sits on top with clip-path --> <div class="lh-sf-panel lh-sf-left font-body" id="sf-left"> <div class="lh-sf-status"> <span class="lh-sf-status-dot lh-sf-status-dot--green"></span> <span class="lh-sf-status-label lh-sf-status-label--green" id="sf-l-status">CI passed</span> </div> <p class="lh-sf-title lh-sf-title--green font-body" id="sf-l-title">PR #412 — Refactor payment reduce logic</p> <p class="lh-sf-desc lh-sf-desc--green font-body" id="sf-l-desc">Order total renders $0.00. Discount logic skips the merge after the reduce function changed.</p> <div class="lh-sf-pills lh-sf-pills--green" id="sf-l-pills"> <span class="lh-sf-pill lh-sf-pill--green font-body">3 approvals</span> <span class="lh-sf-pill lh-sf-pill--green font-body">all checks pass</span> <span class="lh-sf-pill lh-sf-pill--green font-body">merged to main</span> </div> </div> <!-- SVG diagonal divider --> <svg class="lh-sf-divider" viewBox="0 0 631 354" preserveAspectRatio="none"> <line id="sf-div-line" x1="391.2" y1="0" x2="296.6" y2="354" stroke="rgba(255,255,255,0.1)" stroke-width="1.5"></line> </svg> <!-- Drag handle --> <div class="lh-sf-handle" id="sf-handle"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none"> <path d="M7 9L4 12L7 15" stroke="#A1A1AA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M17 9L20 12L17 15" stroke="#A1A1AA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> <line x1="9" y1="7" x2="9" y2="17" stroke="#3F3F46" stroke-width="1"></line> <line x1="15" y1="7" x2="15" y2="17" stroke="#3F3F46" stroke-width="1"></line> </svg> </div> </div> <!-- Dot navigation --> <div class="lh-sf-dots"> <button type="button" class="lh-sf-dot lh-sf-dot--active" data-i="0" aria-label="Show bug 1"></button> <button type="button" class="lh-sf-dot" data-i="1" aria-label="Show bug 2"></button> <button type="button" class="lh-sf-dot" data-i="2" aria-label="Show bug 3"></button> </div> <div class="text-center mt-12"> <p class="font-body text-lg text-text-secondary leading-relaxed max-w-2xl mx-auto">
These are the bugs that pass every code review tool on the market. They don't live in the diff. They live in the running product. <strong class="text-text-primary">Pie catches them because Pie actually uses your product, the same way your customers do.</strong> </p> </div> </section> <script>
(function() {
  var card = document.getElementById('sf-card');
  if (!card) return;

  var divLine = document.getElementById('sf-div-line');
  var handle = document.getElementById('sf-handle');
  var section = card.closest('section');
  var leftStatusRow = card.querySelector('.lh-sf-left .lh-sf-status');
  var rightPanel = document.getElementById('sf-right');
  var redDesc = document.getElementById('sf-r-desc');

  // Note: we deliberately don't gate on `prefers-reduced-motion: reduce`.
  // iOS 17+ Safari reports it whenever Low Power Mode is on, which silently
  // disabled drag, pre-hid nothing, and skipped the entrance animation for
  // most mobile visitors (low battery is the dominant state by mid-day).
  // Drag is user-initiated and the entrance animation is a single short
  // burst on scroll-in, so neither is aggressive enough to warrant a bail.
  var dragging = false;
  var animating = false;
  var hasAnimated = false;
  var rafId = null;
  var timeoutIds = [];

  var cards = [
    {
      leftStatus: "CI passed",
      leftTitle: "PR #412 \u2014 Refactor payment reduce logic",
      leftDesc: "Order total renders $0.00. Discount logic skips the merge after the reduce function changed.",
      leftPills: ["3 approvals", "all checks pass", "merged to main"],
      rightStatus: "Production",
      rightTitle: "Checkout total renders $0.00 for all orders",
      rightDesc: "Discovered by a customer. 4 hours after deploy. CI was green.",
      rightPills: ["847 errors in 30 min", "12 customer reports"]
    },
    {
      leftStatus: "CI passed",
      leftTitle: "PR #287 \u2014 Update auth redirect flow",
      leftDesc: "Session token doesn\u2019t persist across redirects. Works on Chrome, silent failure on Safari.",
      leftPills: ["2 approvals", "CI green", "merged to main"],
      rightStatus: "Production",
      rightTitle: "Login fails on mobile Safari for 18% of users",
      rightDesc: "Two days before anyone noticed. Found via support ticket spike.",
      rightPills: ["342 failed logins", "48 support tickets"]
    },
    {
      leftStatus: "CI passed",
      leftTitle: "PR #503 \u2014 Migrate data layer to v2",
      leftDesc: "Component crashes when the API returns an empty array. No error boundary, white screen.",
      leftPills: ["4 approvals", "all checks pass", "staging OK"],
      rightStatus: "Production",
      rightTitle: "Dashboard goes blank for new accounts",
      rightDesc: "Three support tickets before engineering noticed. Shipped on a Friday.",
      rightPills: ["white screen", "3 escalations in 1 hour"]
    }
  ];

  function applySplit(pct) {
    card.style.setProperty('--split', pct + '%');
    var topX = (pct / 100) * 631;
    var botX = ((pct - 15) / 100) * 631;
    divLine.setAttribute('x1', topX);
    divLine.setAttribute('x2', botX);
    handle.style.left = ((pct - 7.5) / 100 * 100) + '%';
  }

  function setSplit(pct) {
    pct = Math.max(25, Math.min(85, pct));
    applySplit(pct);
  }

  function setSplitRaw(pct) {
    applySplit(Math.max(5, Math.min(98, pct)));
  }

  function updateFromPointer(e) {
    var rect = card.getBoundingClientRect();
    var pct = ((e.clientX - rect.left) / rect.width) * 100;
    setSplit(pct + 7.5);
  }

  function updatePills(containerId, pills, color) {
    var el = document.getElementById(containerId);
    el.innerHTML = '';
    pills.forEach(function(text) {
      var span = document.createElement('span');
      span.className = 'lh-sf-pill lh-sf-pill--' + color + ' font-body';
      span.textContent = text;
      el.appendChild(span);
    });
  }

  function setCard(i) {
    var c = cards[i];
    document.getElementById('sf-l-status').textContent = c.leftStatus;
    document.getElementById('sf-l-title').textContent = c.leftTitle;
    document.getElementById('sf-l-desc').textContent = c.leftDesc;
    updatePills('sf-l-pills', c.leftPills, 'green');
    document.getElementById('sf-r-status').textContent = c.rightStatus;
    document.getElementById('sf-r-title').textContent = c.rightTitle;
    document.getElementById('sf-r-desc').textContent = c.rightDesc;
    updatePills('sf-r-pills', c.rightPills, 'red');
    setSplit(62);
    document.querySelectorAll('.lh-sf-dot').forEach(function(d, idx) {
      d.classList.toggle('lh-sf-dot--active', idx === i);
    });
  }

  function cancelAnimation() {
    if (!animating) return;
    animating = false;
    if (rafId) cancelAnimationFrame(rafId);
    rafId = null;
    timeoutIds.forEach(function(id) { clearTimeout(id); });
    timeoutIds = [];
    if (leftStatusRow) leftStatusRow.classList.remove('lh-sf-shimmer-active');
    if (card) card.classList.remove('lh-sf-shake-active');
    if (rightPanel) rightPanel.classList.remove('lh-sf-flash-active');
    if (redDesc) redDesc.classList.remove('lh-sf-desc-hidden');
  }

  function animateSplit(from, to, duration, onComplete) {
    var start = performance.now();
    function tick(now) {
      if (!animating) return;
      var progress = Math.min((now - start) / duration, 1);
      var eased = 1 - Math.pow(1 - progress, 3);
      setSplitRaw(from + (to - from) * eased);
      if (progress < 1) {
        rafId = requestAnimationFrame(tick);
      } else {
        rafId = null;
        if (onComplete) onComplete();
      }
    }
    rafId = requestAnimationFrame(tick);
  }

  function schedule(fn, delay) {
    var id = setTimeout(function() {
      if (!animating) return;
      fn();
    }, delay);
    timeoutIds.push(id);
  }

  function startAnimation() {
    if (hasAnimated || animating) return;
    hasAnimated = true;
    animating = true;

    // Beat 1: open at 95%, shimmer the CI status
    setSplitRaw(95);
    if (leftStatusRow) {
      leftStatusRow.classList.remove('lh-sf-shimmer-active');
      // reflow so the animation restarts cleanly
      void leftStatusRow.offsetWidth;
      leftStatusRow.classList.add('lh-sf-shimmer-active');
      schedule(function() { leftStatusRow.classList.remove('lh-sf-shimmer-active'); }, 700);
    }

    // Beat 2: 95 -> 35 starting at 1500ms, over 2000ms
    schedule(function() {
      animateSplit(95, 35, 2000, function() {
        // Beat 3 "boom": shake + red flash immediately, human cost fade-up at +500ms
        if (card) {
          card.classList.remove('lh-sf-shake-active');
          void card.offsetWidth;
          card.classList.add('lh-sf-shake-active');
          schedule(function() { card.classList.remove('lh-sf-shake-active'); }, 350);
        }
        if (rightPanel) {
          rightPanel.classList.remove('lh-sf-flash-active');
          void rightPanel.offsetWidth;
          rightPanel.classList.add('lh-sf-flash-active');
          schedule(function() { rightPanel.classList.remove('lh-sf-flash-active'); }, 450);
        }
        schedule(function() {
          if (redDesc) redDesc.classList.remove('lh-sf-desc-hidden');
        }, 500);

        // Beat 4: settle 35 -> 62 after 2000ms Beat 3 hold, over 1000ms
        schedule(function() {
          animateSplit(35, 62, 1000, function() {
            animating = false;
          });
        }, 2000);
      });
    }, 1500);
  }

  // Drag interaction
  card.addEventListener('pointerdown', function(e) {
    if (animating) cancelAnimation();
    dragging = true;
    card.setPointerCapture(e.pointerId);
    updateFromPointer(e);
  });
  card.addEventListener('pointermove', function(e) {
    if (!dragging) return;
    updateFromPointer(e);
  });
  card.addEventListener('pointerup', function() { dragging = false; });
  card.addEventListener('pointercancel', function() { dragging = false; });

  // Dot navigation
  document.querySelectorAll('.lh-sf-dot').forEach(function(dot) {
    dot.addEventListener('click', function() {
      if (animating) cancelAnimation();
      var i = Number(dot.getAttribute('data-i'));
      setCard(i);
    });
  });

  // Initialize
  setSplit(62);
  // Pre-hide the red human-cost line so Beat 3 has something to fade up
  if (redDesc) {
    redDesc.classList.add('lh-sf-desc-hidden');
  }

  // Scroll-triggered entrance animation (one-shot, 0.3 threshold)
  if (section && 'IntersectionObserver' in window) {
    var observer = new IntersectionObserver(function(entries) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting && !hasAnimated) {
          startAnimation();
          observer.disconnect();
        }
      });
    }, { threshold: 0.3 });
    observer.observe(section);
  }
})();
</script> <section class="max-w-[1120px] mx-auto px-5 lg:px-8 py-[120px] relative" data-reveal> <div class="text-center mb-12"> <h2 class="font-display font-bold text-4xl md:text-5xl text-text-primary mb-6 tracking-tight">
The numbers behind <span class="text-gradient">the gap</span> </h2> </div> <div class="grid md:grid-cols-3 bg-[#050506] border border-[rgba(255,255,255,0.05)] rounded-[24px] p-6 lg:p-10 shadow-[0_0_40px_rgba(0,0,0,0.5)]" data-reveal-stagger> <div class="text-center px-4 py-8 md:py-0"> <div class="font-mono text-[clamp(40px,5vw,56px)] font-bold text-white tracking-tighter mb-2">6.4x</div> <div class="font-display font-semibold text-lg text-text-primary mb-4">more code generated by AI</div> <div class="font-mono text-[11px] text-text-muted">That's 6.4 times more surface area to review, maintain, and break.</div> </div> <div class="text-center px-4 border-y md:border-y-0 md:border-x border-[rgba(255,255,255,0.05)] py-8 md:py-0"> <div class="font-mono text-[clamp(40px,5vw,56px)] font-bold text-white tracking-tighter mb-2">96%</div> <div class="font-display font-semibold text-lg text-text-primary mb-4">of devs don't trust AI code</div> <div class="font-mono text-[11px] text-text-muted">Only 48% check it before committing.</div> </div> <div class="text-center px-4 py-8 md:py-0"> <div class="font-mono text-[clamp(40px,5vw,56px)] font-bold text-white tracking-tighter mb-2">68%</div> <div class="font-display font-semibold text-lg text-text-primary mb-4">more issues per AI-authored PR</div> <div class="font-mono text-[11px] text-text-muted">CodeRabbit PR analysis, 2025</div> </div> </div> </section> <section class="lh-hpw-section"> <div class="max-w-1080 mx-auto px-6 md:px-16 lg:px-6 py-[120px]"> <!-- Header --> <div class="text-center mb-16" data-reveal> <div class="inline-flex items-center gap-[7px] px-[14px] py-[5px] rounded-full font-mono text-[12.5px] font-bold text-accent-violet bg-[linear-gradient(135deg,rgba(139,92,246,0.1),rgba(217,70,239,0.05))] border border-[rgba(139,92,246,0.2)] tracking-[0.06em] mb-5">HOW PIE WORKS</div> <h2 class="font-display font-semibold text-[clamp(2.2rem,5vw,3.2rem)] text-text-primary tracking-[-0.04em] leading-[1.08] mb-4">
Three steps to <span class="text-gradient">zero bugs</span> </h2> <p class="font-body text-base text-text-secondary max-w-[480px] mx-auto">Connect your repo. Here's what happens when your next PR merges.</p> </div> <!-- Timeline --> <div class="lh-story"> <!-- ═══ BEAT 1: PR merges — text left, card right ═══ --> <div class="lh-beat" data-reveal> <div class="lh-beat-left"> <div class="lh-beat-title">Code merges. CI is green.</div> <div class="lh-beat-desc">All checks pass. Ships to production.</div> </div> <div class="lh-beat-node"><div class="lh-node-dot lh-node-dot--violet text-accent-violet"><svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="18" r="3"></circle><circle cx="6" cy="6" r="3"></circle><path d="M6 21V9a9 9 0 0 0 9 9"></path></svg></div></div> <div class="lh-beat-right"> <div class="lh-card lh-glow-hover bg-[#0a0a0b]"> <div class="p-[18px_20px]"> <div class="text-[14.5px] font-semibold text-text-primary mb-2">Refactor payment — migrate to PaymentIntents</div> <div class="text-[12px] mb-3.5"> <span class="text-accent-violet font-semibold">● Merged</span> </div> <div class="pt-3 border-t border-[rgba(255,255,255,0.08)] flex items-center gap-2 flex-wrap text-[11px] text-text-muted font-medium tracking-[0.02em]">
PIE SCANNING → AFFECTED FLOWS
<span class="lh-flow-tag">checkout flow</span> <span class="lh-flow-tag">refund flow</span> </div> </div> </div> </div> </div> <!-- ═══ BEAT 2: Pie finds the bug — card left, text right ═══ --> <div class="lh-beat" data-reveal> <div class="lh-beat-left lh-beat-left--visual"> <!-- Browser Mockup Card --> <div class="lh-bento-card bg-[#0a0a0b] p-0 overflow-visible relative lh-glow-hover"> <div class="absolute inset-0 rounded-[1.25rem] overflow-hidden bg-[radial-gradient(ellipse_at_center,rgba(139,92,246,0.1)_0%,transparent_70%)] pointer-events-none"></div> <div class="bg-[rgba(255,255,255,0.03)] border-b border-[rgba(255,255,255,0.05)] px-4 py-3 flex items-center gap-4 rounded-t-[1.25rem] overflow-hidden"> <div class="flex items-center gap-1.5 opacity-50"> <div class="w-3 h-3 rounded-full bg-red-400"></div> <div class="w-3 h-3 rounded-full bg-amber-400"></div> <div class="w-3 h-3 rounded-full bg-accent-success"></div> </div> <div class="lh-hpw-url bg-[rgba(255,255,255,0.05)] rounded px-3 py-1 text-[12px] font-mono text-[rgba(255,255,255,0.5)] flex-1 text-center truncate">staging.yourapp.com/checkout</div> </div> <div class="p-8 pb-12"> <div class="max-w-[280px] mx-auto bg-[#111113] border border-[rgba(255,255,255,0.05)] rounded-lg p-6 shadow-xl relative text-left"> <div class="border-b border-[rgba(255,255,255,0.05)] pb-3 mb-6 font-medium text-white flex justify-between"> <span>Checkout</span> <span class="text-[rgba(255,255,255,0.3)]">Cart</span> </div> <div class="space-y-4"> <div class="bg-[rgba(255,255,255,0.02)] border border-[rgba(255,255,255,0.05)] p-2 rounded text-[13px] text-white"><a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b6c5d7c4d7def6d5d9dbc6d7d8cf98d5d9db">[email&#160;protected]</a></div> <div class="bg-[rgba(255,255,255,0.02)] border border-[rgba(255,255,255,0.05)] p-2 rounded text-[13px] text-white font-mono">4242 &bull;&bull;&bull;&bull; &bull;&bull;&bull;&bull; 4242</div> <div class="bg-[rgba(239,68,68,0.05)] border border-red-400 p-2 rounded text-[13px] text-red-400 font-bold font-mono shadow-[0_0_15px_rgba(239,68,68,0.2)]">$0.00</div> </div> <div class="mt-6 bg-accent-violet text-white text-center p-2 rounded text-[13px] font-bold">Complete Purchase</div> <!-- Pie cursor pointing at $0.00 field --> <div class="absolute right-[164px] bottom-[72px] lh-pie-cursor"> <!-- Cursor arrow icon --> <img src="/icons/cursor.svg" alt="" width="32" height="32" style="min-width:32px;min-height:32px;" class="drop-shadow-[0_0_8px_rgba(139,92,246,0.5)] relative z-10 -translate-x-6"> <!-- Tooltip extending below cursor --> <div class="absolute top-5 -left-1 bg-[rgba(10,10,12,0.95)] border border-[rgba(239,68,68,0.3)] shadow-[0_10px_30px_rgba(0,0,0,0.8)] rounded-lg px-3 py-2 w-[190px] text-left"> <div class="text-[11px] font-mono text-red-400 font-bold">Checkout Failure</div> </div> </div> </div> </div> </div> </div> <div class="lh-beat-node"><div class="lh-node-dot lh-node-dot--orange text-accent-orange"><svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg></div></div> <div class="lh-beat-right lh-beat-right--text"> <div class="lh-beat-title">Caught! Customers can checkout for free.</div> <div class="lh-beat-desc">Pie opened the app, ran the checkout flow, and caught the $0.00 bug. Code review missed it — the diff looked fine.</div> </div> </div> <!-- ═══ BEAT 3: Fix PR ready — text left, card right ═══ --> <div class="lh-beat" data-reveal> <div class="lh-beat-left"> <div class="lh-beat-title">Minutes later, the fix is ready.</div> <div class="lh-beat-desc">Pie traced the bug, wrote the patch, and opened a PR. Your team reviews and merges.</div> </div> <div class="lh-beat-node"><div class="lh-node-dot lh-node-dot--green text-accent-success"><svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg></div></div> <div class="lh-beat-right"> <div class="lh-card lh-glow-hover bg-[#0a0a0b]"> <div class="p-5"> <div class="flex items-center gap-1.5 text-[12.5px] font-semibold text-accent-success mb-3"> <div class="w-5 h-5 rounded-full bg-[rgba(34,197,94,0.1)] flex items-center justify-center"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6L9 17l-5-5"></path></svg> </div>
Fix verified
</div> <div class="font-display text-[17px] font-semibold text-text-primary tracking-[-0.01em] mb-1.5">fix: checkout total shows $0.00 after discount</div> <div class="flex items-center gap-1.5 text-[11.5px] text-text-muted mb-4"> <div class="w-4 h-4 rounded-full bg-[linear-gradient(135deg,#8B5CF6,#D946EF)] flex items-center justify-center text-[8px] text-white font-bold">P</div>
pie-bot
</div> <!-- Before / After --> <div class="grid grid-cols-2 gap-2 mb-4"> <div class="lh-ba-panel lh-ba-panel--before"> <div class="lh-ba-label">Before</div> <div class="lh-ba-val">$0.00</div> </div> <div class="lh-ba-panel lh-ba-panel--after"> <div class="lh-ba-label">After</div> <div class="lh-ba-val">$49.99</div> </div> </div> <div class="flex items-center gap-3.5 pt-3 border-t border-[rgba(255,255,255,0.08)] text-[11.5px] font-medium"> <span class="flex items-center gap-1 text-accent-success"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6L9 17l-5-5"></path></svg> CI passed</span> <span class="flex items-center gap-1 text-accent-success"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6L9 17l-5-5"></path></svg> No conflicts</span> <span class="flex items-center gap-1 text-accent-success"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6L9 17l-5-5"></path></svg> Ready to merge</span> </div> </div> </div> </div> </div> </div> </div> </section> <section class="max-w-[1120px] mx-auto px-5 lg:px-8 py-[120px]" data-reveal> <div class="text-center mb-16"> <div class="font-mono text-xs font-bold text-accent-violet tracking-[0.1em] uppercase mb-4">Features</div> <h2 class="font-display font-bold text-4xl md:text-5xl text-text-primary tracking-tight">
What Pie catches <span class="text-gradient">for you</span> </h2> </div> <!-- Spotlight card --> <div class="lh-bento-card lh-features-spotlight"> <div class="lh-features-spotlight-copy"> <div class="font-mono text-xs font-bold text-accent-violet tracking-[0.1em] uppercase mb-3">Vision-based testing</div> <h3 class="lh-features-spotlight-headline">Pie finds product bugs. Not coding errors.</h3> <p class="lh-features-spotlight-body">Uses your product like customers do. Catches bugs code review can't.</p> </div> <div class="lh-features-spotlight-artifact" role="img" aria-label="Mock browser showing Pie detecting a pricing bug on an e-commerce product page — price shows $0.00 despite a 25% OFF promotion"> <div class="lh-features-browser"> <div class="lh-features-browser-chrome"> <span class="lh-features-dot lh-features-dot--r"></span> <span class="lh-features-dot lh-features-dot--y"></span> <span class="lh-features-dot lh-features-dot--g"></span> <div class="lh-features-url">staging.acmestore.com</div> </div> <div class="lh-features-browser-content"> <img src="/screenshots/feature_sportlight.png" alt="" class="lh-features-browser-screenshot"> <span class="lh-features-cursor-dot lh-features-cursor-dot-1"></span> <span class="lh-features-cursor-dot lh-features-cursor-dot-2"></span> <span class="lh-features-cursor-dot lh-features-cursor-dot-3"></span> <div class="lh-features-pie-cursor"> <img src="/icons/cursor.svg" alt="" width="26" height="26" class="lh-features-cursor-arrow"> <div class="lh-features-cursor-callout"> <div class="lh-features-cursor-callout-label">Pricing bug</div> <div class="lh-features-cursor-callout-detail">expected $224.99</div> </div> </div> </div> </div> </div> </div> <!-- Supporting strip --> <div class="lh-features-strip"> <!-- Card 1: Autofix --> <article class="lh-bento-card lh-features-strip-card"> <div class="lh-features-strip-icon lh-features-strip-icon--success" aria-hidden="true"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 13l4 4L19 7"></path></svg> </div> <h3 class="lh-features-strip-title">Autofix</h3> <p class="lh-features-strip-desc">Pie finds the bug. Writes the fix. Review the PR, ship it.</p> </article> <!-- Card 2: Coverage stories --> <article class="lh-bento-card lh-features-strip-card"> <div class="lh-features-strip-icon lh-features-strip-icon--danger" aria-hidden="true"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"></circle><path d="M12 8v5"></path><path d="M12 16h.01"></path></svg> </div> <h3 class="lh-features-strip-title">Coverage stories</h3> <p class="lh-features-strip-desc">Full bug reports. Ranked by severity. Know what broke.</p> </article> <!-- Card 3: Auto-tracking --> <article class="lh-bento-card lh-features-strip-card"> <div class="lh-features-strip-icon lh-features-strip-icon--info" aria-hidden="true"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"></circle><path d="M12 7v5l3 2"></path></svg> </div> <h3 class="lh-features-strip-title">Auto-tracking</h3> <p class="lh-features-strip-desc">Push your code. Pie maps the impact. Retests affected flows.</p> </article> <!-- Card 4: Test generation --> <article class="lh-bento-card lh-features-strip-card"> <div class="lh-features-strip-icon lh-features-strip-icon--violet" aria-hidden="true"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 8l-4 4 4 4"></path><path d="M16 8l4 4-4 4"></path><path d="M14 6l-4 12"></path></svg> </div> <h3 class="lh-features-strip-title">Test generation</h3> <p class="lh-features-strip-desc">Pie finds the bug. Writes the test. Locks it down.</p> </article> </div> </section> <section class="max-w-[1120px] mx-auto px-5 lg:px-8 py-[120px]" data-reveal> <div class="text-center"> <div class="font-mono text-xs font-bold text-accent-violet tracking-[0.1em] uppercase mb-4">Zero friction</div> <h2 class="font-display font-bold text-4xl md:text-5xl text-text-primary tracking-tight">
Built for <span class="text-gradient">engineering teams</span> </h2> </div> <div class="lh-team-stat-card"> <div class="lh-team-stat-body"> <div class="lh-team-stat-num">&lt; 5 min</div> <div class="lh-team-stat-label">From setup to first bugs found</div> <div class="lh-team-stat-desc">No scripts. No setup. Nothing to maintain.</div> </div> <div class="lh-team-proof-strip"> <div class="lh-team-proof-cell"> <div class="lh-team-proof-val">1 commit</div> <div class="lh-team-proof-lab">to first results</div> </div> <div class="lh-team-proof-cell"> <div class="lh-team-proof-val">0 steps</div> <div class="lh-team-proof-lab">to set up</div> </div> <div class="lh-team-proof-cell"> <div class="lh-team-proof-val">PRs</div> <div class="lh-team-proof-lab">not tickets</div> </div> </div> </div> <p class="font-body text-lg md:text-body-lg text-text-secondary leading-[1.7] max-w-[680px] mx-auto mt-10 text-center">
Your team already has enough tools to maintain. Pie plugs into your existing workflow, runs in your CI, and delivers fixes as PRs. No DSL to learn. No scripts to debug. No weekly maintenance.
</p> </section> <section class="w-full bg-[rgba(255,255,255,0.01)] border-y border-[rgba(255,255,255,0.05)] py-16" data-reveal> <div class="max-w-[1120px] mx-auto px-5 lg:px-8 text-center"> <h2 class="font-display font-bold text-4xl md:text-5xl text-text-primary mb-12 tracking-tight">
Works with the tools <span class="text-gradient">your team already uses</span> </h2> <div class="flex flex-wrap items-center justify-center gap-x-6 gap-y-4 md:gap-x-14 md:gap-y-8"> <div class="flex items-center gap-2 md:gap-3 text-text-muted hover:text-text-primary transition-colors font-bold text-[15px] md:text-[18px]"> <svg class="w-5 h-5 md:w-6 md:h-6" viewBox="0 0 24 24" fill="currentColor"> <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"></path> </svg> GitHub
</div> <div class="flex items-center gap-2 md:gap-3 text-text-muted hover:text-[#FC6D26] transition-colors font-bold text-[15px] md:text-[18px]"> <svg class="w-5 h-5 md:w-6 md:h-6" viewBox="0 0 24 24" fill="currentColor"> <path d="m23.6 9.593-.033-.086L20.3.98a.851.851 0 0 0-.336-.405.879.879 0 0 0-1.002.07.866.866 0 0 0-.286.406l-2.209 6.76H7.533L5.324 1.051a.857.857 0 0 0-.286-.408.878.878 0 0 0-1.003-.07.858.858 0 0 0-.335.406L.433 9.507l-.032.086a6.066 6.066 0 0 0 2.012 7.01l.011.008.027.02 4.987 3.734 2.468 1.867 1.503 1.136a1.012 1.012 0 0 0 1.222 0l1.503-1.136 2.468-1.867 5.014-3.754.012-.01a6.07 6.07 0 0 0 2.01-7.008z"></path> </svg> GitLab
</div> <div class="flex items-center gap-2 md:gap-3 text-text-muted hover:text-text-primary transition-colors font-bold text-[15px] md:text-[18px]"> <svg class="w-5 h-5 md:w-6 md:h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path> </svg> Web, iOS, Android
</div> <div class="flex items-center gap-2 md:gap-3 text-text-muted hover:text-text-primary transition-colors font-bold text-[15px] md:text-[18px]"> <svg class="w-5 h-5 md:w-6 md:h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path> </svg> Your CI/CD
</div> <div class="flex items-center gap-2 md:gap-3 text-text-muted hover:text-text-primary transition-colors font-bold text-[15px] md:text-[18px] slack-logo"> <svg class="w-5 h-5 md:w-6 md:h-6" viewBox="0 0 24 24"> <path class="slack-red" fill="currentColor" d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313z"></path> <path class="slack-blue" fill="currentColor" d="M8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312z"></path> <path class="slack-green" fill="currentColor" d="M18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312z"></path> <path class="slack-yellow" fill="currentColor" d="M15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"></path> </svg> Slack
</div> </div> </div> </section> <section class="max-w-[1120px] mx-auto px-5 lg:px-8 py-[120px]" data-reveal> <div class="text-center mb-16"> <div class="font-mono text-xs font-bold text-accent-violet tracking-[0.1em] uppercase mb-4">Build vs buy</div> <h2 class="font-display font-bold text-4xl md:text-5xl text-text-primary tracking-tight">
You've probably tried building this <span class="text-gradient">yourself</span> </h2> </div> <dl class="lh-build-ledger" aria-label="Cost of building internal testing tools versus using Pie"> <div class="lh-build-row"> <dt class="lh-build-row-task">Write test scripts</dt> <dd class="lh-build-row-hours">~120 hrs/mo</dd> </div> <div class="lh-build-row"> <dt class="lh-build-row-task">Build CI integration</dt> <dd class="lh-build-row-hours">~80 hrs/mo</dd> </div> <div class="lh-build-row"> <dt class="lh-build-row-task">Wire up alerting</dt> <dd class="lh-build-row-hours">~60 hrs/mo</dd> </div> <div class="lh-build-row"> <dt class="lh-build-row-task">Maintain scripts</dt> <dd class="lh-build-row-hours">~160 hrs/mo</dd> </div> <div class="lh-build-row"> <dt class="lh-build-row-task">Fix when it breaks</dt> <dd class="lh-build-row-hours lh-build-row-hours--warn">~80 hrs/mo</dd> </div> <div class="lh-build-row lh-build-total"> <dt class="lh-build-row-task">Monthly total</dt> <dd class="lh-build-row-hours">500+ hrs/mo</dd> </div> </dl> <div class="lh-build-pie"> <div class="lh-build-pie-copy"> <div class="lh-build-pie-label">Or just use Pie.</div> <div class="lh-build-pie-sub">5 minutes to set up. Maintained by us.</div> </div> <div class="lh-build-pie-hours">0 hrs</div> </div> <blockquote class="lh-build-quote"> <p class="lh-build-quote-text">"I've basically been doing that same workflow on my own, and it would be nice to not have to develop that. That seems like something that's not a core value of our company."</p> <cite class="lh-build-quote-attr">— VP Engineering, 1000+ person engineering org</cite> </blockquote> </section> <section class="max-w-[1120px] mx-auto px-5 lg:px-8 py-[120px]" data-reveal> <div class="text-center mb-16"> <div class="font-mono text-xs font-bold text-accent-violet tracking-[0.1em] uppercase mb-4">What teams are saying</div> <h2 class="font-display font-bold text-4xl md:text-5xl text-text-primary tracking-tight">
Real results from <span class="text-gradient">real teams</span> </h2> </div> <div class="grid md:grid-cols-3 gap-6" data-reveal-stagger> <div class="lh-bento-card lh-glow-hover p-6 flex flex-col justify-between"> <p class="font-body text-[15px] text-text-secondary italic leading-relaxed mb-6">An iOS-only crash that happened after three specific steps? Manual testing never would have caught that. Pie found it on the first scan.</p> <div class="pt-4 border-t border-[rgba(255,255,255,0.06)] mt-auto"> <span class="font-mono text-xs text-text-muted">— Mobile Test Lead, Consumer Tech Startup</span> </div> </div><div class="lh-bento-card lh-glow-hover p-6 flex flex-col justify-between"> <p class="font-body text-[15px] text-text-secondary italic leading-relaxed mb-6">We used to find regressions a week after they shipped. Now we catch them before the PR even merges. It changed how we think about testing.</p> <div class="pt-4 border-t border-[rgba(255,255,255,0.06)] mt-auto"> <span class="font-mono text-xs text-text-muted">— Engineering Manager, Series A Fintech</span> </div> </div><div class="lh-bento-card lh-glow-hover p-6 flex flex-col justify-between"> <p class="font-body text-[15px] text-text-secondary italic leading-relaxed mb-6">The autofix feature is honestly what sold us. Finding bugs is one thing. Getting a PR with the fix already written? That&#39;s next level.</p> <div class="pt-4 border-t border-[rgba(255,255,255,0.06)] mt-auto"> <span class="font-mono text-xs text-text-muted">— Senior Engineer, E-commerce Platform</span> </div> </div> </div> </section> <section id="cta" class="text-center py-[140px] relative" data-reveal> <div class="absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(139,92,246,0.04)_0%,transparent_60%)] pointer-events-none -z-10"></div> <div class="max-w-[720px] mx-auto px-5"> <h2 class="font-display font-bold text-4xl md:text-5xl lg:text-[clamp(44px,6vw,60px)] text-text-primary tracking-tighter leading-[1.05] mb-12">
Your team pushes code.<br><span class="text-gradient">Pie makes sure it actually works.</span> </h2> <a href="https://app.pie.inc/start" target="_blank" class="btn-primary inline-flex mb-6"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-[18px] h-[18px]"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
Try it for free <span class="arrow-wrapper"><span class="arrow"></span></span> </a> <p class="font-body text-sm text-text-muted leading-[1.6] max-w-md mx-auto">
Connect GitHub or GitLab and see results on your actual codebase. It's free, there's no demo to sit through, and nobody's going to call you.
</p> </div> </section> <section class="max-w-[720px] mx-auto px-5 lg:px-8 py-[120px]" data-reveal> <div class="text-center mb-12"> <h2 class="font-display font-bold text-4xl md:text-5xl text-text-primary tracking-tight">
Frequently Asked <span class="text-gradient">Questions</span> </h2> </div> <div class="space-y-0"> <div class="faq-item"> <button class="faq-question"> <span>How is Pie different from code review tools like CodeRabbit or Greptile?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">Code review tools analyze your code. Pie tests your running product. CodeRabbit can tell you if your checkout function looks correct. Pie actually clicks &quot;Buy Now&quot; on staging and confirms the payment goes through. They read diffs. We use the app.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>What does &quot;2-click install&quot; actually mean?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">You authorize Pie on GitHub, pick a repo, and paste your staging URL. That&#39;s it. No SDK, no test scripts, no config files. Pie figures out your user flows automatically by exploring your app.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>How does Pie know what to test?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">Pie reads your commit diffs to understand what changed, then maps that to the user flows it discovered when it first explored your app. If your payment form changed, Pie tests checkout. If you touched the nav, it tests cross-page navigation. It&#39;s not random.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>Does Pie work with mobile apps?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">Yes. Pie tests iOS and Android apps in simulators, not just web. Same 2-click setup. Same autofix PRs. Mobile-specific bugs like gesture failures, deep link issues, and in-app purchase flows are all covered.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>What about false positives?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">Pie only reports bugs it can reproduce. Every finding includes a step-by-step recording of how to trigger it. If Pie reports it, it&#39;s real. No flaky tests, no &quot;works on my machine&quot; arguments.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>How does the autofix feature work?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">When Pie finds a bug, it doesn&#39;t just log it. It traces the issue back to the source code, identifies the likely root cause, and opens a PR with a suggested fix. You review and merge, or reject if it&#39;s wrong. Most fixes merge without changes.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>Is my code safe? Where does it go?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">Pie runs on secure, isolated infrastructure. Your code never leaves your repo, we only read the diffs. Your staging environment is accessed the same way your CI does. We&#39;re SOC 2 compliant. Reach out and we&#39;ll share the documentation.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>What if I already have Playwright or Cypress tests?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">You can run both, or let Pie take over entirely. Pie can analyze your existing test cases and rebuild them using AI, with zero ongoing maintenance. Most teams that migrate see better coverage and stop dealing with flaky tests. We&#39;ll help with the transition.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>What does it cost?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">Pricing scales with your usage. We offer packages for teams of all sizes. Reach out and we&#39;ll put together a quote.</p> </div> </div><div class="faq-item"> <button class="faq-question"> <span>Can I self-host Pie?</span> <svg class="faq-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> </button> <div class="faq-answer"> <p class="font-body text-text-secondary">Not currently. Pie runs as a managed service. For teams with strict data residency requirements, reach out and we&#39;ll discuss options.</p> </div> </div> </div> </section> </div>  <!-- ========================================
       FOOTER
       ======================================== --> <footer class="relative py-16 border-t border-canvas-subtle"> <div class="max-w-1080 mx-auto px-6 md:px-16 lg:px-6"> <div class="grid md:grid-cols-5 gap-12 mb-12"> <!-- Brand --> <div class="md:col-span-1"> <a href="/" class="flex items-center gap-2 mb-4"> <img src="/pielogo.avif" alt="Pie" class="h-8 w-auto"> </a> <p class="font-body text-sm text-text-secondary mb-4">
The quality layer for AI-speed engineering.
</p> <!-- SOC 2 Badge --> <div class="inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-canvas-elevated border border-canvas-subtle"> <svg class="w-4 h-4 text-accent-success" fill="currentColor" viewBox="0 0 20 20"> <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path> </svg> <span class="font-body text-xs text-text-secondary">SOC 2&reg; Certified</span> </div> </div> <!-- Product --> <div> <h4 class="font-display font-semibold text-sm text-text-primary mb-4">Product</h4> <ul class="space-y-3"> <li><a href="/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Home</a></li> <li><a href="/product/pie-qa/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Pie QA</a></li> <li><a href="/product/overview/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Product Overview</a></li> <li><a href="/product/how-it-works/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">How Pie Works</a></li> <li><a href="/product/autonomous-discovery/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Autonomous Discovery</a></li> <li><a href="/product/self-healing-tests/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Self-Healing Tests</a></li> <li><a href="/product/integrations/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Integrations</a></li> <li><a href="/product/custom-tests/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Custom Tests</a></li> <li><a href="/product/security/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Security</a></li> </ul> </div> <!-- Resources --> <div> <h4 class="font-display font-semibold text-sm text-text-primary mb-4">Resources</h4> <ul class="space-y-3"> <li><a href="https://docs.pie.inc/" target="_blank" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Docs</a></li> <li><a href="/blog/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Blog</a></li> <li><a href="/customers/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Case Studies</a></li> <li><a href="/resources/whitepapers/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Whitepapers</a></li> </ul> </div> <!-- Company --> <div> <h4 class="font-display font-semibold text-sm text-text-primary mb-4">Company</h4> <ul class="space-y-3"> <li><a href="https://www.linkedin.com/company/pielabs-inc/jobs/" target="_blank" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Work with us</a></li> <li><a href="https://www.linkedin.com/company/pielabs-inc/" target="_blank" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">LinkedIn</a></li> </ul> </div> <!-- Legal --> <div> <h4 class="font-display font-semibold text-sm text-text-primary mb-4">Legal</h4> <ul class="space-y-3"> <li><a href="/privacy-policy/" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors">Privacy Policy</a></li> </ul> </div> </div> <!-- Copyright --> <div class="pt-8 border-t border-canvas-subtle"> <p class="font-body text-sm text-text-muted text-center">
PieLabs, Inc. &copy; 2026. All rights reserved.
</p> </div> </div> </footer> <!-- ========================================
       JAVASCRIPT
       ======================================== --> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script src="/main.js"></script> <!-- Cookie Consent Banner --> <div id="cookie-banner" style="display:none" class="fixed bottom-0 left-0 right-0 z-50 border-t border-canvas-subtle bg-canvas-elevated/95 backdrop-blur-lg"> <div class="max-w-1080 mx-auto px-6 md:px-16 lg:px-6 py-4 flex flex-col sm:flex-row items-start sm:items-center gap-4 justify-between"> <p class="font-body text-sm text-text-secondary">
We use analytics and session recording tools (Google Analytics, Microsoft Clarity) to improve pie.inc.
<a href="/privacy-policy/" class="text-accent-violet hover:underline ml-1">Privacy Policy</a> </p> <div class="flex items-center gap-3 shrink-0"> <button id="cookie-decline" class="font-body text-sm text-text-secondary hover:text-text-primary transition-colors px-4 py-2 rounded-lg border border-canvas-subtle hover:bg-canvas-base">
Decline
</button> <button id="cookie-accept" class="font-body text-sm font-medium px-4 py-2 rounded-lg bg-accent-violet text-white hover:opacity-90 transition-opacity">
Accept
</button> </div> </div> </div> <script>
    (function() {
      var stored = typeof localStorage !== 'undefined' ? localStorage.getItem('pie_consent') : null;
      if (!stored) {
        document.getElementById('cookie-banner').style.display = 'block';
      }
      document.getElementById('cookie-accept').addEventListener('click', function() {
        localStorage.setItem('pie_consent', 'granted');
        gtag('consent', 'update', { analytics_storage: 'granted', ad_storage: 'granted' });
        dataLayer.push({ event: 'consent_granted' });
        document.getElementById('cookie-banner').style.display = 'none';
      });
      document.getElementById('cookie-decline').addEventListener('click', function() {
        localStorage.setItem('pie_consent', 'denied');
        document.getElementById('cookie-banner').style.display = 'none';
      });
    })();
  </script> </body> </html> <script type="module">const r=new IntersectionObserver(e=>{e.forEach(t=>{t.isIntersecting&&(t.target.classList.add("visible"),r.unobserve(t.target))})},{threshold:.15});document.querySelectorAll("[data-reveal], [data-reveal-stagger]").forEach(e=>{r.observe(e)});document.querySelectorAll(".lh-glow-hover").forEach(e=>{e.addEventListener("mousemove",t=>{const o=e.getBoundingClientRect(),s=t.clientX-o.left,c=t.clientY-o.top;e.style.setProperty("--mouse-x",`${s}px`),e.style.setProperty("--mouse-y",`${c}px`)})});</script>