Here’s a blunt, dev-first teardown of the AI.gov page you shared (Webflow build with heavy animation). I’ve grouped fixes by impact and included copy-pasteable snippets where helpful.


🔴 High-impact bugs & breakages

  1. ReferenceError: DOMPurify is used but never loaded
    • Your GSAP line animation script calls DOMPurify.sanitize(...), but the library isn’t included on the page. This will throw and can short-circuit the block.
    • Fix: add DOMPurify before any code that calls it: <script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.6/dist/purify.min.js" integrity="sha384-5GzHIkqhHDo+YiH2W5Tq8Pz6VNTGgq7n4GvKJ8h6EB9m1o1rQuc8X9mR97tLWR8c" crossorigin="anonymous"></script>
  2. Duplicate GSAP versions
    • You load GSAP 3.11.4 and 3.12.5 (twice) plus CustomEase later. Multiple versions = undefined behavior, extra bytes.
    • Fix: keep one GSAP (latest) and needed plugins, once, after jQuery/Webflow: <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/CustomEase.min.js" crossorigin="anonymous"></script>
  3. Broken/placeholder CSS
    • -webkit-perspective:<some value> is invalid and shipped. Also -webkit-transform-style: preserve is invalid (should be preserve-3d).
    • Fix: .nav-parent, .burger-menu-parent, .flex-cc-h.menu { perspective: 1000px; /* or remove if not needed */ -webkit-backface-visibility: hidden; backface-visibility: hidden; transform-style: preserve-3d; transform: translate3d(0,0,0); }
  4. Event handlers targeting wrong selectors / never firing
    • $('.open').on('tap', ...)tap isn’t a jQuery native event; unless you include a touch library, this will do nothing. Use click.
    • $('.menu-link-parent').on('mouseenter', function(){ $('.menu-text').find('.menu-text').addClass('hover'); });
      • .menu-text doesn’t exist in the markup (you have menu_text-link). This also adds hover to all nodes, not the current one.
    • Fix: $('.open').on('click', function () { $('body').toggleClass('no-scroll'); }); $('.menu-link-parent').on('mouseenter', function () { $(this).find('.menu_text-link').addClass('hover'); }).on('mouseleave', function () { $(this).find('.menu_text-link').removeClass('hover'); });
  5. Transition hijack can block normal navigation
    • You intercept every <a> click and delay navigation for animations. Edge cases (hash links, modified clicks, downloads, router back/forward) are fragile even with your exceptions.
    • Fix (safeguards): ignore modifier keys and same-page hash links: $('a').on('click', function (e) { const a = this; const internal = a.hostname === location.hostname; const hashLink = a.getAttribute('href') && a.getAttribute('href').startsWith('#'); const newTab = a.getAttribute('target') === '_blank'; const modified = e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0; if (!internal || hashLink || newTab || modified) return; e.preventDefault(); // ... trigger transition then window.location = a.href });

🟠 Performance & Core Web Vitals

  1. Hero LCP image
    • Your right-side hero image is the likely LCP. It’s loading="eager" (good), but set priority and async decode: <img src=".../President Donald Trump - AI.Gov.jpg" alt="President Donald Trump" width="3000" height="2000" fetchpriority="high" decoding="async">
    • Consider a smaller max intrinsic width (e.g., 2000px) unless you truly render at 3000px on desktop.
  2. Fonts
    • You load WebFont Loader (Google) + Google Fonts + Adobe Typekit and then hide scrollbars; that’s a lot.
    • Minimize FOIT/FOUT & privacy: either self-host fonts or: <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://use.typekit.net" crossorigin>
    • Add font-display: swap for Google families if you move to CSS @import.
  3. Third-party script bloat
    • You include Splitting CSS but use SplitType JS (different libs). Remove the Splitting CSS includes if you aren’t using Splitting.
    • lenis is included but not initialized anywhere meaningful—drop it if unused.
    • Webflow bundles are loaded three times (three different URLs). If these are split chunks that Webflow requires, fine—but ensure there’s no duplicate functional overlap. Audit network waterfall for redundancy.
  4. Hide scrollbars
    • ::-webkit-scrollbar{width:0} + no-scrollbar class hurts usability. Don’t hide system scrollbars (accessibility).
    • Remove those rules or scope to non-essential overflow containers.
  5. Preconnect critical origins <link rel="preconnect" href="https://cdn.prod.website-files.com" crossorigin> <link rel="preconnect" href="https://d3e54v103j8qbb.cloudfront.net" crossorigin> <link rel="preconnect" href="https://cdnjs.cloudflare.com"> <link rel="preconnect" href="https://cdn.jsdelivr.net">

🟡 Accessibility (WCAG 2.1 AA quick wins)

  1. Motion & prefers-reduced-motion
  • Heavy GSAP/transitions. Provide a global reduction: @media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }
  • Add a visible “Reduce motion” toggle if brand allows.
  1. Keyboard & focus
  • You’ve added global :focus-visible styles (good!). Ensure burger/menu toggles update aria-expanded and trap focus when open; restore on close. const btn = document.querySelector('.navbar_menu-button-copy'); const panel = document.querySelector('.menu_parent'); btn.addEventListener('click', () => { const open = btn.getAttribute('aria-expanded') === 'true'; btn.setAttribute('aria-expanded', String(!open)); panel.hidden = open; (open ? document.body.classList.remove : document.body.classList.add)('no-scroll'); });
  1. Alt text
  • Many images have verbose or brand-heavy alts (e.g., includes “AI.Gov”). For content images, keep alts concise and informative; for decorative brand flourishes, use alt="".
  1. Headings
  • Ensure only one <h1> per page (your hero looks like it’s images and paragraphs). Make your primary headline a true H1.
  1. Color contrast
  • Verify text over gradients and on gray backgrounds (#f0f0f0) meets 4.5:1 minimum, especially the small “SEE IT IN ACTION” label and menu hover states.

🔵 SEO & social

  1. Add og:image / twitter:image
  • You ship title/description cards but no image meta: <meta property="og:image" content="https://www.ai.gov/path/share.jpg"> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="630"> <meta name="twitter:image" content="https://www.ai.gov/path/share.jpg">
  • Ensure the image is static, ≤2 MB, with text-safe margins.
  1. Canonical & robots
  • You have canonical set; also serve a clean XML sitemap and ensure robots.txt allows it.
  1. JSON-LD (Organization + WebSite / SearchAction)
<script type="application/ld+json">
{
  "@context":"https://schema.org",
  "@type":"GovernmentOrganization",
  "name":"AI.gov",
  "url":"https://www.ai.gov/",
  "logo":"https://www.ai.gov/path/logo.png",
  "parentOrganization": {"@type":"GovernmentOrganization","name":"The White House","url":"https://www.whitehouse.gov/"},
  "sameAs": ["https://www.whitehouse.gov/"]
}
</script>

🛡️ Security hygiene

  1. CSP (report-only to start)
  • With many CDNs, start permissive and ratchet down: Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.prod.website-files.com https://d3e54v103j8qbb.cloudfront.net https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://ajax.googleapis.com https://use.typekit.net https://cdn.jsdelivr.net https://unpkg.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.prod.website-files.com; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com https://use.typekit.net https://cdn.prod.website-files.com; frame-src 'self' https:; connect-src 'self' https:; report-uri https://YOUR-endpoint.example/csp;
  1. rel="noopener noreferrer"
  • Add to all target="_blank" links (many external WhiteHouse links already have it, ensure consistency).
  1. Mailchimp embed in footer
  • Confirm you have a published privacy statement for email collection and that form errors/success are announced to screen readers (add role="status" to response containers).

🧼 Code hygiene & small fixes

  1. Remove unused imports
  • Splitting CSS (unused), extra GSAP, unused Lenis; drop them.
  1. Decode images asynchronously
  • For all non-LCP images: <img ... loading="lazy" decoding="async">
  1. Inline styles with filters/transforms
  • Webflow shipped many inline style="opacity:0;filter:blur(5px);transform:...". That’s fine for initial animations but ensure they are removed (or overridden) once animations complete, so content is visible for users with script disabled / blocked.
  1. Avoid hiding scrollbars globally
  • Remove the global ::-webkit-scrollbar { width: 0 } — use it only on decorative carousels if you must, not the document.

📋 “Ready to ticket” checklist

  • Include DOMPurify (or remove its usage).
  • Consolidate GSAP to one version; keep only needed plugins.
  • Fix invalid CSS values (<some value>, preserve-3d).
  • Replace tap with click; fix menu selector .menu_text-link.
  • Safeguard transition-hijack handler for modified/hash links.
  • Mark hero image fetchpriority="high" and decoding="async".
  • Preconnect fonts/CDNs; consider self-hosting fonts.
  • Remove Splitting CSS and unused Lenis if not used.
  • Add prefers-reduced-motion CSS.
  • Ensure burger toggles aria-expanded / focus management.
  • Review image alt text and heading structure.
  • Add og:image / twitter:image and Organization JSON-LD.
  • Add CSP (Report-Only) and rel="noopener noreferrer" to all external links.
  • Remove global scrollbar-hiding CSS.
  • Make Mailchimp responses accessible (role="status").

If you want, I can turn this into a pull request / Webflow custom code block with the cleaned script and meta bundle, or produce a single “production head” include you can drop into the site settings.