From 074f9670f4eb40607a9d69be0166e5681e4cd87d Mon Sep 17 00:00:00 2001 From: Marcellolepoe <67198779+Marcellolepoe@users.noreply.github.com> Date: Wed, 25 Feb 2026 20:24:58 +0800 Subject: [PATCH 1/8] Landing page refresh: hero, sections, waitlist, grid animation, a11y and type fixes Co-authored-by: Cursor --- .../content/backlink-experiment-results.mdx | 179 ++++ apps/seo-www/content/geo-seo-future.mdx | 146 +++ .../content/introducing-fluid-posts.mdx | 68 ++ apps/seo-www/src/routeTree.gen.ts | 42 + .../seo-www/src/routes/-components/footer.tsx | 13 - .../-components/founders/founder-hero.tsx | 191 +--- .../founders/hero-search-engine-carousel.tsx | 175 ++++ .../-components/founders/hero-serp-climb.tsx | 275 +++++ .../founders/landing-page-mockup.tsx | 431 ++++++++ .../founders/landing-sections-demo.tsx | 486 +++++++++ .../-components/founders/serp-climb-v2.tsx | 572 +++++++++++ .../founders/serp-zoom-animation.tsx | 255 +++++ .../seo-www/src/routes/-components/header.tsx | 3 +- .../routes/-components/waitlist-dialog.tsx | 4 +- apps/seo-www/src/routes/blog/index.tsx | 241 ++++- apps/seo-www/src/routes/index.tsx | 950 +++++++++++++++++- apps/seo-www/src/routes/landing-demo.tsx | 14 + apps/seo-www/src/routes/landing-mockup.tsx | 14 + apps/seo-www/src/styles.css | 13 + apps/seo-www/vite.config.ts | 1 + package.json | 1 + packages/ui/src/styles.css | 2 +- 22 files changed, 3844 insertions(+), 232 deletions(-) create mode 100644 apps/seo-www/content/backlink-experiment-results.mdx create mode 100644 apps/seo-www/content/geo-seo-future.mdx create mode 100644 apps/seo-www/content/introducing-fluid-posts.mdx create mode 100644 apps/seo-www/src/routes/-components/founders/hero-search-engine-carousel.tsx create mode 100644 apps/seo-www/src/routes/-components/founders/hero-serp-climb.tsx create mode 100644 apps/seo-www/src/routes/-components/founders/landing-page-mockup.tsx create mode 100644 apps/seo-www/src/routes/-components/founders/landing-sections-demo.tsx create mode 100644 apps/seo-www/src/routes/-components/founders/serp-climb-v2.tsx create mode 100644 apps/seo-www/src/routes/-components/founders/serp-zoom-animation.tsx create mode 100644 apps/seo-www/src/routes/landing-demo.tsx create mode 100644 apps/seo-www/src/routes/landing-mockup.tsx diff --git a/apps/seo-www/content/backlink-experiment-results.mdx b/apps/seo-www/content/backlink-experiment-results.mdx new file mode 100644 index 000000000..adefbb2e9 --- /dev/null +++ b/apps/seo-www/content/backlink-experiment-results.mdx @@ -0,0 +1,179 @@ +--- +title: "We Built 50 Backlinks in 30 Days: Here's What Happened" +description: "An experiment in authority building—testing different backlink strategies and measuring their impact on rankings and traffic." +icon: "FlaskConical" +cover: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?q=80&w=1600&auto=format&fit=crop" +author: "winston" +tags: + - "SEO Experiments" + - "backlinks" + - "case study" + - "authority" +--- + + +This is part of our ongoing SEO Experiments series, where we test common SEO advice and share real results. + + +## The Experiment + +Everyone says backlinks are crucial for SEO. But with so many conflicting strategies—guest posting, broken link building, HARO, digital PR—how do you know what actually works? + +We decided to find out. Over 30 days, we systematically built 50 backlinks using five different methods, tracking the impact on rankings, traffic, and domain authority. + +## The Setup + +**Test site:** A 6-month-old SaaS blog with a Domain Rating (DR) of 15 +**Starting traffic:** ~500 monthly organic visitors +**Target keywords:** 10 commercial-intent terms in the productivity space +**Baseline rankings:** All keywords ranking 15-50 + +### Methods Tested + +We allocated 10 backlinks to each method: + +1. **Guest posting** on niche-relevant blogs (DR 30-50) +2. **Broken link building** on resource pages +3. **HARO/Connectively** responses to journalist queries +4. **Content partnerships** with complementary tools +5. **Link insertions** into existing articles via outreach + +## Results Overview + +| Method | Links Built | Referring Domains | Avg. DR | Traffic Impact | +|--------|------------|-------------------|---------|----------------| +| Guest posting | 10 | 10 | 38 | +12% | +| Broken link building | 8 | 8 | 42 | +8% | +| HARO | 6 | 6 | 61 | +18% | +| Content partnerships | 10 | 5 | 35 | +22% | +| Link insertions | 10 | 10 | 31 | +6% | + +**Total impact:** 66% increase in organic traffic (500 → 830 monthly visitors) + +## Detailed Findings + +### Guest Posting: Reliable but Time-Intensive + +Guest posting delivered consistent results—every pitch that got accepted resulted in a link. However, it required significant time investment: approximately 4 hours per published post including research, writing, and revisions. + +**What worked:** +- Pitching unique angles rather than generic topics +- Targeting sites that had linked to competitors +- Including internal links in the guest post (when allowed) + +**What didn't:** +- Pitching sites outside our niche (low acceptance rate) +- Overly promotional content (rejected or heavily edited) + +### Broken Link Building: High Quality, Low Volume + +The links we secured through broken link building were among the highest quality—resource pages on established sites. However, the success rate was low (8 links from 45 prospects). + +**The process:** +1. Find resource pages in our niche +2. Run them through a broken link checker +3. Identify relevant broken links +4. Create replacement content (or use existing) +5. Pitch the site owner + +**Success rate:** 18% (8/45 prospects) + +### HARO: Best ROI for Authority + +HARO (now Connectively) delivered the highest-authority links with the least effort per link. However, acceptance rates were unpredictable—we submitted 50+ responses to land 6 links. + +**Key insight:** High-DR publications have massive ranking influence. One link from a DR 75 site moved our target keyword from position 23 to position 11. + +**Tips that worked:** +- Responding within 30 minutes of query posting +- Providing specific data or unique insights +- Including credentials and social proof + +### Content Partnerships: Best for Referral Traffic + +Content partnerships—where we collaborated on guides, webinars, or tools with complementary businesses—generated the most referral traffic in addition to SEO value. + +**Example:** We co-created a "Productivity Stack Calculator" with a project management tool. They linked to it from their resources page; we linked to them from ours. Both sites benefited from the shared traffic. + +**Bonus:** These relationships often lead to additional link opportunities over time. + +### Link Insertions: Easiest but Lowest Impact + +Reaching out to site owners with relevant existing content and asking them to add our link was the easiest method—but also the lowest impact. Many of these links were on pages with thin content or low traffic. + +**Best for:** Building link velocity and diversifying anchor text + +## Ranking Changes + +Here's how our target keywords moved during the experiment: + +| Keyword | Starting Position | Ending Position | Change | +|---------|-------------------|-----------------|--------| +| "productivity app comparison" | 23 | 11 | +12 | +| "best task manager 2024" | 31 | 19 | +12 | +| "project management for freelancers" | 18 | 9 | +9 | +| "todo app alternatives" | 45 | 28 | +17 | +| "time tracking software review" | 22 | 14 | +8 | + +Most significant movements came from: +1. High-DR HARO links +2. Links from topically relevant sites (guest posts, partnerships) +3. Links on high-traffic pages (broken link building) + +## What We'd Do Differently + +### Prioritize Quality Over Quantity + +Our initial goal was 50 links. In hindsight, 20 high-quality links would have been more valuable than 50 mixed-quality ones. + +### Start HARO Earlier + +HARO links took the longest to secure (journalist timelines) but had the biggest impact. We'd allocate more time to this channel in future experiments. + +### Build Relationships First + +The content partnerships that worked best came from existing relationships. Cold outreach for partnerships had a much lower success rate. + +## Recommendations by Site Stage + +### New sites (DR < 20) +Focus on: Guest posting, content partnerships +Rationale: Build foundational authority and relationships + +### Growing sites (DR 20-40) +Focus on: HARO, broken link building +Rationale: Secure high-authority links that move the needle + +### Established sites (DR 40+) +Focus on: Digital PR, original research +Rationale: Create link-worthy assets that attract links naturally + +## The Fluid Posts Approach + +At Fluid Posts, we've systematized authority building through our network. Instead of manually building links one-by-one, our members benefit from: + +- **Mutual link exchanges** with relevant businesses +- **Curated partnerships** based on topical alignment +- **Quality controls** that ensure links benefit all parties + +The result: consistent authority growth without the outreach grind. + +## Try It Yourself + +Want to replicate this experiment? Here's a simplified 30-day plan: + +**Week 1:** Set up tracking, identify 20 guest post targets +**Week 2:** Submit 5 guest post pitches, sign up for HARO +**Week 3:** Start broken link prospecting, respond to 10+ HARO queries +**Week 4:** Reach out for content partnerships, follow up on all pitches + +Track your results and share what you learn—we'd love to hear about it. + + + + Build authority through our backlink community. + + + See all our experiment results and case studies. + + diff --git a/apps/seo-www/content/geo-seo-future.mdx b/apps/seo-www/content/geo-seo-future.mdx new file mode 100644 index 000000000..90823081b --- /dev/null +++ b/apps/seo-www/content/geo-seo-future.mdx @@ -0,0 +1,146 @@ +--- +title: "GEO vs SEO: Why AI Search Changes Everything" +description: "Generative Engine Optimization is reshaping how brands get discovered. Here's what you need to know about optimizing for ChatGPT, Perplexity, and AI Overviews." +icon: "Sparkles" +cover: "https://images.unsplash.com/photo-1677442136019-21780ecad995?q=80&w=1600&auto=format&fit=crop" +author: "winston" +tags: + - "SEO Insights" + - "GEO" + - "AI search" + - "strategy" +--- + + +This guide covers the emerging field of Generative Engine Optimization (GEO)—optimizing your content for AI-powered search experiences. + + +## The Search Landscape Is Shifting + +For two decades, SEO meant optimizing for Google's blue links. You'd research keywords, create content, build backlinks, and climb the rankings. Simple enough in theory. + +But 2024 changed everything. ChatGPT now handles millions of search-like queries daily. Google's AI Overviews provide direct answers above traditional results. Perplexity offers citation-driven research experiences. And this is just the beginning. + +## What Is GEO? + +**Generative Engine Optimization (GEO)** is the practice of optimizing content to be surfaced, cited, and recommended by AI systems. While traditional SEO focuses on ranking in search results, GEO focuses on being included in AI-generated responses. + +The key difference? AI systems don't just rank pages—they synthesize information, cite sources, and directly answer user questions. Your content needs to be the source they draw from. + +## How AI Systems Evaluate Content + +AI search engines evaluate content differently than traditional search: + +### 1. Factual Accuracy and Citations + +AI systems prefer content that makes verifiable claims with clear sources. They cross-reference information across multiple pages before including it in responses. + +**What this means for you:** +- Include specific data points and statistics +- Cite reputable sources +- Update content when information changes +- Avoid vague or unsupported claims + +### 2. Comprehensive Coverage + +AI systems are trained to provide complete answers. Content that thoroughly addresses a topic is more likely to be cited than surface-level overviews. + +**What this means for you:** +- Create definitive guides rather than thin content +- Address related questions within your content +- Structure information clearly with headers and lists +- Include multiple perspectives when relevant + +### 3. Entity Recognition + +AI models understand entities—people, places, organizations, concepts—and their relationships. Content that clearly establishes entity connections is easier for AI to process and cite. + +**What this means for you:** +- Use consistent naming for your brand and products +- Link to authoritative sources that define key concepts +- Include structured data (Schema.org markup) +- Create content that positions your brand as an authority on specific topics + +## The GEO Playbook + +Here's how to optimize your content for AI search: + +### Write for Direct Answers + +AI systems often pull content that directly answers questions. Structure your content accordingly: + +``` +❌ "Many factors influence pricing..." +✅ "The average cost of X is $500-2000, depending on Y and Z." +``` + +### Create Question-Focused Content + +AI systems heavily weight content that matches user query patterns. Include natural questions and answers throughout your content: + +- "What is [topic]?" +- "How does [topic] work?" +- "Why is [topic] important?" +- "[Topic] vs [alternative]: which is better?" + +### Build Topical Authority + +AI systems prefer citing sources with demonstrated expertise. To build authority: + +1. Create comprehensive hub pages on core topics +2. Link related content together with clear internal links +3. Publish consistently on your focus areas +4. Get cited by other authoritative sources + +### Optimize for Citations + +When AI systems cite your content, they typically pull: + +- Your page title +- A brief description or key sentence +- Your domain name + +Make sure these elements clearly communicate your value proposition. + +## SEO and GEO: Not Either/Or + +Here's the good news: most GEO best practices align with modern SEO. High-quality, authoritative content that answers user questions will perform well in both traditional and AI search. + +The key is to think about search holistically: + +| Traditional SEO | GEO | +|-----------------|-----| +| Keywords in titles | Clear, descriptive titles | +| Backlinks | Citations from authoritative sources | +| Page speed | Easily parseable content | +| User engagement | Comprehensive, accurate information | + +## How Fluid Posts Approaches GEO + +At Fluid Posts, every piece of content we create is optimized for both traditional search engines and AI systems. Our approach includes: + +- **Structured content** that AI can easily parse and cite +- **Factual, well-researched information** that passes AI accuracy checks +- **Strategic internal linking** that establishes topical authority +- **Regular updates** to keep content current and accurate + +The result? Our clients don't just rank on Google—they get cited on ChatGPT. + +## Getting Started + +Ready to optimize for the AI search era? Here's your action plan: + +1. **Audit your existing content** for direct answers and citations +2. **Identify gaps** where AI systems might look for information +3. **Create comprehensive guides** on your core topics +4. **Monitor AI search results** for your key terms +5. **Track citations** across ChatGPT, Perplexity, and AI Overviews + + + + Master the fundamentals of finding topics that drive traffic. + + + Automate your SEO and GEO strategy today. + + diff --git a/apps/seo-www/content/introducing-fluid-posts.mdx b/apps/seo-www/content/introducing-fluid-posts.mdx new file mode 100644 index 000000000..23ef75229 --- /dev/null +++ b/apps/seo-www/content/introducing-fluid-posts.mdx @@ -0,0 +1,68 @@ +--- +title: "Introducing Fluid Posts: Complete SEO, Automated" +description: "We built Fluid Posts to help growing businesses achieve organic visibility without the complexity. Here's how we're changing SEO." +icon: "Rocket" +cover: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?q=80&w=1600&auto=format&fit=crop" +author: "winston" +tags: + - "Fluid Posts Updates" + - "announcement" + - "product" +--- + + +Fluid Posts is now available for early access. Sign up today to get started with automated SEO. + + +## Why We Built Fluid Posts + +Traditional SEO is broken. Agencies charge thousands per month, deliver opaque results, and lock you into long contracts. In-house teams require expensive hires and constant management. And DIY approaches? They demand expertise most founders simply don't have time to develop. + +We asked ourselves: what if SEO could be as simple as setting your goals and letting the system work for you? + +## The Fluid Posts Approach + +Fluid Posts combines AI-powered content strategy with automated publishing and a growing authority network. Here's what makes us different: + +### 1. Strategy That Understands Your Business + +During onboarding, we learn about your business, target audience, and goals. Our system then generates tailored content strategies—not generic keyword lists, but actual publishing plans designed to capture high-intent traffic. + +### 2. Content That Ranks + +Every article is optimized for both search engines and AI systems like ChatGPT and Google's AI Overview. We don't just stuff keywords—we create genuinely useful content that builds trust with your audience. + +### 3. Authority That Compounds + +Our backlink network connects you with relevant businesses in complementary spaces. As you give and receive quality backlinks, your domain authority grows—and with it, your ability to rank for increasingly competitive terms. + +## Early Results + +We've been testing Fluid Posts with a small group of businesses, and the results speak for themselves: + +- **Dispute Ninja** went from 0 to 1,000 monthly visitors in their first month, ranking #1 on Google and getting cited on ChatGPT +- **QuantumByte** saw clicks increase 486% and impressions jump 906% within 30 days + +These aren't outliers—they're the norm when strategy, content, and authority work together. + +## What's Next + +We're just getting started. In the coming months, we'll be rolling out: + +- Advanced analytics and performance tracking +- AI-powered chat for SEO questions and insights +- Expanded CMS integrations +- More robust authority network matching + +## Get Started + +Ready to see what automated SEO can do for your business? [Sign up for early access](/signup) and join the growing community of brands that are building organic traffic on autopilot. + + + + Get started with Fluid Posts today. + + + Learn more about our approach to SEO. + + diff --git a/apps/seo-www/src/routeTree.gen.ts b/apps/seo-www/src/routeTree.gen.ts index 71125fc64..fe43ff394 100644 --- a/apps/seo-www/src/routeTree.gen.ts +++ b/apps/seo-www/src/routeTree.gen.ts @@ -12,6 +12,8 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as WhoWeAreRouteImport } from './routes/who-we-are' import { Route as SeoExpertsRouteImport } from './routes/seo-experts' import { Route as ReferralRouteImport } from './routes/referral' +import { Route as LandingMockupRouteImport } from './routes/landing-mockup' +import { Route as LandingDemoRouteImport } from './routes/landing-demo' import { Route as BlogRouteRouteImport } from './routes/blog/route' import { Route as IndexRouteImport } from './routes/index' import { Route as BlogIndexRouteImport } from './routes/blog/index' @@ -37,6 +39,16 @@ const ReferralRoute = ReferralRouteImport.update({ path: '/referral', getParentRoute: () => rootRouteImport, } as any) +const LandingMockupRoute = LandingMockupRouteImport.update({ + id: '/landing-mockup', + path: '/landing-mockup', + getParentRoute: () => rootRouteImport, +} as any) +const LandingDemoRoute = LandingDemoRouteImport.update({ + id: '/landing-demo', + path: '/landing-demo', + getParentRoute: () => rootRouteImport, +} as any) const BlogRouteRoute = BlogRouteRouteImport.update({ id: '/blog', path: '/blog', @@ -87,6 +99,8 @@ const ApiBlogSearchRoute = ApiBlogSearchRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/blog': typeof BlogRouteRouteWithChildren + '/landing-demo': typeof LandingDemoRoute + '/landing-mockup': typeof LandingMockupRoute '/referral': typeof ReferralRoute '/seo-experts': typeof SeoExpertsRoute '/who-we-are': typeof WhoWeAreRoute @@ -100,6 +114,8 @@ export interface FileRoutesByFullPath { } export interface FileRoutesByTo { '/': typeof IndexRoute + '/landing-demo': typeof LandingDemoRoute + '/landing-mockup': typeof LandingMockupRoute '/referral': typeof ReferralRoute '/seo-experts': typeof SeoExpertsRoute '/who-we-are': typeof WhoWeAreRoute @@ -115,6 +131,8 @@ export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/blog': typeof BlogRouteRouteWithChildren + '/landing-demo': typeof LandingDemoRoute + '/landing-mockup': typeof LandingMockupRoute '/referral': typeof ReferralRoute '/seo-experts': typeof SeoExpertsRoute '/who-we-are': typeof WhoWeAreRoute @@ -131,6 +149,8 @@ export interface FileRouteTypes { fullPaths: | '/' | '/blog' + | '/landing-demo' + | '/landing-mockup' | '/referral' | '/seo-experts' | '/who-we-are' @@ -144,6 +164,8 @@ export interface FileRouteTypes { fileRoutesByTo: FileRoutesByTo to: | '/' + | '/landing-demo' + | '/landing-mockup' | '/referral' | '/seo-experts' | '/who-we-are' @@ -158,6 +180,8 @@ export interface FileRouteTypes { | '__root__' | '/' | '/blog' + | '/landing-demo' + | '/landing-mockup' | '/referral' | '/seo-experts' | '/who-we-are' @@ -173,6 +197,8 @@ export interface FileRouteTypes { export interface RootRouteChildren { IndexRoute: typeof IndexRoute BlogRouteRoute: typeof BlogRouteRouteWithChildren + LandingDemoRoute: typeof LandingDemoRoute + LandingMockupRoute: typeof LandingMockupRoute ReferralRoute: typeof ReferralRoute SeoExpertsRoute: typeof SeoExpertsRoute WhoWeAreRoute: typeof WhoWeAreRoute @@ -205,6 +231,20 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ReferralRouteImport parentRoute: typeof rootRouteImport } + '/landing-mockup': { + id: '/landing-mockup' + path: '/landing-mockup' + fullPath: '/landing-mockup' + preLoaderRoute: typeof LandingMockupRouteImport + parentRoute: typeof rootRouteImport + } + '/landing-demo': { + id: '/landing-demo' + path: '/landing-demo' + fullPath: '/landing-demo' + preLoaderRoute: typeof LandingDemoRouteImport + parentRoute: typeof rootRouteImport + } '/blog': { id: '/blog' path: '/blog' @@ -290,6 +330,8 @@ const BlogRouteRouteWithChildren = BlogRouteRoute._addFileChildren( const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, BlogRouteRoute: BlogRouteRouteWithChildren, + LandingDemoRoute: LandingDemoRoute, + LandingMockupRoute: LandingMockupRoute, ReferralRoute: ReferralRoute, SeoExpertsRoute: SeoExpertsRoute, WhoWeAreRoute: WhoWeAreRoute, diff --git a/apps/seo-www/src/routes/-components/footer.tsx b/apps/seo-www/src/routes/-components/footer.tsx index d2fa938eb..de1d406c1 100644 --- a/apps/seo-www/src/routes/-components/footer.tsx +++ b/apps/seo-www/src/routes/-components/footer.tsx @@ -6,19 +6,6 @@ import { import { Link } from "@tanstack/react-router"; const links = [ - { - group: "Solution", - items: [ - { - title: "Founders", - href: "/", - }, - { - title: "Freelancers", - href: "/seo-experts", - }, - ], - }, { group: "Company", items: [ diff --git a/apps/seo-www/src/routes/-components/founders/founder-hero.tsx b/apps/seo-www/src/routes/-components/founders/founder-hero.tsx index b153a3ce5..8b5b438ce 100644 --- a/apps/seo-www/src/routes/-components/founders/founder-hero.tsx +++ b/apps/seo-www/src/routes/-components/founders/founder-hero.tsx @@ -1,197 +1,10 @@ -import { MoveRight, Search } from "@rectangular-labs/ui/components/icon"; -import { buttonVariants } from "@rectangular-labs/ui/components/ui/button"; import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { useState } from "react"; -import { WaitListDialog } from "../waitlist-dialog"; +import { SerpClimbDemo } from "./serp-climb-v2"; export const FounderHero = () => { - const [dnOk, setDnOk] = useState(true); - const [chatgptOk, setChatgptOk] = useState(true); - - const GoogleMark = () => ( - - Google - - - - - - ); - - const ChatGptMark = () => ( -
- {chatgptOk ? ( - ChatGPT setChatgptOk(false)} - src="/logos/chatgpt.png" - /> - ) : ( - - ChatGPT - {/* fallback mark */} - - - )} -
- ); - return (
-
-

- Your{" "} - SEO Co-Founder. -

-

- Fluid Posts is an End-to-End SEO tool built to think like a business - owner: self-critical, data-driven, and focused on growth. -

-
- - Join the waitlist - - } - /> -

- Launching End-Jan 2026 -

-
-
-

- Early results -

-

- In early pilots, we helped 2 clients reach{" "} - #1 on Google{" "} - and appear on{" "} - ChatGPT for - targeted terms within a month. -

- -
-
-

- Pilot highlight -

- -
- {/* Google SERP mock */} -
-
- - Google -
-
- - gambling chargebacks -
-
-

- #1 result -

-

- Gambling Chargebacks: How to Dispute Online Casino... -

-
- {dnOk ? ( - Dispute Ninja setDnOk(false)} - src="/logos/dispute-ninjas.png" - /> - ) : ( -
- DN -
- )} - - Dispute Ninjas - -
-
-
- - {/* ChatGPT mock */} -
-
- - - - ChatGPT -
- -
- - best chargeback softwares -
- -
-

- #5 Result -

-

- Top Chargeback Management & Prevention Software -

-
- {dnOk ? ( - Dispute Ninja setDnOk(false)} - src="/logos/dispute-ninjas.png" - /> - ) : ( -
- DN -
- )} - - Dispute Ninjas - -
-
-
-
-
-
-
-
+
); }; diff --git a/apps/seo-www/src/routes/-components/founders/hero-search-engine-carousel.tsx b/apps/seo-www/src/routes/-components/founders/hero-search-engine-carousel.tsx new file mode 100644 index 000000000..5b3a02293 --- /dev/null +++ b/apps/seo-www/src/routes/-components/founders/hero-search-engine-carousel.tsx @@ -0,0 +1,175 @@ +import { AnimatePresence, motion } from "motion/react"; +import type { ReactNode } from "react"; +import { useEffect, useMemo, useState } from "react"; + +type Engine = { + id: string; + label: string; + node: ReactNode; +}; + +function ClaudeMark() { + return ( + + Claude + + + + ); +} + +function GeminiMark() { + return ( + + Gemini + + + + + + + + + + + ); +} + +function AiOverviewsMark() { + return ( +
+ AI +
+ ); +} + +function GoogleMark() { + return ( + + Google + + + + + + ); +} + +function ChatGptMark({ onError }: { onError: () => void }) { + return ( + ChatGPT + ); +} + +export function HeroSearchEngineCarousel() { + const [chatgptOk, setChatgptOk] = useState(true); + const engines = useMemo(() => { + const base: Engine[] = [ + { id: "google", label: "Google", node: }, + { + id: "chatgpt", + label: "ChatGPT", + node: chatgptOk ? ( + setChatgptOk(false)} /> + ) : ( +
+ GPT +
+ ), + }, + { id: "aio", label: "AI Overviews", node: }, + { id: "claude", label: "Claude", node: }, + { id: "gemini", label: "Gemini", node: }, + ]; + return base; + }, [chatgptOk]); + + const [index, setIndex] = useState(0); + + useEffect(() => { + if (engines.length === 0) return; + const id = window.setInterval(() => { + setIndex((i) => (i + 1) % engines.length); + }, 1000); + return () => window.clearInterval(id); + }, [engines.length]); + + const active = engines[index] ?? engines[0]; + if (!active) return null; + + return ( + + + + + {active.label} + {active.node} + + + + + ); +} diff --git a/apps/seo-www/src/routes/-components/founders/hero-serp-climb.tsx b/apps/seo-www/src/routes/-components/founders/hero-serp-climb.tsx new file mode 100644 index 000000000..486c76acc --- /dev/null +++ b/apps/seo-www/src/routes/-components/founders/hero-serp-climb.tsx @@ -0,0 +1,275 @@ +import { motion, useAnimationControls } from "motion/react"; +import { useEffect, useMemo, useState } from "react"; + +type Row = { + id: string; + title: string; + url: string; + snippet: string; + isBrand?: boolean; +}; + +const ROW_H = 86; +const VISIBLE = 4; +const HOLD_START_MS = 180; +const HOLD_TOP_MS = 800; + +const easePremium: [number, number, number, number] = [0.22, 1, 0.36, 1]; + +function clamp(n: number, min: number, max: number) { + return Math.max(min, Math.min(max, n)); +} + +export function HeroSerpClimb() { + const controls = useAnimationControls(); + const [phase, setPhase] = useState<"idle" | "climbing" | "top">("idle"); + + const rows = useMemo( + () => [ + { + id: "a", + title: "Competitor A — SEO services", + url: "competitor-a.com", + snippet: "A short description of a competing offer.", + }, + { + id: "b", + title: "Competitor B — Content & SEO", + url: "competitor-b.com", + snippet: "Another result with a calm, realistic snippet.", + }, + { + id: "brand", + title: "Your brand — AI SEO that compounds", + url: "yourbrand.com", + snippet: "Automates strategy, writing, optimization, and publishing.", + isBrand: true, + }, + { + id: "c", + title: "Competitor C — SEO agency", + url: "competitor-c.com", + snippet: "A third competitor result with muted styling.", + }, + { + id: "d", + title: "Competitor D — SEO tool", + url: "competitor-d.com", + snippet: "Yet another competitor, still muted in the UI.", + }, + { + id: "e", + title: "Competitor E — Growth platform", + url: "competitor-e.com", + snippet: "Generic competitor snippet for realism.", + }, + ], + [], + ); + + const brandIndex = rows.findIndex((r) => r.isBrand); + const startIndex = clamp(brandIndex - 2, 0, rows.length - VISIBLE); + const topIndex = clamp(brandIndex - 0, 0, rows.length - VISIBLE); + + const startY = -(startIndex * ROW_H); + const topY = -(topIndex * ROW_H); + + useEffect(() => { + let cancelled = false; + + async function loop() { + if (cancelled) return; + + setPhase("idle"); + await controls.set({ y: startY, opacity: 1 }); + + await new Promise((r) => setTimeout(r, HOLD_START_MS)); + if (cancelled) return; + + setPhase("climbing"); + + await controls.start({ + y: topY, + transition: { duration: 1.35, ease: easePremium }, + }); + + if (cancelled) return; + setPhase("top"); + + await new Promise((r) => setTimeout(r, HOLD_TOP_MS)); + if (cancelled) return; + + await controls.start({ + opacity: 0, + transition: { duration: 0.16, ease: easePremium }, + }); + await controls.set({ y: startY }); + await controls.start({ + opacity: 1, + transition: { duration: 0.12, ease: easePremium }, + }); + + void loop(); + } + + void loop(); + return () => { + cancelled = true; + }; + }, [controls, startY, topY]); + + return ( +
+
+

+ push your brand atop search +

+ +
+
+
+ {/* top bar */} +
+
+
+ 🔎 +
+
+ your brand +
+
+
+ {phase === "climbing" + ? "Ranking automatically…" + : phase === "top" + ? "Rank secured." + : "Indexing…"} +
+
+ + {/* viewport */} +
+ {/* cinematic vignette */} +
+
+
+
+ + + {rows.map((r, idx) => { + const isBrand = !!r.isBrand; + + return ( +
+ {/* rank column */} +
+ {idx + 1} +
+ + {/* favicon */} +
+
+
+ + {/* content */} +
+ {/* brand highlight */} + {isBrand && ( + + )} + +
+
+ {r.title} +
+
+ {r.url} +
+
+ {r.snippet} +
+ + {isBrand && phase === "top" && ( +
+ Rank #1 + + Compounding +
+ )} +
+
+
+ ); + })} + +
+ + {/* subtle footer strip */} +
+
+ Search results (simulated) +
+
+ Fluid Posts +
+
+
+
+
+
+
+ ); +} diff --git a/apps/seo-www/src/routes/-components/founders/landing-page-mockup.tsx b/apps/seo-www/src/routes/-components/founders/landing-page-mockup.tsx new file mode 100644 index 000000000..31da77ab3 --- /dev/null +++ b/apps/seo-www/src/routes/-components/founders/landing-page-mockup.tsx @@ -0,0 +1,431 @@ +import { motion, AnimatePresence } from "motion/react"; +import { useState } from "react"; + +// ============================================ +// SHARED BACKGROUND - Gradient Mesh (recommended) +// ============================================ + +function GradientBackground({ variant = "hero" }: { variant?: "hero" | "light" | "subtle" }) { + const intensity = variant === "hero" ? 1 : variant === "light" ? 0.6 : 0.3; + + return ( +
+ + + +
+ ); +} + +// ============================================ +// HERO SECTION +// ============================================ + +function HeroSection() { + return ( +
+ + +
+

+ + Take Your Brand to the + + + Top of Search. + +

+ +

+ We create strategic content and build authoritative backlinks that push your brand + to #1 on Google, AI Overviews, and ChatGPT. +

+ +
+ + +
+ + {/* Placeholder for carousel graphic */} +
+
+
+ [Hero Carousel Graphic] +
+
+
+
+
+ ); +} + +// ============================================ +// SOCIAL PROOF - Single Quote +// ============================================ + +function SocialProofSection() { + return ( +
+
+
+ "We went from page 5 to ranking #1 for our main keyword in under 90 days. + The ROI paid for itself in the first month." +
+
+
+
+
Sarah Chen
+
Head of Growth, TechStartup
+
+
+
+
+ ); +} + +// ============================================ +// HOW IT WORKS +// ============================================ + +function HowItWorksSection() { + const steps = [ + { + num: "01", + title: "Strategic Content", + desc: "We research your market and create high-quality content optimized for both search engines and AI systems.", + }, + { + num: "02", + title: "Authority Links", + desc: "We build backlinks from trusted, relevant sources that signal authority to Google and AI platforms.", + }, + { + num: "03", + title: "Rank & Dominate", + desc: "Watch your brand climb to #1 and stay there. We monitor, adjust, and keep you on top.", + }, + ]; + + return ( +
+ + +
+
+

+ How We Get You to #1. +

+

+ A proven system that combines content excellence with strategic link building. +

+
+ +
+ {steps.map((step) => ( +
+ {step.num} +

{step.title}

+

{step.desc}

+
+ ))} +
+
+
+ ); +} + +// ============================================ +// RESULTS - Mini Case Study +// ============================================ + +function ResultsSection() { + return ( +
+
+
+
+
+ +
+
+

+ Real Results. +

+

+ Don't take our word for it. Here's what happens when we work together. +

+
+ + {/* Mini Case Study */} +
+
+
+
Before
+
Page 5
+
Invisible to customers
+
+ +
+ +
+ +
+
After 90 Days
+
#1
+
Dominating search
+
+
+ +
+
+
312%
+
Traffic increase
+
+
+
47
+
Keywords on page 1
+
+
+
8.2x
+
ROI in 6 months
+
+
+ +
+

"FluidPosts transformed our entire organic strategy."

+

— Marketing Director, B2B SaaS Company

+
+
+
+
+ ); +} + +// ============================================ +// FEATURES / WHAT YOU GET +// ============================================ + +function FeaturesSection() { + const features = [ + { + title: "AI-Optimized Content", + desc: "Content engineered to rank on Google AND get cited by ChatGPT, Claude, and AI Overviews.", + icon: "M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z", + }, + { + title: "Authority Backlinks", + desc: "High-quality links from real, relevant websites. No spam, no shortcuts, just real authority.", + icon: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1", + }, + { + title: "Rank Tracking", + desc: "Real-time monitoring across Google, Bing, and AI platforms. Know exactly where you stand.", + icon: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z", + }, + { + title: "Competitor Analysis", + desc: "We reverse-engineer what's working for your competitors so you can outrank them.", + icon: "M15 12a3 3 0 11-6 0 3 3 0 016 0z M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z", + }, + ]; + + return ( +
+ + +
+
+

+ Everything You Need. +

+

+ A complete system for dominating search—traditional and AI-powered. +

+
+ +
+ {features.map((feature) => ( +
+
+ + + +
+
+

{feature.title}

+

{feature.desc}

+
+
+ ))} +
+
+
+ ); +} + +// ============================================ +// CTA SECTION +// ============================================ + +function CTASection() { + return ( +
+ + +
+

+ Ready to Rank #1? +

+

+ Join 50+ brands that have transformed their search presence. + Let's discuss how we can get you to the top. +

+
+ + +
+
+
+ ); +} + +// ============================================ +// FAQ SECTION +// ============================================ + +function FAQSection() { + const faqs = [ + { + q: "How long until I see results?", + a: "Most clients see meaningful ranking improvements within 60-90 days. SEO is a long-term play, but our approach accelerates results significantly.", + }, + { + q: "Do you guarantee #1 rankings?", + a: "No one can guarantee specific rankings—anyone who does is lying. What we guarantee is a proven process, transparent reporting, and relentless optimization.", + }, + { + q: "How is this different from other SEO agencies?", + a: "We focus specifically on the new landscape: Google + AI platforms. Most agencies are still stuck in 2015. We're building for where search is going.", + }, + { + q: "What kind of backlinks do you build?", + a: "Real editorial links from relevant, authoritative sites. No PBNs, no spam, no shortcuts. Quality over quantity, always.", + }, + ]; + + const [openIndex, setOpenIndex] = useState(null); + + return ( +
+
+

+ Questions? +

+ +
+ {faqs.map((faq, i) => ( +
+ + + {openIndex === i && ( + +
+ {faq.a} +
+
+ )} +
+
+ ))} +
+
+
+ ); +} + +// ============================================ +// FOOTER +// ============================================ + +function Footer() { + return ( +
+
+
+
FluidPosts
+
+ + + +
+
© 2024 FluidPosts
+
+
+
+ ); +} + +// ============================================ +// FULL PAGE +// ============================================ + +export function LandingPageMockup() { + return ( +
+ + + + + + + +
+
+ ); +} diff --git a/apps/seo-www/src/routes/-components/founders/landing-sections-demo.tsx b/apps/seo-www/src/routes/-components/founders/landing-sections-demo.tsx new file mode 100644 index 000000000..ab72359f6 --- /dev/null +++ b/apps/seo-www/src/routes/-components/founders/landing-sections-demo.tsx @@ -0,0 +1,486 @@ +import { motion } from "motion/react"; + +// ============================================ +// CONTINUOUS LIQUID GRADIENT BACKGROUND +// This flows seamlessly across the entire page +// ============================================ + +export function LiquidGradientBackground() { + return ( +
+ {/* Subtle top gradient - light mode */} +
+ {/* Dark mode gradient */} +
+ {/* Single subtle accent - light mode */} +
+ {/* Dark mode accent */} +
+
+ ); +} + +// ============================================ +// DEMO PAGE SHOWCASING ALL THEMES +// ============================================ + +// Theme 1: Gradient Beams (diagonal light rays) +function GradientBeamsBackground() { + return ( +
+
+ + + +
+ ); +} + +// Theme 2: Morphing Blob (single large animated shape) +function MorphingBlobBackground() { + return ( +
+ +
+ ); +} + +// Theme 3: Gradient Stripes (angled color bands) +function GradientStripesBackground() { + return ( +
+
+
+
+ ); +} + +// Theme 4: Spotlight Effect (dramatic top-down light) +function SpotlightBackground() { + return ( +
+
+ +
+
+ ); +} + +// Theme 5: Particle Field (floating dots with depth) +function ParticleFieldBackground() { + const particles = Array.from({ length: 40 }, (_, i) => ({ + id: i, + size: Math.random() * 4 + 2, + x: Math.random() * 100, + y: Math.random() * 100, + duration: Math.random() * 10 + 15, + delay: Math.random() * 5, + opacity: Math.random() * 0.3 + 0.1, + })); + + return ( +
+
+ {particles.map((p) => ( + + ))} +
+
+ ); +} + +// Theme 6: Glassmorphism Layers (stacked frosted panels) +function GlassLayersBackground() { + return ( +
+
+ + + +
+ ); +} + +// Theme 7: Noise Gradient (textured gradient) +function NoiseGradientBackground() { + return ( +
+
+ +
+
+
+ ); +} + +// Theme 8: Liquid Gradient (flowing color blend) - STANDALONE VERSION +function LiquidGradientBackgroundStandalone() { + return ( +
+ +
+ ); +} + +// Theme 9: Geometric Shapes (floating abstract forms) +function GeometricShapesBackground() { + return ( +
+
+ + + + +
+
+ ); +} + +// Theme 10: Aurora Waves (flowing aurora borealis) +function AuroraWavesBackground() { + return ( +
+
+ + +
+ ); +} + +// Theme 11: Split Gradient (bold color division) +function SplitGradientBackground() { + return ( +
+
+ + +
+
+ ); +} + +// Theme 12: Prism Light (refracted light effect) +function PrismLightBackground() { + return ( +
+
+ + +
+ ); +} + +// ============================================ +// DEMO SECTIONS +// ============================================ + +function Section({ bg, label, labelColor, description }: { + bg: React.ReactNode; + label: string; + labelColor: string; + description: string; +}) { + return ( +
+ {bg} +
+
+ + {label} + +
+

+ + Take Your Brand to the + + + Top of Search. + +

+

+ {description} +

+
+
+ ); +} + +// ============================================ +// COMBINED DEMO PAGE +// ============================================ + +export function LandingSectionsDemo() { + return ( +
+
} + label="Theme 1: Gradient Beams" + labelColor="bg-blue-100 text-blue-700" + description="Animated diagonal light rays. Dynamic, premium, catches attention without overwhelming." + /> +
} + label="Theme 2: Morphing Blob" + labelColor="bg-violet-100 text-violet-700" + description="Single large shape that morphs and rotates. Hypnotic, modern, very unique." + /> +
} + label="Theme 3: Gradient Stripes" + labelColor="bg-indigo-100 text-indigo-700" + description="Angled color bands. Bold, structured, editorial feel. Very intentional." + /> +
} + label="Theme 4: Spotlight" + labelColor="bg-sky-100 text-sky-700" + description="Dramatic top-down light cone. Draws focus to content, theatrical." + /> +
} + label="Theme 5: Particle Field" + labelColor="bg-cyan-100 text-cyan-700" + description="Floating dots with depth. Tech-forward, alive, sophisticated." + /> +
} + label="Theme 6: Glass Layers" + labelColor="bg-emerald-100 text-emerald-700" + description="Stacked frosted glass panels. Depth, dimension, very modern UI feel." + /> +
} + label="Theme 7: Noise Gradient" + labelColor="bg-teal-100 text-teal-700" + description="Textured gradient with grain. Editorial, tactile, premium print feel." + /> +
} + label="Theme 8: Liquid Gradient" + labelColor="bg-purple-100 text-purple-700" + description="Smoothly transitioning colors. Hypnotic, fluid, very polished." + /> +
} + label="Theme 9: Geometric Shapes" + labelColor="bg-pink-100 text-pink-700" + description="Floating abstract forms. Playful but professional, distinctive." + /> +
} + label="Theme 10: Aurora Waves" + labelColor="bg-amber-100 text-amber-700" + description="Flowing aurora borealis from top. Dramatic, ethereal, striking." + /> +
} + label="Theme 11: Split Gradient" + labelColor="bg-orange-100 text-orange-700" + description="Bold diagonal color division. Architectural, confident, modern." + /> +
} + label="Theme 12: Prism Light" + labelColor="bg-rose-100 text-rose-700" + description="Refracted light beams with rainbow hints. Innovative, eye-catching, tech-forward." + /> +
+ ); +} diff --git a/apps/seo-www/src/routes/-components/founders/serp-climb-v2.tsx b/apps/seo-www/src/routes/-components/founders/serp-climb-v2.tsx new file mode 100644 index 000000000..bbc391305 --- /dev/null +++ b/apps/seo-www/src/routes/-components/founders/serp-climb-v2.tsx @@ -0,0 +1,572 @@ +import { motion, useAnimationControls, AnimatePresence } from "motion/react"; +import { useEffect, useState, useCallback } from "react"; +import { WaitListDialog } from "../waitlist-dialog"; + +const ROW_H = 96; +const VISIBLE_ROWS = 3; +const VIEWPORT_H = ROW_H * VISIBLE_ROWS; + +const CLIMB_DURATION = 1.6; +const HOLD_START_MS = 800; +const HOLD_TOP_MS = 200; +const CURSOR_MOVE_DURATION = 0.18; +const CURSOR_HOLD_MS = 350; +const EASE: [number, number, number, number] = [0.25, 0.1, 0.25, 1]; + +const TRANSITION_DELAY = 250; +const GRAPHIC_HEIGHT = 520; + +// ============================================ +// GOOGLE SERP COMPONENT +// ============================================ + +function GoogleLogo() { + return ( + + + + + + + + + ); +} + +function SearchBar({ query }: { query: string }) { + return ( +
+ + + + {query} +
+ ); +} + +function SerpResultRow({ + name, url, snippet, isBrand, isBlurred, isAtTop, isClicked, +}: { + name: string; url: string; snippet: string; isBrand?: boolean; isBlurred: boolean; isAtTop?: boolean; isClicked?: boolean; +}) { + return ( + + {isBrand && ( + + )} +
{url}
+ + {name} + +
{snippet}
+
+ ); +} + +function MouseCursor({ isVisible, isClicking }: { isVisible: boolean; isClicking: boolean }) { + return ( + + + + + + ); +} + +function GoogleSerpGraphic({ onComplete }: { onComplete: () => void }) { + const competitorControls = useAnimationControls(); + const brandControls = useAnimationControls(); + const [phase, setPhase] = useState<"idle" | "climbing" | "top" | "cursor" | "click">("idle"); + + const competitors = [ + { id: "c1", name: "Competitor 1 — Industry Solutions", url: "competitor1.com", snippet: "Professional services for your business..." }, + { id: "c2", name: "Competitor 2 — Industry Solutions", url: "competitor2.com", snippet: "Professional services for your business..." }, + { id: "c3", name: "Competitor 3 — Industry Solutions", url: "competitor3.com", snippet: "Professional services for your business..." }, + { id: "c4", name: "Competitor 4 — Industry Solutions", url: "competitor4.com", snippet: "Professional services for your business..." }, + { id: "c5", name: "Competitor 5 — Industry Solutions", url: "competitor5.com", snippet: "Professional services for your business..." }, + { id: "c6", name: "Competitor 6 — Industry Solutions", url: "competitor6.com", snippet: "Professional services for your business..." }, + { id: "c7", name: "Competitor 7 — Industry Solutions", url: "competitor7.com", snippet: "Professional services for your business..." }, + { id: "c8", name: "Competitor 8 — Industry Solutions", url: "competitor8.com", snippet: "Professional services for your business..." }, + { id: "c9", name: "Competitor 9 — Industry Solutions", url: "competitor9.com", snippet: "Professional services for your business..." }, + ]; + + const competitorStartY = -ROW_H * (competitors.length - 2); + const competitorEndY = ROW_H; + const brandStartY = ROW_H * 2; + const brandEndY = 0; + + useEffect(() => { + let cancelled = false; + const run = async () => { + if (cancelled) return; + setPhase("idle"); + competitorControls.set({ y: competitorStartY }); + brandControls.set({ y: brandStartY }); + + await new Promise((r) => setTimeout(r, HOLD_START_MS)); + if (cancelled) return; + setPhase("climbing"); + + await Promise.all([ + brandControls.start({ y: brandEndY, transition: { duration: CLIMB_DURATION, ease: EASE } }), + competitorControls.start({ y: competitorEndY, transition: { duration: CLIMB_DURATION, ease: EASE } }), + ]); + if (cancelled) return; + setPhase("top"); + + await new Promise((r) => setTimeout(r, HOLD_TOP_MS)); + if (cancelled) return; + setPhase("cursor"); + + await new Promise((r) => setTimeout(r, CURSOR_MOVE_DURATION * 1000 + 80)); + if (cancelled) return; + setPhase("click"); + + await new Promise((r) => setTimeout(r, CURSOR_HOLD_MS)); + if (cancelled) return; + onComplete(); + }; + void run(); + return () => { cancelled = true; }; + }, [competitorControls, brandControls, competitorStartY, brandStartY, onComplete]); + + const isClimbing = phase === "climbing"; + const isAtTop = phase === "top" || phase === "cursor" || phase === "click"; + const showCursor = phase === "cursor" || phase === "click"; + const isClicked = phase === "click"; + + return ( +
+
+
+ +
+
+ All + Images + Videos + News +
+
+
+ + {competitors.map((c) => ( + + ))} + + + + + +
+
+
+ ); +} + +// ============================================ +// GOOGLE AI OVERVIEW COMPONENT (Light mode) +// ============================================ + +function GeminiSparkle() { + return ( + + + + + + + + + + ); +} + +function AIOverviewGraphic({ onComplete }: { onComplete: () => void }) { + const [phase, setPhase] = useState<"idle" | "thinking" | "typing" | "highlight" | "done">("idle"); + + useEffect(() => { + let cancelled = false; + const run = async () => { + if (cancelled) return; + setPhase("idle"); + await new Promise((r) => setTimeout(r, 300)); + if (cancelled) return; + setPhase("thinking"); + await new Promise((r) => setTimeout(r, 800)); + if (cancelled) return; + setPhase("typing"); + await new Promise((r) => setTimeout(r, 600)); + if (cancelled) return; + setPhase("highlight"); + await new Promise((r) => setTimeout(r, 1200)); + if (cancelled) return; + setPhase("done"); + await new Promise((r) => setTimeout(r, 500)); + if (cancelled) return; + onComplete(); + }; + void run(); + return () => { cancelled = true; }; + }, [onComplete]); + + const isThinking = phase === "thinking"; + const showText = phase === "typing" || phase === "highlight" || phase === "done"; + const highlightBrand = phase === "highlight" || phase === "done"; + + return ( +
+
+ {/* Header */} +
+ + AI Overview +
+ + + +
+
+ + {/* Content */} +
+ {/* Thinking indicator */} + + {isThinking && ( + + + + + Thinking... + + )} + + + {/* Main content */} + + {showText && ( + +

+ The best product for your needs is{" "} + + Your Brand + . +

+ +

+ Based on customer reviews and expert analysis,{" "} + + Your Brand + + {" "}is the top-rated solution in its category. +

+ + {/* Source citation inline */} + + {highlightBrand && ( + + + + + yourbrand.com + + )} + +
+ )} +
+
+
+
+ ); +} + +// ============================================ +// CHATGPT COMPONENT (Light mode with logo) +// ============================================ + +function ChatGPTLogo() { + return ( + + + + ); +} + +function ChatGPTGraphic({ onComplete }: { onComplete: () => void }) { + const [phase, setPhase] = useState<"idle" | "typing" | "show" | "sources" | "done">("idle"); + + useEffect(() => { + let cancelled = false; + const run = async () => { + if (cancelled) return; + setPhase("idle"); + await new Promise((r) => setTimeout(r, 400)); + if (cancelled) return; + setPhase("typing"); + await new Promise((r) => setTimeout(r, 800)); + if (cancelled) return; + setPhase("show"); + await new Promise((r) => setTimeout(r, 600)); + if (cancelled) return; + setPhase("sources"); + await new Promise((r) => setTimeout(r, 1000)); + if (cancelled) return; + setPhase("done"); + await new Promise((r) => setTimeout(r, 400)); + if (cancelled) return; + onComplete(); + }; + void run(); + return () => { cancelled = true; }; + }, [onComplete]); + + const showResponse = phase === "show" || phase === "sources" || phase === "done"; + const showSources = phase === "sources" || phase === "done"; + + return ( +
+
+ {/* Header with logo */} +
+ + ChatGPT +
+ + {/* Chat area */} +
+ {/* User message - pill style on right */} +
+
+

best product for my needs

+
+
+ + {/* Assistant response */} +
+ {phase === "typing" && ( +
+ +
+ + + +
+
+ )} + + + {showResponse && ( + +

+ The best product for your needs is{" "} + + Your Brand + . +

+ + + {showSources && ( + +

+ It's consistently rated #1 for quality, customer satisfaction, and value. +

+ + {/* Source citation */} +
+ + + + yourbrand.com + + + +
+
+ )} +
+
+ )} +
+
+
+ + {/* Input bar */} +
+
+ + + + Message ChatGPT + + + +
+
+
+
+ ); +} + +// ============================================ +// CAROUSEL WRAPPER +// ============================================ + +const GRAPHICS = [ + { key: "google", label: "Google", component: GoogleSerpGraphic }, + { key: "ai-overview", label: "AI Overview", component: AIOverviewGraphic }, + { key: "chatgpt", label: "ChatGPT", component: ChatGPTGraphic }, +]; + +export function SerpClimbDemo() { + const [currentGraphic, setCurrentGraphic] = useState(0); + + const handleComplete = useCallback(() => { + setTimeout(() => { + setCurrentGraphic((prev) => (prev + 1) % GRAPHICS.length); + }, TRANSITION_DELAY); + }, []); + + const current = GRAPHICS[currentGraphic]; + const CurrentComponent = current?.component; + + return ( +
+ {/* Subtle green glow - lighter in light mode, stronger in dark mode */} +
+
+
+
+
+

+ + Take Your Brand to the + + + Top of Search. + +

+ + {/* Subheading and CTA */} +
+

+ Fluid Posts is the end-to-end SEO/GEO tool that automates organic rankings. +

+ + Join the Waitlist + + } + /> +
+ +
+ + + {CurrentComponent ? : null} + + +
+ + {/* Tab-style indicators */} +
+
+ {GRAPHICS.map((g) => ( + + ))} +
+
+
+
+ ); +} diff --git a/apps/seo-www/src/routes/-components/founders/serp-zoom-animation.tsx b/apps/seo-www/src/routes/-components/founders/serp-zoom-animation.tsx new file mode 100644 index 000000000..638457ac0 --- /dev/null +++ b/apps/seo-www/src/routes/-components/founders/serp-zoom-animation.tsx @@ -0,0 +1,255 @@ +import { motion, useAnimationControls } from "motion/react"; +import { useEffect, useMemo, useState } from "react"; + +const CARD_H = 68; +const GAP = 12; +const STEP = CARD_H + GAP; +const VIEWPORT_H = 232; + +type Ghost = { + id: string; + urlW: "w-16" | "w-20" | "w-24"; + titleW: "w-36" | "w-40" | "w-44" | "w-48"; + dim?: boolean; +}; + +function SkeletonLine({ w }: { w: string }) { + return
; +} + +function GhostResult({ ghost }: { ghost: Ghost }) { + return ( +
+
+
+
+
+
+ + +
+
+
+ ); +} + +function BrandResult() { + return ( +
+
+
+
+
+
+
+
+
+
+
+
+ + Your Brand + +
+
+
+
+ ); +} + +function rotateDownBy(arr: T[], n: number): T[] { + if (arr.length === 0) return arr; + const k = ((n % arr.length) + arr.length) % arr.length; + if (k === 0) return arr; + return [...arr.slice(-k), ...arr.slice(0, -k)]; +} + +function makeGhosts(seed: number): Ghost[] { + const urlWidths: Ghost["urlW"][] = ["w-16", "w-20", "w-24"]; + const titleWidths: Ghost["titleW"][] = ["w-36", "w-40", "w-44", "w-48"]; + + return Array.from({ length: 12 }, (_, i) => ({ + id: `g-${seed}-${i}`, + urlW: urlWidths[(seed + i) % urlWidths.length] ?? "w-20", + titleW: titleWidths[(seed * 3 + i) % titleWidths.length] ?? "w-40", + dim: i % 5 === 0, + })); +} + +export function SerpZoomAnimation() { + const bgControls = useAnimationControls(); + const brandControls = useAnimationControls(); + const cutControls = useAnimationControls(); + const vignetteControls = useAnimationControls(); + + const [ghosts, setGhosts] = useState(() => makeGhosts(0)); + const [boosting, setBoosting] = useState(false); + + const brandStartY = useMemo(() => VIEWPORT_H - CARD_H - 16, []); + const brandEndY = useMemo(() => 12, []); + + useEffect(() => { + let cancelled = false; + const CLIMB_STEPS = 3; + const CLIMB_BG_Y = CLIMB_STEPS * STEP; + + const run = async () => { + let seed = 1; + + bgControls.set({ y: 0, opacity: 0.95, filter: "blur(0px)" }); + brandControls.set({ y: brandStartY, scale: 0.98 }); + cutControls.set({ opacity: 0 }); + vignetteControls.set({ opacity: 0.16 }); + + while (!cancelled) { + // Act I: start low + setBoosting(false); + await Promise.all([ + bgControls.start({ y: 0, transition: { duration: 0.35 } }), + brandControls.start({ + y: brandStartY, + scale: 0.985, + transition: { duration: 0.35, ease: "easeOut" }, + }), + vignetteControls.start({ + opacity: 0.14, + transition: { duration: 0.35, ease: "easeOut" }, + }), + ]); + + // Act II: cinematic climb + setBoosting(true); + await Promise.all([ + brandControls.start({ + y: brandEndY, + scale: 1.01, + transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] }, + }), + bgControls.start({ + y: CLIMB_BG_Y, + opacity: 0.9, + filter: "blur(1.5px)", + transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] }, + }), + vignetteControls.start({ + opacity: 0.28, + transition: { duration: 0.28, ease: "easeOut" }, + }), + ]); + + // Act III: settle at top + setBoosting(false); + await Promise.all([ + brandControls.start({ + scale: 1, + transition: { duration: 0.18, ease: "easeOut" }, + }), + bgControls.start({ + filter: "blur(0px)", + opacity: 0.92, + transition: { duration: 0.22, ease: "easeOut" }, + }), + ]); + + // Hold + await brandControls.start({ + y: brandEndY, + transition: { duration: 1.0, ease: "linear" }, + }); + + // Film cut to hide reset + await cutControls.start({ + opacity: 1, + transition: { duration: 0.12, ease: "easeIn" }, + }); + + setGhosts((prev) => rotateDownBy(prev, CLIMB_STEPS)); + setGhosts(makeGhosts(seed)); + seed += 1; + bgControls.set({ y: 0, opacity: 0.95, filter: "blur(0px)" }); + brandControls.set({ y: brandStartY, scale: 0.98 }); + vignetteControls.set({ opacity: 0.14 }); + + await cutControls.start({ + opacity: 0, + transition: { duration: 0.18, ease: "easeOut" }, + }); + } + }; + + void run(); + return () => { + cancelled = true; + }; + }, [ + bgControls, + brandControls, + brandEndY, + brandStartY, + cutControls, + vignetteControls, + ]); + + const brandShadow = boosting + ? "0 22px 50px rgba(99, 102, 241, 0.12)" + : "0 12px 28px rgba(0,0,0,0.10)"; + + return ( +
+ {/* Cinematic vignette */} + + + {/* Cut overlay for seamless looping */} + + +
+
+
+ +
+ {/* Background SERP stack (moves down) */} + + {ghosts.map((g) => ( +
+ +
+ ))} +
+ + {/* Brand (moves from bottom to top) */} + + + +
+
+
+ ); +} diff --git a/apps/seo-www/src/routes/-components/header.tsx b/apps/seo-www/src/routes/-components/header.tsx index 17512cb6f..47223e844 100644 --- a/apps/seo-www/src/routes/-components/header.tsx +++ b/apps/seo-www/src/routes/-components/header.tsx @@ -5,8 +5,7 @@ import { AnimatePresence, motion } from "motion/react"; import { useState } from "react"; const menuItems = [ - { name: "Founders", href: "/" }, - { name: "SEO Experts", href: "/seo-experts" }, + { name: "Blog", href: "/blog" }, { name: "Referral", href: "/referral" }, { name: "About us", href: "/who-we-are" }, ]; diff --git a/apps/seo-www/src/routes/-components/waitlist-dialog.tsx b/apps/seo-www/src/routes/-components/waitlist-dialog.tsx index c3eb7a032..93737ca96 100644 --- a/apps/seo-www/src/routes/-components/waitlist-dialog.tsx +++ b/apps/seo-www/src/routes/-components/waitlist-dialog.tsx @@ -179,13 +179,13 @@ export function WaitListDialog({ trigger, className }: Props) { ) : null}
- + + ))} + + +
+ + {/* Main content area */} +
+ {/* Search bar */} +
+
+ + setSearchQuery(e.target.value)} + className="w-full rounded-xl border border-neutral-200 bg-white py-3 pr-4 pl-12 text-neutral-900 placeholder:text-neutral-400 focus:border-emerald-500 focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-neutral-700 dark:bg-neutral-900 dark:text-white dark:focus:border-emerald-400 dark:placeholder:text-neutral-500" + /> +
+
+ + {/* Mobile categories */} +
+ {CATEGORIES.map((cat) => ( + + ))} +
+ + {/* Posts grid */} + {filteredPosts.length === 0 ? ( +
+

No articles found.

+
+ ) : ( + +
+
+
+ ); } diff --git a/apps/seo-www/src/routes/index.tsx b/apps/seo-www/src/routes/index.tsx index 3bd5a72ac..598ce7fe5 100644 --- a/apps/seo-www/src/routes/index.tsx +++ b/apps/seo-www/src/routes/index.tsx @@ -1,11 +1,10 @@ import { createFileRoute } from "@tanstack/react-router"; -import { FounderCTA } from "~/routes/-components/founders/founder-cta"; -import { FounderGrowth } from "~/routes/-components/founders/founder-growth"; -import { FounderHero } from "~/routes/-components/founders/founder-hero"; -import { FounderIntervention } from "~/routes/-components/founders/founder-intervention"; -import { FounderStrategist } from "~/routes/-components/founders/founder-strategist"; -import { FounderTransparency } from "~/routes/-components/founders/founder-transparency"; -import { FounderWhatItIs } from "~/routes/-components/founders/founder-what-it-is"; +import { motion, AnimatePresence } from "motion/react"; +import { useState, useMemo, useEffect, useCallback } from "react"; +import { Logo } from "@rectangular-labs/ui/components/icon"; +import { SerpClimbDemo } from "~/routes/-components/founders/serp-climb-v2"; +import { LiquidGradientBackground } from "~/routes/-components/founders/landing-sections-demo"; +import { WaitListDialog } from "~/routes/-components/waitlist-dialog"; export const Route = createFileRoute("/")({ component: App, @@ -28,16 +27,937 @@ export const Route = createFileRoute("/")({ }), }); +// ============================================ +// SOCIAL PROOF - Single Quote +// ============================================ + +function SocialProofSection() { + return ( +
+ {/* Subtle dot pattern */} +
+
+
+
+
+ "Our website ranked #1 for relevant keywords within a month of using Fluid Posts." +
+

+ Bowen Xue · Founder, Dispute Ninja +

+
+
+ ); +} + +// ============================================ +// ANIMATED NETWORK GRAPH +// ============================================ + +function NetworkGraph() { + const nodes = useMemo(() => { + const generated: Array<{ id: number; x: number; y: number; size: number; opacity: number }> = []; + for (let i = 0; i < 80; i++) { + generated.push({ + id: i, + x: Math.random() * 100, + y: Math.random() * 100, + size: Math.random() * 8 + 3, + opacity: Math.random() * 0.6 + 0.2, + }); + } + return generated; + }, []); + + const connections = useMemo(() => { + const lines: Array<{ from: number; to: number; opacity: number }> = []; + for (let i = 0; i < nodes.length; i++) { + const numConnections = Math.floor(Math.random() * 3) + 1; + for (let j = 0; j < numConnections; j++) { + const target = Math.floor(Math.random() * nodes.length); + if (target !== i) { + lines.push({ from: i, to: target, opacity: Math.random() * 0.3 + 0.1 }); + } + } + } + return lines; + }, [nodes]); + + return ( +
+ +
+ ); +} + +// ============================================ +// COMPLETE SEO, AUTOMATED +// ============================================ + +function JourneySection() { + return ( +
+ {/* Grid pattern with subtle fade - animated */} +
+ +
+
+
+
+

+ Complete SEO, automated. +

+

+ From strategy to publishing—we handle it all. +

+ {/* Decorative line */} +
+
+ + {/* Step 1: Content Strategy */} +
+
+
+

+ 01 + Content Strategy +

+

+ Based on your onboarding, we research your business, target users, and tailor strategies to reach your audience. +

+
    +
  • + + Custom strategy based on your business goals +
  • +
  • + + SEO-optimized articles written for you +
  • +
  • + + Automated publishing to your CMS +
  • +
+
+
+ {/* Strategy mockup - Toothbrush business example */} +
+
+
+ Suggestion +
+

Electric Toothbrush Buyer's Guide Cluster

+

Goal: 12,000 impressions per month

+
+
+
+

Motivation

+

+ High-intent buyers searching "best electric toothbrush" are ready to purchase. Capturing these queries drives qualified leads directly to your product pages. +

+
+
+

Description

+

+ Create comparison guides targeting "how to choose a toothbrush", "electric vs manual toothbrush", and "best toothbrush for sensitive teeth". +

+
+
+
+ + + +
+
+
+
+
+ + {/* Step 2: Authority Network */} +
+
+
+ +
+
+

+ 02 + Authority Network +

+

+ We pass trusted backlinks across our network, strengthening domain authority and compounding visibility. +

+
+
+
+
+
+ ); +} + +// ============================================ +// RESULTS - Two Client Cards (AirOps style) +// ============================================ + +function ResultsSection() { + return ( +
+ {/* Circle grid pattern */} +
+ +
+
+
+

+ Real Results. +

+
+
+ +
+ {/* Dispute Ninja Card */} +
+
+

DisputeNinja

+

B2B SaaS

+
+
+
+ 0 → 1,000 + monthly visitors +
+
+ + #1 on Google for target keywords +
+
+ + Cited on ChatGPT +
+
+

Results achieved within 1 month

+
+ + {/* QuantumByte Card */} +
+
+

QuantumByte

+

B2C SaaS

+
+
+
+ +486% + clicks +
+
+ +906% + impressions +
+
+

Results achieved within 1 month

+
+
+
+
+ ); +} + +// ============================================ +// FEATURE ICONS +// ============================================ + +function PerformanceIcon({ className }: { className?: string }) { + return ( + + ); +} + +function AuditIcon({ className }: { className?: string }) { + return ( + + ); +} + +function ArticleIcon({ className }: { className?: string }) { + return ( + + ); +} + +function InsightsIcon({ className }: { className?: string }) { + return ( + + ); +} + +function ChatIcon({ className }: { className?: string }) { + return ( + + ); +} + +// ============================================ +// FEATURES - THE WHOLE SUITE (Light mode with platform render) +// ============================================ + +function FeaturesSection() { + const [activeTab, setActiveTab] = useState<"performance" | "strategies" | "chat">("performance"); + const [isAutoPlaying, setIsAutoPlaying] = useState(true); + + const tabs = ["performance", "strategies", "chat"] as const; + + const cycleTab = useCallback(() => { + if (isAutoPlaying) { + setActiveTab((current) => { + const currentIndex = tabs.indexOf(current); + const nextIndex = (currentIndex + 1) % tabs.length; + return tabs[nextIndex] ?? "performance"; + }); + } + }, [isAutoPlaying, tabs]); + + useEffect(() => { + const interval = setInterval(cycleTab, 5000); + return () => clearInterval(interval); + }, [cycleTab]); + + const handleTabClick = (tab: typeof activeTab) => { + setIsAutoPlaying(false); + setActiveTab(tab); + setTimeout(() => setIsAutoPlaying(true), 15000); + }; + + const featureGroups = [ + { + title: "Performance Tracking", + icon: PerformanceIcon, + items: null, + desc: "Track key metrics like clicks and impressions for your whole website, and within clusters we suggest.", + }, + { + title: "Self-Auditing", + icon: AuditIcon, + items: null, + desc: "Fluid Posts audits its performance biweekly and shares its honest assessment with you.", + }, + { + title: "Article Generation", + icon: ArticleIcon, + items: ["Auto Image Generation", "SEO-Optimized Articles", "Organic Product Mentions", "Auto Publishing with CMS Integration"], + desc: null, + }, + { + title: "Business Insights", + icon: InsightsIcon, + items: null, + desc: "Actionable product and service insights and recommendations based on organic performance.", + }, + { + title: "Chat About Anything", + icon: ChatIcon, + items: null, + desc: "Have questions about your SEO, GEO, or business insights? Just ask chat.", + }, + ]; + + return ( +
+ {/* Same grid pattern as Complete SEO - with subtle flow animation */} +
+ +
+
+
+
+

+ The Whole Suite. And More. +

+

+ Fluid Posts is the only point of contact you need for SEO. Monitor performance, create articles, + ask questions, and watch it audit itself biweekly. +

+
+
+ +
+ {/* Interactive Platform Mockup */} +
+ {/* Tab switcher */} +
+ + + +
+ + {/* Platform mockup - with dark mode support */} +
+
+
+
+
+ FluidPosts +
+ + + {activeTab === "performance" && ( + +
+
+

BrightSmile Dental Co

+

Monitor clicks, impressions, and top queries

+
+
+ Last 28 days +
+
+
+
+

Total Clicks

+

4,821

+

+892%

+
+
+

Total Impressions

+

1.2M

+

+1,247%

+
+
+
+

Clicks & Impressions over time

+ +
+
+ )} + + {activeTab === "strategies" && ( + +
+

Active Strategies

+

Strategies currently executing

+
+
+
+
+ Active +
+
Electric Toothbrush Buyer's Guide
+

Goal: 12,000 impressions per month

+
+
+
+ Suggestion +
+
Dental Care Tips for Sensitive Teeth
+

Goal: 8,000 impressions per month

+
+
+
+ )} + + {activeTab === "chat" && ( + +
+

Chat

+

Ask anything about your SEO performance

+
+
+ {/* User message */} +
+
+ How has performance been this last week compared to the previous week, and why? +
+
+ {/* AI response */} +
+
+

Great question! This week showed a 23% increase in impressions compared to last week.

+

The main driver was your article "Best Electric Toothbrush 2025" which gained traction on Google's featured snippets...

+

.....

+
+
+
+ {/* Input bar */} +
+ + +
+
+ )} +
+
+
+ + {/* Feature list - grouped with icons */} +
+ {featureGroups.map((group) => ( +
+
+ +
+
+

{group.title}

+ {group.desc && ( +

{group.desc}

+ )} + {group.items && ( +
    + {group.items.map((item) => ( +
  • • {item}
  • + ))} +
+ )} +
+
+ ))} +
+
+
+
+ ); +} + +// ============================================ +// FLUID POSTS LOGO COMPONENT +// ============================================ + +function FluidPostsLogo({ className, centered }: { className?: string; centered?: boolean }) { + return ( +
+ + Fluid Posts +
+ ); +} + +// ============================================ +// PRICING - COMPARISON SECTION +// ============================================ + +function PricingSection() { + return ( +
+ {/* Dot pattern - same as Real Results */} +
+ +
+
+
+

+ Pricing. +

+

+ We believe SEO should be accessible to businesses of all sizes. That's why we're priced competitively—a fraction of traditional agencies, with better results. +

+
+
+ +
+ {/* Traditional Agency */} +
+ {/* Header section - price aligned with other cards */} +
+
+

Traditional SEO Agency

+
+
+ $3,000-$10,000 + /mo +
+
+ + {/* Features section */} +
+

What you get:

+
    +
  • + + 3-4 Articles / month +
  • +
  • + + 6-12 month lock-in period +
  • +
  • + + Monthly Reporting +
  • +
+ +

What you don't get:

+
    +
  • + + Real-time traffic updates +
  • +
  • + + Search strategy +
  • +
  • + + Transparent Self-auditing +
  • +
+
+
+ + {/* Fluid Posts - HIGHLIGHTED */} +
+
+ BEST FOR SMALL BUSINESSES +
+ {/* Header section - price aligned with other cards */} +
+
+ +
+
+ $99 + /mo +
+
+ $199/mo + 50% OFF +
+
+ + {/* Features section */} +
+

What you get:

+
    +
  • + + 5 GEO/SEO-optimized articles/month +
  • +
  • + + 1 quality backlink/month +
  • +
  • + + Clear strategies upon onboarding +
  • +
  • + + Self-auditing platform +
  • +
  • + + Automated CMS publishing +
  • +
  • + + Control over published content +
  • +
+
+ + + Join the waitlist + + } + /> +
+ + {/* Enterprise - HIGHLIGHTED */} +
+
+ BEST FOR ENTERPRISES +
+ {/* Header section - price aligned with other cards */} +
+
+ + Fluid Posts Enterprise +
+
+ Custom +
+

Accelerated results for serious growth

+
+ + {/* Features section */} +
+

What you get:

+
    +
  • + + 30+ SEO-optimized articles/month +
  • +
  • + + 3+ quality backlinks/month +
  • +
  • + + Direct contact with founders +
  • +
  • + + Personalized onboarding +
  • +
  • + + Quicker results +
  • +
+
+ + + Join the waitlist + + } + /> +
+
+
+
+ ); +} + +// ============================================ +// CTA SECTION +// ============================================ + +function CTASection() { + return ( +
+
+

+ Let's Get Ranking. +

+

+ Unlock the value of SEO for your business today, and watch visibility compound while you sit and watch. +

+
+ + Join the waitlist + + } + /> +
+
+ ); +} + +// ============================================ +// MAIN APP +// ============================================ + function App() { return ( -
- - - - - - - +
+ + + + + + + +
); } diff --git a/apps/seo-www/src/routes/landing-demo.tsx b/apps/seo-www/src/routes/landing-demo.tsx new file mode 100644 index 000000000..c4a30ba5c --- /dev/null +++ b/apps/seo-www/src/routes/landing-demo.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { LandingSectionsDemo } from "~/routes/-components/founders/landing-sections-demo"; + +export const Route = createFileRoute("/landing-demo")({ + component: LandingDemoPage, +}); + +function LandingDemoPage() { + return ( +
+ +
+ ); +} diff --git a/apps/seo-www/src/routes/landing-mockup.tsx b/apps/seo-www/src/routes/landing-mockup.tsx new file mode 100644 index 000000000..7480be765 --- /dev/null +++ b/apps/seo-www/src/routes/landing-mockup.tsx @@ -0,0 +1,14 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { LandingPageMockup } from "~/routes/-components/founders/landing-page-mockup"; + +export const Route = createFileRoute("/landing-mockup")({ + component: LandingMockupPage, +}); + +function LandingMockupPage() { + return ( +
+ +
+ ); +} diff --git a/apps/seo-www/src/styles.css b/apps/seo-www/src/styles.css index 560acd5ab..cc819efbe 100644 --- a/apps/seo-www/src/styles.css +++ b/apps/seo-www/src/styles.css @@ -8,3 +8,16 @@ --border: oklch(0.78 0 0); --input: oklch(0.78 0 0); } + +.seo-www-hero-display { + font-family: "EB Garamond Variable", ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; +} + +@keyframes grid-flow { + 0%, 100% { opacity: 0.88; } + 50% { opacity: 1; } +} + +.animate-grid-flow { + animation: grid-flow 25s ease-in-out infinite; +} diff --git a/apps/seo-www/vite.config.ts b/apps/seo-www/vite.config.ts index 8d191a5e7..77272c321 100644 --- a/apps/seo-www/vite.config.ts +++ b/apps/seo-www/vite.config.ts @@ -39,6 +39,7 @@ const config = defineConfig({ viteReact(), ], server: { + host: "localhost", port: 4242, }, }); diff --git a/package.json b/package.json index c9745c689..93b46a414 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dev": "docker compose up -d && pnpm turbo watch dev --continue", "dev:seo": "docker compose up -d && pnpm turbo watch dev --continue --filter=seo... --filter=!seo-www", "dev:seo-www": "pnpm turbo watch dev --continue --filter=seo-www", + "dev:localhost": "pnpm --filter seo-www dev", "build": "turbo build", "build:preview": "turbo build:preview", "build:production": "turbo build:production", diff --git a/packages/ui/src/styles.css b/packages/ui/src/styles.css index f3a80d49a..f786e1d41 100644 --- a/packages/ui/src/styles.css +++ b/packages/ui/src/styles.css @@ -184,7 +184,7 @@ code { unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; } -font-face { +@font-face { font-family: 'EB Garamond Variable'; font-style: normal; font-display: swap; From 83e62a9d791a29ab709f6248d6bd259e0de10844 Mon Sep 17 00:00:00 2001 From: Marcellolepoe <67198779+Marcellolepoe@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:17:40 +0800 Subject: [PATCH 2/8] chore(seo-www): remove unused landing routes and components (demo, mockup, seo-experts, old founders) Made-with: Cursor --- apps/seo-www/src/routeTree.gen.ts | 63 - .../-components/founders/chat-mockup.tsx | 132 --- .../-components/founders/founder-cta.tsx | 40 - .../-components/founders/founder-growth.tsx | 70 -- .../-components/founders/founder-hero.tsx | 10 - .../founders/founder-intervention.tsx | 214 ---- .../founders/founder-strategist.tsx | 293 ----- .../founders/founder-transparency.tsx | 446 ------- .../founders/founder-what-it-is.tsx | 153 --- .../founders/hero-search-engine-carousel.tsx | 175 --- .../-components/founders/hero-serp-climb.tsx | 275 ----- .../founders/landing-page-mockup.tsx | 431 ------- .../founders/landing-sections-demo.tsx | 199 ++-- .../-components/founders/serp-climb-v2.tsx | 557 +++++++-- .../founders/serp-zoom-animation.tsx | 255 ---- .../-components/seo-experts/chat-mockup.tsx | 115 -- .../-components/seo-experts/control.tsx | 43 - .../routes/-components/seo-experts/cta.tsx | 40 - .../routes/-components/seo-experts/data.tsx | 54 - .../-components/seo-experts/expertise.tsx | 164 --- .../routes/-components/seo-experts/hero.tsx | 207 ---- .../-components/seo-experts/judgement.tsx | 51 - .../routes/-components/seo-experts/proof.tsx | 50 - .../-components/seo-experts/reporting.tsx | 256 ---- .../-components/seo-experts/strategy.tsx | 312 ----- .../routes/-components/seo-experts/writer.tsx | 227 ---- .../routes/-components/waitlist-dialog.tsx | 7 +- apps/seo-www/src/routes/blog/index.tsx | 81 +- apps/seo-www/src/routes/index.tsx | 1029 +++++++++++++---- apps/seo-www/src/routes/landing-demo.tsx | 14 - apps/seo-www/src/routes/landing-mockup.tsx | 14 - apps/seo-www/src/routes/seo-experts.tsx | 26 - biome.jsonc | 2 +- package.json | 3 +- pnpm-lock.yaml | 75 +- 35 files changed, 1447 insertions(+), 4636 deletions(-) delete mode 100644 apps/seo-www/src/routes/-components/founders/chat-mockup.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/founder-cta.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/founder-growth.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/founder-hero.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/founder-intervention.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/founder-strategist.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/founder-transparency.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/founder-what-it-is.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/hero-search-engine-carousel.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/hero-serp-climb.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/landing-page-mockup.tsx delete mode 100644 apps/seo-www/src/routes/-components/founders/serp-zoom-animation.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/chat-mockup.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/control.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/cta.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/data.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/expertise.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/hero.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/judgement.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/proof.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/reporting.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/strategy.tsx delete mode 100644 apps/seo-www/src/routes/-components/seo-experts/writer.tsx delete mode 100644 apps/seo-www/src/routes/landing-demo.tsx delete mode 100644 apps/seo-www/src/routes/landing-mockup.tsx delete mode 100644 apps/seo-www/src/routes/seo-experts.tsx diff --git a/apps/seo-www/src/routeTree.gen.ts b/apps/seo-www/src/routeTree.gen.ts index fe43ff394..e3f77c3aa 100644 --- a/apps/seo-www/src/routeTree.gen.ts +++ b/apps/seo-www/src/routeTree.gen.ts @@ -10,10 +10,7 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as WhoWeAreRouteImport } from './routes/who-we-are' -import { Route as SeoExpertsRouteImport } from './routes/seo-experts' import { Route as ReferralRouteImport } from './routes/referral' -import { Route as LandingMockupRouteImport } from './routes/landing-mockup' -import { Route as LandingDemoRouteImport } from './routes/landing-demo' import { Route as BlogRouteRouteImport } from './routes/blog/route' import { Route as IndexRouteImport } from './routes/index' import { Route as BlogIndexRouteImport } from './routes/blog/index' @@ -29,26 +26,11 @@ const WhoWeAreRoute = WhoWeAreRouteImport.update({ path: '/who-we-are', getParentRoute: () => rootRouteImport, } as any) -const SeoExpertsRoute = SeoExpertsRouteImport.update({ - id: '/seo-experts', - path: '/seo-experts', - getParentRoute: () => rootRouteImport, -} as any) const ReferralRoute = ReferralRouteImport.update({ id: '/referral', path: '/referral', getParentRoute: () => rootRouteImport, } as any) -const LandingMockupRoute = LandingMockupRouteImport.update({ - id: '/landing-mockup', - path: '/landing-mockup', - getParentRoute: () => rootRouteImport, -} as any) -const LandingDemoRoute = LandingDemoRouteImport.update({ - id: '/landing-demo', - path: '/landing-demo', - getParentRoute: () => rootRouteImport, -} as any) const BlogRouteRoute = BlogRouteRouteImport.update({ id: '/blog', path: '/blog', @@ -99,10 +81,7 @@ const ApiBlogSearchRoute = ApiBlogSearchRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/blog': typeof BlogRouteRouteWithChildren - '/landing-demo': typeof LandingDemoRoute - '/landing-mockup': typeof LandingMockupRoute '/referral': typeof ReferralRoute - '/seo-experts': typeof SeoExpertsRoute '/who-we-are': typeof WhoWeAreRoute '/blog/$': typeof BlogSplatRoute '/blog/rss.xml': typeof BlogRssDotxmlRoute @@ -114,10 +93,7 @@ export interface FileRoutesByFullPath { } export interface FileRoutesByTo { '/': typeof IndexRoute - '/landing-demo': typeof LandingDemoRoute - '/landing-mockup': typeof LandingMockupRoute '/referral': typeof ReferralRoute - '/seo-experts': typeof SeoExpertsRoute '/who-we-are': typeof WhoWeAreRoute '/blog/$': typeof BlogSplatRoute '/blog/rss.xml': typeof BlogRssDotxmlRoute @@ -131,10 +107,7 @@ export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/blog': typeof BlogRouteRouteWithChildren - '/landing-demo': typeof LandingDemoRoute - '/landing-mockup': typeof LandingMockupRoute '/referral': typeof ReferralRoute - '/seo-experts': typeof SeoExpertsRoute '/who-we-are': typeof WhoWeAreRoute '/blog/$': typeof BlogSplatRoute '/blog/rss.xml': typeof BlogRssDotxmlRoute @@ -149,10 +122,7 @@ export interface FileRouteTypes { fullPaths: | '/' | '/blog' - | '/landing-demo' - | '/landing-mockup' | '/referral' - | '/seo-experts' | '/who-we-are' | '/blog/$' | '/blog/rss.xml' @@ -164,10 +134,7 @@ export interface FileRouteTypes { fileRoutesByTo: FileRoutesByTo to: | '/' - | '/landing-demo' - | '/landing-mockup' | '/referral' - | '/seo-experts' | '/who-we-are' | '/blog/$' | '/blog/rss.xml' @@ -180,10 +147,7 @@ export interface FileRouteTypes { | '__root__' | '/' | '/blog' - | '/landing-demo' - | '/landing-mockup' | '/referral' - | '/seo-experts' | '/who-we-are' | '/blog/$' | '/blog/rss.xml' @@ -197,10 +161,7 @@ export interface FileRouteTypes { export interface RootRouteChildren { IndexRoute: typeof IndexRoute BlogRouteRoute: typeof BlogRouteRouteWithChildren - LandingDemoRoute: typeof LandingDemoRoute - LandingMockupRoute: typeof LandingMockupRoute ReferralRoute: typeof ReferralRoute - SeoExpertsRoute: typeof SeoExpertsRoute WhoWeAreRoute: typeof WhoWeAreRoute LegalDataProcessingAgreementRoute: typeof LegalDataProcessingAgreementRoute LegalPrivacyPolicyRoute: typeof LegalPrivacyPolicyRoute @@ -217,13 +178,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof WhoWeAreRouteImport parentRoute: typeof rootRouteImport } - '/seo-experts': { - id: '/seo-experts' - path: '/seo-experts' - fullPath: '/seo-experts' - preLoaderRoute: typeof SeoExpertsRouteImport - parentRoute: typeof rootRouteImport - } '/referral': { id: '/referral' path: '/referral' @@ -231,20 +185,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ReferralRouteImport parentRoute: typeof rootRouteImport } - '/landing-mockup': { - id: '/landing-mockup' - path: '/landing-mockup' - fullPath: '/landing-mockup' - preLoaderRoute: typeof LandingMockupRouteImport - parentRoute: typeof rootRouteImport - } - '/landing-demo': { - id: '/landing-demo' - path: '/landing-demo' - fullPath: '/landing-demo' - preLoaderRoute: typeof LandingDemoRouteImport - parentRoute: typeof rootRouteImport - } '/blog': { id: '/blog' path: '/blog' @@ -330,10 +270,7 @@ const BlogRouteRouteWithChildren = BlogRouteRoute._addFileChildren( const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, BlogRouteRoute: BlogRouteRouteWithChildren, - LandingDemoRoute: LandingDemoRoute, - LandingMockupRoute: LandingMockupRoute, ReferralRoute: ReferralRoute, - SeoExpertsRoute: SeoExpertsRoute, WhoWeAreRoute: WhoWeAreRoute, LegalDataProcessingAgreementRoute: LegalDataProcessingAgreementRoute, LegalPrivacyPolicyRoute: LegalPrivacyPolicyRoute, diff --git a/apps/seo-www/src/routes/-components/founders/chat-mockup.tsx b/apps/seo-www/src/routes/-components/founders/chat-mockup.tsx deleted file mode 100644 index 44bc43100..000000000 --- a/apps/seo-www/src/routes/-components/founders/chat-mockup.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { - Message, - MessageContent, -} from "@rectangular-labs/ui/components/ai-elements/message"; -import { - Tool, - ToolContent, - ToolHeader, - ToolInput, - ToolOutput, -} from "@rectangular-labs/ui/components/ai-elements/tool"; -import { MarkdownContent } from "@rectangular-labs/ui/components/chat/markdown-content"; -import { cn } from "@rectangular-labs/ui/utils/cn"; -import { motion } from "motion/react"; -import { type ReactNode, useId } from "react"; - -export interface ChatMockupProps { - className?: string; - contentClassName?: string; - children: ReactNode; -} - -export function ChatMockup({ - className, - contentClassName, - children, -}: ChatMockupProps) { - return ( -
-
{children}
-
- ); -} - -export function ChatMockupMessage({ - from, - children, - delay = 0, - density = "default", - size = "base", -}: { - from: "user" | "assistant"; - children: ReactNode; - delay?: number; - density?: "default" | "compact"; - size?: "sm" | "base"; -}) { - const id = useId(); - - return ( - - - -
- {typeof children === "string" ? ( - - ) : ( - children - )} -
-
-
-
- ); -} - -export function ChatMockupTool({ - title, - input, - output, - state = "output-available", - delay = 0, -}: { - title: string; - input?: string; - output?: string | ReactNode; - state?: - | "output-available" - | "input-available" - | "input-streaming" - | "output-error"; - delay?: number; -}) { - return ( - - - - - {input && } - {output && ( - - )} - {typeof output !== "string" && output && ( -
{output}
- )} -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/founders/founder-cta.tsx b/apps/seo-www/src/routes/-components/founders/founder-cta.tsx deleted file mode 100644 index 44ad43f47..000000000 --- a/apps/seo-www/src/routes/-components/founders/founder-cta.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { MoveRight } from "@rectangular-labs/ui/components/icon"; -import { Button } from "@rectangular-labs/ui/components/ui/button"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { WaitListDialog } from "../waitlist-dialog"; - -export function FounderCTA() { - return ( -
-
-

- Ready for your co-founder? -

-

- Your End-to-End SEO Co-Founder{" "} - is Ready for You -

- -
- - Join the waitlist - - } - /> -
-
-

- Launching in 2–3 weeks -

-
-
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/founders/founder-growth.tsx b/apps/seo-www/src/routes/-components/founders/founder-growth.tsx deleted file mode 100644 index 4ea93e476..000000000 --- a/apps/seo-www/src/routes/-components/founders/founder-growth.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { Check, Users, Zap } from "@rectangular-labs/ui/components/icon"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; - -export function FounderGrowth() { - const points = [ - { - icon: Users, - title: "Organic Product Integration", - desc: "Plugs your services and products organically within content to drive real leads.", - }, - { - icon: Zap, - title: "Opportunistic", - desc: "Finds adjacent wins and launches new clusters when it spots low-competition demand.", - }, - { - icon: Check, - title: "Commercially Aware", - desc: "Maps intent → offer → CTA so traffic becomes qualified leads.", - }, - ]; - - return ( -
-
-
-

- Commercial ROI -

-

- Built to{" "} - - grow your business - - , -
- not just your website -

-

- Rankings don't matter unless they drive leads, conversions, and - trust. Fluid Posts aligns every action to real commercial intent. -

-
- -
- {points.map((item) => ( -
-
-
- -
-
-

- {item.title} -

-

- {item.desc} -

-
-
-
- ))} -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/founders/founder-hero.tsx b/apps/seo-www/src/routes/-components/founders/founder-hero.tsx deleted file mode 100644 index 8b5b438ce..000000000 --- a/apps/seo-www/src/routes/-components/founders/founder-hero.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { SerpClimbDemo } from "./serp-climb-v2"; - -export const FounderHero = () => { - return ( -
- -
- ); -}; diff --git a/apps/seo-www/src/routes/-components/founders/founder-intervention.tsx b/apps/seo-www/src/routes/-components/founders/founder-intervention.tsx deleted file mode 100644 index 13b082814..000000000 --- a/apps/seo-www/src/routes/-components/founders/founder-intervention.tsx +++ /dev/null @@ -1,214 +0,0 @@ -import { - AlertIcon, - Check, - EyeOn, - RotateCcw, -} from "@rectangular-labs/ui/components/icon"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { cn } from "@rectangular-labs/ui/utils/cn"; -import { AnimatePresence, motion } from "motion/react"; -import { useState } from "react"; - -export function FounderIntervention() { - const [activeId, setActiveId] = useState<"approve" | "review" | "correct">( - "approve", - ); - - const steps = [ - { - id: "approve", - icon: Check, - title: "Approve direction", - desc: "Greenlight a new cluster or pivot with one click.", - color: "emerald", - }, - { - id: "review", - icon: EyeOn, - title: "Review outputs", - desc: "Quickly scan logic + voice before anything ships.", - color: "blue", - }, - { - id: "correct", - icon: AlertIcon, - title: "Correct drift", - desc: "Fix misunderstandings before they become bad output.", - color: "rose", - }, - ] as const; - - return ( -
-
-
-

- Efficiency -

-

- Intervene only{" "} - where it counts -

-

- Founders shouldn't be micromanaging SEO. Fluid Posts handles - auditing, planning, writing, and publishing — pulling you in only at - critical moments. -

-
- -
-
-
- {steps.map((s) => { - const isActive = activeId === s.id; - const styles = - s.color === "emerald" - ? { - ring: "ring-emerald-500/25 border-emerald-500/25 bg-emerald-500/[0.03]", - icon: "bg-emerald-500/10 text-emerald-600", - dot: "bg-emerald-500", - } - : s.color === "blue" - ? { - ring: "ring-blue-500/25 border-blue-500/25 bg-blue-500/[0.03]", - icon: "bg-blue-500/10 text-blue-600", - dot: "bg-blue-500", - } - : { - ring: "ring-rose-500/25 border-rose-500/25 bg-rose-500/[0.03]", - icon: "bg-rose-500/10 text-rose-600", - dot: "bg-rose-500", - }; - - return ( - - ); - })} -
- - {/* Dynamic visual */} -
-
- - - {activeId === "approve" && ( - -
-
- - Approval checkpoint -
-
-

- Approve: Topical Authority strategy -

-

- One parent hub + supporting child pages. Pivot - detected: funnel “Examples” into high-intent asset - pages. -

-
-
-
- Clicking approve starts outlines → publishing. -
-
- - )} - - {activeId === "review" && ( - -
-
- - Quality scan -
-
-

- Draft ready for review -

-

- Scan tone + reasoning. If anything feels off, tweak it - before it ships. -

-
-
-
- Open in editor -
-
- Publish now -
-
-
-
- )} - - {activeId === "correct" && ( - -
-
- - Drift detected -
-
-

Recalibrate intent

-

- Drafts skewing too technical. Confirm a Founder tone - before the next batch. -

-
-
- - Correction prevents compounding wrong output. -
-
-
- )} - -
-
-
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/founders/founder-strategist.tsx b/apps/seo-www/src/routes/-components/founders/founder-strategist.tsx deleted file mode 100644 index 2414b8787..000000000 --- a/apps/seo-www/src/routes/-components/founders/founder-strategist.tsx +++ /dev/null @@ -1,293 +0,0 @@ -import { - Grid, - MousePointer2, - Target, -} from "@rectangular-labs/ui/components/icon"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { cn } from "@rectangular-labs/ui/utils/cn"; -import { AnimatePresence, motion } from "motion/react"; -import { useMemo, useState } from "react"; -import { ChatMockup, ChatMockupMessage } from "./chat-mockup"; - -export function FounderStrategist() { - const [selectedId, setSelectedId] = useState("cta"); - - type ActionColor = "emerald" | "blue" | "rose"; - - const actionColorStyles: Record< - ActionColor, - { expanded: string; icon: string; approveButton: string } - > = { - emerald: { - expanded: - "border-emerald-500 bg-emerald-500/[0.03] ring-1 ring-inset ring-emerald-500/20", - icon: "bg-emerald-500/10 text-emerald-600", - approveButton: "bg-emerald-600 hover:bg-emerald-700", - }, - blue: { - expanded: - "border-blue-500 bg-blue-500/[0.03] ring-1 ring-inset ring-blue-500/20", - icon: "bg-blue-500/10 text-blue-600", - approveButton: "bg-blue-600 hover:bg-blue-700", - }, - rose: { - expanded: - "border-rose-500 bg-rose-500/[0.03] ring-1 ring-inset ring-rose-500/20", - icon: "bg-rose-500/10 text-rose-600", - approveButton: "bg-rose-600 hover:bg-rose-700", - }, - }; - - const actions = [ - { - id: "cta", - icon: MousePointer2, - color: "emerald" satisfies ActionColor, - title: "Fixing CTAs in published articles", - shortTitle: "Fixing CTAs in Published Articles", - summary: "High impressions but low conversion path engagement.", - issue: - "Current articles rank well but use generic 'Contact Us' buttons, resulting in a 0.5% lead conversion rate.", - actionable: - "Implement context-specific CTAs (e.g., 'Download MVP Checklist') mapped to the reader's decision stage.", - impact: - "Projected 3x increase in lead capture without requiring new traffic or higher rankings.", - }, - { - id: "mvp", - icon: Target, - color: "blue" satisfies ActionColor, - title: "Double down on MVP building cluster", - shortTitle: "Double Down on MVP Cluster", - summary: "Topical authority established; high CTR on parent pillar.", - issue: - "The '/resources/ai-mvp/' pillar is over-performing, but lacks depth in technical child pages to keep users on-site.", - actionable: - "Launch 4 new child articles covering 'Cost', 'Tech Stack', and 'Timeline' to own the cluster end-to-end.", - impact: - "Establish absolute topical authority, making it harder for competitors to displace our Page 1 positions.", - }, - { - id: "internal", - icon: Grid, - color: "rose" satisfies ActionColor, - title: "New Cluster: internal tools for SMBs", - shortTitle: "New Cluster", - summary: "Identified gap in low-competition, high-ACV keywords.", - issue: - "Competitors are ignoring small business internal automation queries like 'custom inventory tracker for SMB'.", - actionable: - "Create a new cluster targeting 'Workflow Automation' and 'Internal Dashboards' for service businesses.", - impact: - "Capture high-intent leads who are specifically looking for build partners, leading to higher quality sales calls.", - }, - ] satisfies [ - { - id: string; - icon: typeof Target; - color: ActionColor; - title: string; - shortTitle: string; - summary: string; - issue: string; - actionable: string; - impact: string; - }, - ...Array<{ - id: string; - icon: typeof Target; - color: ActionColor; - title: string; - shortTitle: string; - summary: string; - issue: string; - actionable: string; - impact: string; - }>, - ]; - - const selected = useMemo( - () => actions.find((a) => a.id === selectedId) ?? actions[0], - [actions, selectedId], - ); - - return ( -
-
-
-
-

- The 24/7 Strategist -

-

- Never guess
- - what to do next - -

-

- Fluid Posts analyzes live keyword data, GEO signals, and search - behavior to decide what matters next — so strategy arrives - justified and ready for approval. -

-
-
- -
- - -
-

- - Ready with 3 actionables for aiappbuilder.example - -

- -
- {/* Left list */} -
- {actions.map((act) => { - const isSelected = selectedId === act.id; - const selectionRing = - act.color === "emerald" - ? "ring-emerald-500/25 border-emerald-500/25 bg-emerald-500/[0.03]" - : act.color === "blue" - ? "ring-blue-500/25 border-blue-500/25 bg-blue-500/[0.03]" - : "ring-rose-500/25 border-rose-500/25 bg-rose-500/[0.03]"; - return ( - - ); - })} -
- - {/* Right detail panel */} -
-
- - - -
- - {selected.shortTitle} -
- -
-

- i) Issue / Opportunity -

-

- {selected.issue} -

-
- -
-

- ii) Suggested Actionable -

-

- {selected.actionable} -

-
- -
-

- iii) Impact -

-

- {selected.impact} -

-
- -
- - -
-
-
-
-
-
- - - -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/founders/founder-transparency.tsx b/apps/seo-www/src/routes/-components/founders/founder-transparency.tsx deleted file mode 100644 index d15367965..000000000 --- a/apps/seo-www/src/routes/-components/founders/founder-transparency.tsx +++ /dev/null @@ -1,446 +0,0 @@ -import { - BarChart3, - Check, - ChevronRight, - FileText, - RotateCcw, - Search, - Shield, - TrendingUp, - Zap, -} from "@rectangular-labs/ui/components/icon"; -import { Button } from "@rectangular-labs/ui/components/ui/button"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { cn } from "@rectangular-labs/ui/utils/cn"; -import { AnimatePresence, motion } from "motion/react"; -import { useState } from "react"; -import { ChatMockup, ChatMockupMessage } from "./chat-mockup"; - -export function FounderTransparency() { - const [expanded, setExpanded] = useState(false); - - const thesisValues = [ - { icon: Search, label: "Forms a clear thesis for organic growth" }, - { - icon: BarChart3, - label: "Explains what data informs its thesis and why", - }, - { icon: Zap, label: "Executes it End-to-End" }, - ]; - - const auditValues = [ - { icon: Shield, label: "Self-audits what worked, what didn't, and why" }, - { icon: RotateCcw, label: "Revises direction when assumptions break" }, - { icon: TrendingUp, label: "Shows the logic, not just the outcome" }, - ]; - - return ( -
-
-
-

- Radical Transparency -

-

- Tells it{" "} - like it is -

-

- Tools dump numbers and leave you to make sense of it. SEO services - polish narratives and stop working after KPIs are met. Your - co-founder wouldn't do that, so Fluid Posts doesn't. -

-
- -
-
- {/* Left: Week 1 */} -
-
-

- Strategy Formation -

-
-
    - {thesisValues.map((v) => ( -
  • -
    - -
    - - {v.label} - -
  • - ))} -
- - - -
-
-
- - -
- - )} - -
- -
- - {/* Center: 2 weeks */} -
-
-
- - 2 Weeks - - - of Data - - - Collection - -
-
-
- - {/* Right: Week 3 */} -
-
-

- Self Auditing -

-
-
    - {auditValues.map((v) => ( -
  • -
    - -
    - - {v.label} - -
  • - ))} -
- - - -
-
- - )} - -
- -
-
-
-
- - ); -} diff --git a/apps/seo-www/src/routes/-components/founders/founder-what-it-is.tsx b/apps/seo-www/src/routes/-components/founders/founder-what-it-is.tsx deleted file mode 100644 index 3ae35dc00..000000000 --- a/apps/seo-www/src/routes/-components/founders/founder-what-it-is.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { - Check, - Globe, - PenTool, - Search, - Send, - Sparkles, -} from "@rectangular-labs/ui/components/icon"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { motion } from "motion/react"; - -function SolidArrowDownIcon() { - return ( - - Down - - - ); -} - -function SolidArrowRightIcon() { - return ( - - Right - - - ); -} - -function SolidArrowLeftIcon() { - return ( - - Left - - - ); -} - -export function FounderWhatItIs() { - const Step = ({ - icon: Icon, - title, - }: { - icon: typeof Globe; - title: string; - }) => ( -
-
- -
-

- {title} -

-
- ); - - return ( -
-
-
-

- What we do -

-

- Strategist, writer and publisher — all yours in 3 minutes -

-

- Drop your URL and Fluid Posts analyzes your brand, researches - keyword strategy and writes articles for you, and publishes straight - to your CMS. -

-
- - {/* Visual flow */} -
-
-
-
- 3-minute setup -
-
- - Ready -
-
- -
-
-
-
- -
-
- -
-
- -
- -
-
-
- -
- -
- -
-
- -
-
- -
-
-
-
-
- - -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/founders/hero-search-engine-carousel.tsx b/apps/seo-www/src/routes/-components/founders/hero-search-engine-carousel.tsx deleted file mode 100644 index 5b3a02293..000000000 --- a/apps/seo-www/src/routes/-components/founders/hero-search-engine-carousel.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import { AnimatePresence, motion } from "motion/react"; -import type { ReactNode } from "react"; -import { useEffect, useMemo, useState } from "react"; - -type Engine = { - id: string; - label: string; - node: ReactNode; -}; - -function ClaudeMark() { - return ( - - Claude - - - - ); -} - -function GeminiMark() { - return ( - - Gemini - - - - - - - - - - - ); -} - -function AiOverviewsMark() { - return ( -
- AI -
- ); -} - -function GoogleMark() { - return ( - - Google - - - - - - ); -} - -function ChatGptMark({ onError }: { onError: () => void }) { - return ( - ChatGPT - ); -} - -export function HeroSearchEngineCarousel() { - const [chatgptOk, setChatgptOk] = useState(true); - const engines = useMemo(() => { - const base: Engine[] = [ - { id: "google", label: "Google", node: }, - { - id: "chatgpt", - label: "ChatGPT", - node: chatgptOk ? ( - setChatgptOk(false)} /> - ) : ( -
- GPT -
- ), - }, - { id: "aio", label: "AI Overviews", node: }, - { id: "claude", label: "Claude", node: }, - { id: "gemini", label: "Gemini", node: }, - ]; - return base; - }, [chatgptOk]); - - const [index, setIndex] = useState(0); - - useEffect(() => { - if (engines.length === 0) return; - const id = window.setInterval(() => { - setIndex((i) => (i + 1) % engines.length); - }, 1000); - return () => window.clearInterval(id); - }, [engines.length]); - - const active = engines[index] ?? engines[0]; - if (!active) return null; - - return ( - - - - - {active.label} - {active.node} - - - - - ); -} diff --git a/apps/seo-www/src/routes/-components/founders/hero-serp-climb.tsx b/apps/seo-www/src/routes/-components/founders/hero-serp-climb.tsx deleted file mode 100644 index 486c76acc..000000000 --- a/apps/seo-www/src/routes/-components/founders/hero-serp-climb.tsx +++ /dev/null @@ -1,275 +0,0 @@ -import { motion, useAnimationControls } from "motion/react"; -import { useEffect, useMemo, useState } from "react"; - -type Row = { - id: string; - title: string; - url: string; - snippet: string; - isBrand?: boolean; -}; - -const ROW_H = 86; -const VISIBLE = 4; -const HOLD_START_MS = 180; -const HOLD_TOP_MS = 800; - -const easePremium: [number, number, number, number] = [0.22, 1, 0.36, 1]; - -function clamp(n: number, min: number, max: number) { - return Math.max(min, Math.min(max, n)); -} - -export function HeroSerpClimb() { - const controls = useAnimationControls(); - const [phase, setPhase] = useState<"idle" | "climbing" | "top">("idle"); - - const rows = useMemo( - () => [ - { - id: "a", - title: "Competitor A — SEO services", - url: "competitor-a.com", - snippet: "A short description of a competing offer.", - }, - { - id: "b", - title: "Competitor B — Content & SEO", - url: "competitor-b.com", - snippet: "Another result with a calm, realistic snippet.", - }, - { - id: "brand", - title: "Your brand — AI SEO that compounds", - url: "yourbrand.com", - snippet: "Automates strategy, writing, optimization, and publishing.", - isBrand: true, - }, - { - id: "c", - title: "Competitor C — SEO agency", - url: "competitor-c.com", - snippet: "A third competitor result with muted styling.", - }, - { - id: "d", - title: "Competitor D — SEO tool", - url: "competitor-d.com", - snippet: "Yet another competitor, still muted in the UI.", - }, - { - id: "e", - title: "Competitor E — Growth platform", - url: "competitor-e.com", - snippet: "Generic competitor snippet for realism.", - }, - ], - [], - ); - - const brandIndex = rows.findIndex((r) => r.isBrand); - const startIndex = clamp(brandIndex - 2, 0, rows.length - VISIBLE); - const topIndex = clamp(brandIndex - 0, 0, rows.length - VISIBLE); - - const startY = -(startIndex * ROW_H); - const topY = -(topIndex * ROW_H); - - useEffect(() => { - let cancelled = false; - - async function loop() { - if (cancelled) return; - - setPhase("idle"); - await controls.set({ y: startY, opacity: 1 }); - - await new Promise((r) => setTimeout(r, HOLD_START_MS)); - if (cancelled) return; - - setPhase("climbing"); - - await controls.start({ - y: topY, - transition: { duration: 1.35, ease: easePremium }, - }); - - if (cancelled) return; - setPhase("top"); - - await new Promise((r) => setTimeout(r, HOLD_TOP_MS)); - if (cancelled) return; - - await controls.start({ - opacity: 0, - transition: { duration: 0.16, ease: easePremium }, - }); - await controls.set({ y: startY }); - await controls.start({ - opacity: 1, - transition: { duration: 0.12, ease: easePremium }, - }); - - void loop(); - } - - void loop(); - return () => { - cancelled = true; - }; - }, [controls, startY, topY]); - - return ( -
-
-

- push your brand atop search -

- -
-
-
- {/* top bar */} -
-
-
- 🔎 -
-
- your brand -
-
-
- {phase === "climbing" - ? "Ranking automatically…" - : phase === "top" - ? "Rank secured." - : "Indexing…"} -
-
- - {/* viewport */} -
- {/* cinematic vignette */} -
-
-
-
- - - {rows.map((r, idx) => { - const isBrand = !!r.isBrand; - - return ( -
- {/* rank column */} -
- {idx + 1} -
- - {/* favicon */} -
-
-
- - {/* content */} -
- {/* brand highlight */} - {isBrand && ( - - )} - -
-
- {r.title} -
-
- {r.url} -
-
- {r.snippet} -
- - {isBrand && phase === "top" && ( -
- Rank #1 - - Compounding -
- )} -
-
-
- ); - })} - -
- - {/* subtle footer strip */} -
-
- Search results (simulated) -
-
- Fluid Posts -
-
-
-
-
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/founders/landing-page-mockup.tsx b/apps/seo-www/src/routes/-components/founders/landing-page-mockup.tsx deleted file mode 100644 index 31da77ab3..000000000 --- a/apps/seo-www/src/routes/-components/founders/landing-page-mockup.tsx +++ /dev/null @@ -1,431 +0,0 @@ -import { motion, AnimatePresence } from "motion/react"; -import { useState } from "react"; - -// ============================================ -// SHARED BACKGROUND - Gradient Mesh (recommended) -// ============================================ - -function GradientBackground({ variant = "hero" }: { variant?: "hero" | "light" | "subtle" }) { - const intensity = variant === "hero" ? 1 : variant === "light" ? 0.6 : 0.3; - - return ( -
- - - -
- ); -} - -// ============================================ -// HERO SECTION -// ============================================ - -function HeroSection() { - return ( -
- - -
-

- - Take Your Brand to the - - - Top of Search. - -

- -

- We create strategic content and build authoritative backlinks that push your brand - to #1 on Google, AI Overviews, and ChatGPT. -

- -
- - -
- - {/* Placeholder for carousel graphic */} -
-
-
- [Hero Carousel Graphic] -
-
-
-
-
- ); -} - -// ============================================ -// SOCIAL PROOF - Single Quote -// ============================================ - -function SocialProofSection() { - return ( -
-
-
- "We went from page 5 to ranking #1 for our main keyword in under 90 days. - The ROI paid for itself in the first month." -
-
-
-
-
Sarah Chen
-
Head of Growth, TechStartup
-
-
-
-
- ); -} - -// ============================================ -// HOW IT WORKS -// ============================================ - -function HowItWorksSection() { - const steps = [ - { - num: "01", - title: "Strategic Content", - desc: "We research your market and create high-quality content optimized for both search engines and AI systems.", - }, - { - num: "02", - title: "Authority Links", - desc: "We build backlinks from trusted, relevant sources that signal authority to Google and AI platforms.", - }, - { - num: "03", - title: "Rank & Dominate", - desc: "Watch your brand climb to #1 and stay there. We monitor, adjust, and keep you on top.", - }, - ]; - - return ( -
- - -
-
-

- How We Get You to #1. -

-

- A proven system that combines content excellence with strategic link building. -

-
- -
- {steps.map((step) => ( -
- {step.num} -

{step.title}

-

{step.desc}

-
- ))} -
-
-
- ); -} - -// ============================================ -// RESULTS - Mini Case Study -// ============================================ - -function ResultsSection() { - return ( -
-
-
-
-
- -
-
-

- Real Results. -

-

- Don't take our word for it. Here's what happens when we work together. -

-
- - {/* Mini Case Study */} -
-
-
-
Before
-
Page 5
-
Invisible to customers
-
- -
- -
- -
-
After 90 Days
-
#1
-
Dominating search
-
-
- -
-
-
312%
-
Traffic increase
-
-
-
47
-
Keywords on page 1
-
-
-
8.2x
-
ROI in 6 months
-
-
- -
-

"FluidPosts transformed our entire organic strategy."

-

— Marketing Director, B2B SaaS Company

-
-
-
-
- ); -} - -// ============================================ -// FEATURES / WHAT YOU GET -// ============================================ - -function FeaturesSection() { - const features = [ - { - title: "AI-Optimized Content", - desc: "Content engineered to rank on Google AND get cited by ChatGPT, Claude, and AI Overviews.", - icon: "M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z", - }, - { - title: "Authority Backlinks", - desc: "High-quality links from real, relevant websites. No spam, no shortcuts, just real authority.", - icon: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1", - }, - { - title: "Rank Tracking", - desc: "Real-time monitoring across Google, Bing, and AI platforms. Know exactly where you stand.", - icon: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z", - }, - { - title: "Competitor Analysis", - desc: "We reverse-engineer what's working for your competitors so you can outrank them.", - icon: "M15 12a3 3 0 11-6 0 3 3 0 016 0z M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z", - }, - ]; - - return ( -
- - -
-
-

- Everything You Need. -

-

- A complete system for dominating search—traditional and AI-powered. -

-
- -
- {features.map((feature) => ( -
-
- - - -
-
-

{feature.title}

-

{feature.desc}

-
-
- ))} -
-
-
- ); -} - -// ============================================ -// CTA SECTION -// ============================================ - -function CTASection() { - return ( -
- - -
-

- Ready to Rank #1? -

-

- Join 50+ brands that have transformed their search presence. - Let's discuss how we can get you to the top. -

-
- - -
-
-
- ); -} - -// ============================================ -// FAQ SECTION -// ============================================ - -function FAQSection() { - const faqs = [ - { - q: "How long until I see results?", - a: "Most clients see meaningful ranking improvements within 60-90 days. SEO is a long-term play, but our approach accelerates results significantly.", - }, - { - q: "Do you guarantee #1 rankings?", - a: "No one can guarantee specific rankings—anyone who does is lying. What we guarantee is a proven process, transparent reporting, and relentless optimization.", - }, - { - q: "How is this different from other SEO agencies?", - a: "We focus specifically on the new landscape: Google + AI platforms. Most agencies are still stuck in 2015. We're building for where search is going.", - }, - { - q: "What kind of backlinks do you build?", - a: "Real editorial links from relevant, authoritative sites. No PBNs, no spam, no shortcuts. Quality over quantity, always.", - }, - ]; - - const [openIndex, setOpenIndex] = useState(null); - - return ( -
-
-

- Questions? -

- -
- {faqs.map((faq, i) => ( -
- - - {openIndex === i && ( - -
- {faq.a} -
-
- )} -
-
- ))} -
-
-
- ); -} - -// ============================================ -// FOOTER -// ============================================ - -function Footer() { - return ( -
-
-
-
FluidPosts
-
- - - -
-
© 2024 FluidPosts
-
-
-
- ); -} - -// ============================================ -// FULL PAGE -// ============================================ - -export function LandingPageMockup() { - return ( -
- - - - - - - -
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/founders/landing-sections-demo.tsx b/apps/seo-www/src/routes/-components/founders/landing-sections-demo.tsx index ab72359f6..c968fd521 100644 --- a/apps/seo-www/src/routes/-components/founders/landing-sections-demo.tsx +++ b/apps/seo-www/src/routes/-components/founders/landing-sections-demo.tsx @@ -9,26 +9,28 @@ export function LiquidGradientBackground() { return (
{/* Subtle top gradient - light mode */} -
{/* Dark mode gradient */} -
{/* Single subtle accent - light mode */} -
{/* Dark mode accent */} -
@@ -46,19 +48,29 @@ function GradientBeamsBackground() {
); @@ -69,7 +81,6 @@ function MorphingBlobBackground() { return (
); @@ -92,7 +105,7 @@ function MorphingBlobBackground() { function GradientStripesBackground() { return (
-
@@ -159,8 +173,13 @@ function ParticleFieldBackground() {
{particles.map((p) => (
); @@ -215,9 +239,14 @@ function NoiseGradientBackground() { return (
-
@@ -256,24 +285,24 @@ function GeometricShapesBackground() {
@@ -287,28 +316,35 @@ function AuroraWavesBackground() {
); @@ -320,20 +356,27 @@ function SplitGradientBackground() {
@@ -346,22 +389,29 @@ function PrismLightBackground() {
); @@ -371,9 +421,14 @@ function PrismLightBackground() { // DEMO SECTIONS // ============================================ -function Section({ bg, label, labelColor, description }: { - bg: React.ReactNode; - label: string; +function Section({ + bg, + label, + labelColor, + description, +}: { + bg: React.ReactNode; + label: string; labelColor: string; description: string; }) { @@ -382,7 +437,9 @@ function Section({ bg, label, labelColor, description }: { {bg}
- + {label}
@@ -411,75 +468,75 @@ export function LandingSectionsDemo() {
} + description="Animated diagonal light rays. Dynamic, premium, catches attention without overwhelming." label="Theme 1: Gradient Beams" labelColor="bg-blue-100 text-blue-700" - description="Animated diagonal light rays. Dynamic, premium, catches attention without overwhelming." />
} + description="Single large shape that morphs and rotates. Hypnotic, modern, very unique." label="Theme 2: Morphing Blob" labelColor="bg-violet-100 text-violet-700" - description="Single large shape that morphs and rotates. Hypnotic, modern, very unique." />
} + description="Angled color bands. Bold, structured, editorial feel. Very intentional." label="Theme 3: Gradient Stripes" labelColor="bg-indigo-100 text-indigo-700" - description="Angled color bands. Bold, structured, editorial feel. Very intentional." />
} + description="Dramatic top-down light cone. Draws focus to content, theatrical." label="Theme 4: Spotlight" labelColor="bg-sky-100 text-sky-700" - description="Dramatic top-down light cone. Draws focus to content, theatrical." />
} + description="Floating dots with depth. Tech-forward, alive, sophisticated." label="Theme 5: Particle Field" labelColor="bg-cyan-100 text-cyan-700" - description="Floating dots with depth. Tech-forward, alive, sophisticated." />
} + description="Stacked frosted glass panels. Depth, dimension, very modern UI feel." label="Theme 6: Glass Layers" labelColor="bg-emerald-100 text-emerald-700" - description="Stacked frosted glass panels. Depth, dimension, very modern UI feel." />
} + description="Textured gradient with grain. Editorial, tactile, premium print feel." label="Theme 7: Noise Gradient" labelColor="bg-teal-100 text-teal-700" - description="Textured gradient with grain. Editorial, tactile, premium print feel." />
} + description="Smoothly transitioning colors. Hypnotic, fluid, very polished." label="Theme 8: Liquid Gradient" labelColor="bg-purple-100 text-purple-700" - description="Smoothly transitioning colors. Hypnotic, fluid, very polished." />
} + description="Floating abstract forms. Playful but professional, distinctive." label="Theme 9: Geometric Shapes" labelColor="bg-pink-100 text-pink-700" - description="Floating abstract forms. Playful but professional, distinctive." />
} + description="Flowing aurora borealis from top. Dramatic, ethereal, striking." label="Theme 10: Aurora Waves" labelColor="bg-amber-100 text-amber-700" - description="Flowing aurora borealis from top. Dramatic, ethereal, striking." />
} + description="Bold diagonal color division. Architectural, confident, modern." label="Theme 11: Split Gradient" labelColor="bg-orange-100 text-orange-700" - description="Bold diagonal color division. Architectural, confident, modern." />
} + description="Refracted light beams with rainbow hints. Innovative, eye-catching, tech-forward." label="Theme 12: Prism Light" labelColor="bg-rose-100 text-rose-700" - description="Refracted light beams with rainbow hints. Innovative, eye-catching, tech-forward." />
); diff --git a/apps/seo-www/src/routes/-components/founders/serp-climb-v2.tsx b/apps/seo-www/src/routes/-components/founders/serp-climb-v2.tsx index bbc391305..24a3cdde8 100644 --- a/apps/seo-www/src/routes/-components/founders/serp-climb-v2.tsx +++ b/apps/seo-www/src/routes/-components/founders/serp-climb-v2.tsx @@ -1,5 +1,5 @@ -import { motion, useAnimationControls, AnimatePresence } from "motion/react"; -import { useEffect, useState, useCallback } from "react"; +import { AnimatePresence, motion, useAnimationControls } from "motion/react"; +import { useCallback, useEffect, useState } from "react"; import { WaitListDialog } from "../waitlist-dialog"; const ROW_H = 96; @@ -22,13 +22,28 @@ const GRAPHIC_HEIGHT = 520; function GoogleLogo() { return ( - - - - + + + + - - + + ); } @@ -36,8 +51,19 @@ function GoogleLogo() { function SearchBar({ query }: { query: string }) { return (
- - + + {query}
@@ -45,56 +71,111 @@ function SearchBar({ query }: { query: string }) { } function SerpResultRow({ - name, url, snippet, isBrand, isBlurred, isAtTop, isClicked, + name, + url, + snippet, + isBrand, + isBlurred, + isAtTop, + isClicked, }: { - name: string; url: string; snippet: string; isBrand?: boolean; isBlurred: boolean; isAtTop?: boolean; isClicked?: boolean; + name: string; + url: string; + snippet: string; + isBrand?: boolean; + isBlurred: boolean; + isAtTop?: boolean; + isClicked?: boolean; }) { return ( {isBrand && ( )} -
{url}
+
+ {url} +
- {name} + + {name} + -
{snippet}
+
+ {snippet} +
); } -function MouseCursor({ isVisible, isClicking }: { isVisible: boolean; isClicking: boolean }) { +function MouseCursor({ + isVisible, + isClicking, +}: { + isVisible: boolean; + isClicking: boolean; +}) { return ( - - + + ); @@ -103,18 +184,65 @@ function MouseCursor({ isVisible, isClicking }: { isVisible: boolean; isClicking function GoogleSerpGraphic({ onComplete }: { onComplete: () => void }) { const competitorControls = useAnimationControls(); const brandControls = useAnimationControls(); - const [phase, setPhase] = useState<"idle" | "climbing" | "top" | "cursor" | "click">("idle"); + const [phase, setPhase] = useState< + "idle" | "climbing" | "top" | "cursor" | "click" + >("idle"); const competitors = [ - { id: "c1", name: "Competitor 1 — Industry Solutions", url: "competitor1.com", snippet: "Professional services for your business..." }, - { id: "c2", name: "Competitor 2 — Industry Solutions", url: "competitor2.com", snippet: "Professional services for your business..." }, - { id: "c3", name: "Competitor 3 — Industry Solutions", url: "competitor3.com", snippet: "Professional services for your business..." }, - { id: "c4", name: "Competitor 4 — Industry Solutions", url: "competitor4.com", snippet: "Professional services for your business..." }, - { id: "c5", name: "Competitor 5 — Industry Solutions", url: "competitor5.com", snippet: "Professional services for your business..." }, - { id: "c6", name: "Competitor 6 — Industry Solutions", url: "competitor6.com", snippet: "Professional services for your business..." }, - { id: "c7", name: "Competitor 7 — Industry Solutions", url: "competitor7.com", snippet: "Professional services for your business..." }, - { id: "c8", name: "Competitor 8 — Industry Solutions", url: "competitor8.com", snippet: "Professional services for your business..." }, - { id: "c9", name: "Competitor 9 — Industry Solutions", url: "competitor9.com", snippet: "Professional services for your business..." }, + { + id: "c1", + name: "Competitor 1 — Industry Solutions", + url: "competitor1.com", + snippet: "Professional services for your business...", + }, + { + id: "c2", + name: "Competitor 2 — Industry Solutions", + url: "competitor2.com", + snippet: "Professional services for your business...", + }, + { + id: "c3", + name: "Competitor 3 — Industry Solutions", + url: "competitor3.com", + snippet: "Professional services for your business...", + }, + { + id: "c4", + name: "Competitor 4 — Industry Solutions", + url: "competitor4.com", + snippet: "Professional services for your business...", + }, + { + id: "c5", + name: "Competitor 5 — Industry Solutions", + url: "competitor5.com", + snippet: "Professional services for your business...", + }, + { + id: "c6", + name: "Competitor 6 — Industry Solutions", + url: "competitor6.com", + snippet: "Professional services for your business...", + }, + { + id: "c7", + name: "Competitor 7 — Industry Solutions", + url: "competitor7.com", + snippet: "Professional services for your business...", + }, + { + id: "c8", + name: "Competitor 8 — Industry Solutions", + url: "competitor8.com", + snippet: "Professional services for your business...", + }, + { + id: "c9", + name: "Competitor 9 — Industry Solutions", + url: "competitor9.com", + snippet: "Professional services for your business...", + }, ]; const competitorStartY = -ROW_H * (competitors.length - 2); @@ -135,8 +263,14 @@ function GoogleSerpGraphic({ onComplete }: { onComplete: () => void }) { setPhase("climbing"); await Promise.all([ - brandControls.start({ y: brandEndY, transition: { duration: CLIMB_DURATION, ease: EASE } }), - competitorControls.start({ y: competitorEndY, transition: { duration: CLIMB_DURATION, ease: EASE } }), + brandControls.start({ + y: brandEndY, + transition: { duration: CLIMB_DURATION, ease: EASE }, + }), + competitorControls.start({ + y: competitorEndY, + transition: { duration: CLIMB_DURATION, ease: EASE }, + }), ]); if (cancelled) return; setPhase("top"); @@ -154,8 +288,16 @@ function GoogleSerpGraphic({ onComplete }: { onComplete: () => void }) { onComplete(); }; void run(); - return () => { cancelled = true; }; - }, [competitorControls, brandControls, competitorStartY, brandStartY, onComplete]); + return () => { + cancelled = true; + }; + }, [ + competitorControls, + brandControls, + competitorStartY, + brandStartY, + onComplete, + ]); const isClimbing = phase === "climbing"; const isAtTop = phase === "top" || phase === "cursor" || phase === "click"; @@ -163,28 +305,63 @@ function GoogleSerpGraphic({ onComplete }: { onComplete: () => void }) { const isClicked = phase === "click"; return ( -
+
-
+
+ +
- All + + All + Images Videos News
-
- +
+ {competitors.map((c) => ( - + ))} - - + + - +
@@ -197,10 +374,26 @@ function GoogleSerpGraphic({ onComplete }: { onComplete: () => void }) { function GeminiSparkle() { return ( - - + + - + @@ -210,7 +403,9 @@ function GeminiSparkle() { } function AIOverviewGraphic({ onComplete }: { onComplete: () => void }) { - const [phase, setPhase] = useState<"idle" | "thinking" | "typing" | "highlight" | "done">("idle"); + const [phase, setPhase] = useState< + "idle" | "thinking" | "typing" | "highlight" | "done" + >("idle"); useEffect(() => { let cancelled = false; @@ -234,22 +429,35 @@ function AIOverviewGraphic({ onComplete }: { onComplete: () => void }) { onComplete(); }; void run(); - return () => { cancelled = true; }; + return () => { + cancelled = true; + }; }, [onComplete]); const isThinking = phase === "thinking"; - const showText = phase === "typing" || phase === "highlight" || phase === "done"; + const showText = + phase === "typing" || phase === "highlight" || phase === "done"; const highlightBrand = phase === "highlight" || phase === "done"; return ( -
+
{/* Header */}
- AI Overview + + AI Overview +
- +
@@ -261,11 +469,11 @@ function AIOverviewGraphic({ onComplete }: { onComplete: () => void }) { {isThinking && ( void }) { > - Thinking... + + Thinking... + )} @@ -282,23 +492,26 @@ function AIOverviewGraphic({ onComplete }: { onComplete: () => void }) { {showText && (

The best product for your needs is{" "} Your Brand - . + + .

@@ -308,23 +521,36 @@ function AIOverviewGraphic({ onComplete }: { onComplete: () => void }) { transition={{ duration: 0.3 }} > Your Brand - - {" "}is the top-rated solution in its category. + {" "} + is the top-rated solution in its category.

{/* Source citation inline */} {highlightBrand && ( - - + + - yourbrand.com + + yourbrand.com + )} @@ -343,14 +569,26 @@ function AIOverviewGraphic({ onComplete }: { onComplete: () => void }) { function ChatGPTLogo() { return ( - - + + ); } function ChatGPTGraphic({ onComplete }: { onComplete: () => void }) { - const [phase, setPhase] = useState<"idle" | "typing" | "show" | "sources" | "done">("idle"); + const [phase, setPhase] = useState< + "idle" | "typing" | "show" | "sources" | "done" + >("idle"); useEffect(() => { let cancelled = false; @@ -374,19 +612,27 @@ function ChatGPTGraphic({ onComplete }: { onComplete: () => void }) { onComplete(); }; void run(); - return () => { cancelled = true; }; + return () => { + cancelled = true; + }; }, [onComplete]); - const showResponse = phase === "show" || phase === "sources" || phase === "done"; + const showResponse = + phase === "show" || phase === "sources" || phase === "done"; const showSources = phase === "sources" || phase === "done"; return ( -
+
{/* Header with logo */}
- ChatGPT + + ChatGPT +
{/* Chat area */} @@ -394,7 +640,9 @@ function ChatGPTGraphic({ onComplete }: { onComplete: () => void }) { {/* User message - pill style on right */}
-

best product for my needs

+

+ best product for my needs +

@@ -404,50 +652,92 @@ function ChatGPTGraphic({ onComplete }: { onComplete: () => void }) {
- - - + + +
)} {showResponse && ( - +

The best product for your needs is{" "} Your Brand - . + + .

{showSources && (

- It's consistently rated #1 for quality, customer satisfaction, and value. + It's consistently rated #1 for quality, customer + satisfaction, and value.

{/* Source citation */}
- - + + - yourbrand.com - - + + yourbrand.com + + +
@@ -462,12 +752,36 @@ function ChatGPTGraphic({ onComplete }: { onComplete: () => void }) { {/* Input bar */}
- - + + - Message ChatGPT - - + + Message ChatGPT + + +
@@ -488,7 +802,7 @@ const GRAPHICS = [ export function SerpClimbDemo() { const [currentGraphic, setCurrentGraphic] = useState(0); - + const handleComplete = useCallback(() => { setTimeout(() => { setCurrentGraphic((prev) => (prev + 1) % GRAPHICS.length); @@ -502,8 +816,14 @@ export function SerpClimbDemo() {
{/* Subtle green glow - lighter in light mode, stronger in dark mode */}
-
-
+
+

@@ -511,20 +831,23 @@ export function SerpClimbDemo() { Take Your Brand to the - Top of Search. + Top of Search + .

- + {/* Subheading and CTA */}

- Fluid Posts is the end-to-end SEO/GEO tool that automates organic rankings. + Fluid Posts is the end-to-end SEO/GEO tool that automates organic + rankings + .

Join the Waitlist @@ -532,17 +855,22 @@ export function SerpClimbDemo() { />
-
+
- {CurrentComponent ? : null} + {CurrentComponent ? ( + + ) : null}
@@ -552,14 +880,17 @@ export function SerpClimbDemo() {
{GRAPHICS.map((g) => ( diff --git a/apps/seo-www/src/routes/-components/founders/serp-zoom-animation.tsx b/apps/seo-www/src/routes/-components/founders/serp-zoom-animation.tsx deleted file mode 100644 index 638457ac0..000000000 --- a/apps/seo-www/src/routes/-components/founders/serp-zoom-animation.tsx +++ /dev/null @@ -1,255 +0,0 @@ -import { motion, useAnimationControls } from "motion/react"; -import { useEffect, useMemo, useState } from "react"; - -const CARD_H = 68; -const GAP = 12; -const STEP = CARD_H + GAP; -const VIEWPORT_H = 232; - -type Ghost = { - id: string; - urlW: "w-16" | "w-20" | "w-24"; - titleW: "w-36" | "w-40" | "w-44" | "w-48"; - dim?: boolean; -}; - -function SkeletonLine({ w }: { w: string }) { - return
; -} - -function GhostResult({ ghost }: { ghost: Ghost }) { - return ( -
-
-
-
-
-
- - -
-
-
- ); -} - -function BrandResult() { - return ( -
-
-
-
-
-
-
-
-
-
-
-
- - Your Brand - -
-
-
-
- ); -} - -function rotateDownBy(arr: T[], n: number): T[] { - if (arr.length === 0) return arr; - const k = ((n % arr.length) + arr.length) % arr.length; - if (k === 0) return arr; - return [...arr.slice(-k), ...arr.slice(0, -k)]; -} - -function makeGhosts(seed: number): Ghost[] { - const urlWidths: Ghost["urlW"][] = ["w-16", "w-20", "w-24"]; - const titleWidths: Ghost["titleW"][] = ["w-36", "w-40", "w-44", "w-48"]; - - return Array.from({ length: 12 }, (_, i) => ({ - id: `g-${seed}-${i}`, - urlW: urlWidths[(seed + i) % urlWidths.length] ?? "w-20", - titleW: titleWidths[(seed * 3 + i) % titleWidths.length] ?? "w-40", - dim: i % 5 === 0, - })); -} - -export function SerpZoomAnimation() { - const bgControls = useAnimationControls(); - const brandControls = useAnimationControls(); - const cutControls = useAnimationControls(); - const vignetteControls = useAnimationControls(); - - const [ghosts, setGhosts] = useState(() => makeGhosts(0)); - const [boosting, setBoosting] = useState(false); - - const brandStartY = useMemo(() => VIEWPORT_H - CARD_H - 16, []); - const brandEndY = useMemo(() => 12, []); - - useEffect(() => { - let cancelled = false; - const CLIMB_STEPS = 3; - const CLIMB_BG_Y = CLIMB_STEPS * STEP; - - const run = async () => { - let seed = 1; - - bgControls.set({ y: 0, opacity: 0.95, filter: "blur(0px)" }); - brandControls.set({ y: brandStartY, scale: 0.98 }); - cutControls.set({ opacity: 0 }); - vignetteControls.set({ opacity: 0.16 }); - - while (!cancelled) { - // Act I: start low - setBoosting(false); - await Promise.all([ - bgControls.start({ y: 0, transition: { duration: 0.35 } }), - brandControls.start({ - y: brandStartY, - scale: 0.985, - transition: { duration: 0.35, ease: "easeOut" }, - }), - vignetteControls.start({ - opacity: 0.14, - transition: { duration: 0.35, ease: "easeOut" }, - }), - ]); - - // Act II: cinematic climb - setBoosting(true); - await Promise.all([ - brandControls.start({ - y: brandEndY, - scale: 1.01, - transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] }, - }), - bgControls.start({ - y: CLIMB_BG_Y, - opacity: 0.9, - filter: "blur(1.5px)", - transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] }, - }), - vignetteControls.start({ - opacity: 0.28, - transition: { duration: 0.28, ease: "easeOut" }, - }), - ]); - - // Act III: settle at top - setBoosting(false); - await Promise.all([ - brandControls.start({ - scale: 1, - transition: { duration: 0.18, ease: "easeOut" }, - }), - bgControls.start({ - filter: "blur(0px)", - opacity: 0.92, - transition: { duration: 0.22, ease: "easeOut" }, - }), - ]); - - // Hold - await brandControls.start({ - y: brandEndY, - transition: { duration: 1.0, ease: "linear" }, - }); - - // Film cut to hide reset - await cutControls.start({ - opacity: 1, - transition: { duration: 0.12, ease: "easeIn" }, - }); - - setGhosts((prev) => rotateDownBy(prev, CLIMB_STEPS)); - setGhosts(makeGhosts(seed)); - seed += 1; - bgControls.set({ y: 0, opacity: 0.95, filter: "blur(0px)" }); - brandControls.set({ y: brandStartY, scale: 0.98 }); - vignetteControls.set({ opacity: 0.14 }); - - await cutControls.start({ - opacity: 0, - transition: { duration: 0.18, ease: "easeOut" }, - }); - } - }; - - void run(); - return () => { - cancelled = true; - }; - }, [ - bgControls, - brandControls, - brandEndY, - brandStartY, - cutControls, - vignetteControls, - ]); - - const brandShadow = boosting - ? "0 22px 50px rgba(99, 102, 241, 0.12)" - : "0 12px 28px rgba(0,0,0,0.10)"; - - return ( -
- {/* Cinematic vignette */} - - - {/* Cut overlay for seamless looping */} - - -
-
-
- -
- {/* Background SERP stack (moves down) */} - - {ghosts.map((g) => ( -
- -
- ))} -
- - {/* Brand (moves from bottom to top) */} - - - -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/chat-mockup.tsx b/apps/seo-www/src/routes/-components/seo-experts/chat-mockup.tsx deleted file mode 100644 index bfba68a8d..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/chat-mockup.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { - Message, - MessageContent, -} from "@rectangular-labs/ui/components/ai-elements/message"; -import { - Tool, - ToolContent, - ToolHeader, - ToolInput, - ToolOutput, -} from "@rectangular-labs/ui/components/ai-elements/tool"; -import { MarkdownContent } from "@rectangular-labs/ui/components/chat/markdown-content"; -import { cn } from "@rectangular-labs/ui/utils/cn"; -import { motion } from "motion/react"; -import { type ReactNode, useId } from "react"; - -export interface ChatMockupProps { - className?: string; - children: ReactNode; -} - -export function ChatMockup({ className, children }: ChatMockupProps) { - return ( -
-
{children}
-
- ); -} - -export function ChatMockupMessage({ - from, - children, - delay = 0, -}: { - from: "user" | "assistant"; - children: ReactNode; - delay?: number; -}) { - const id = useId(); - - return ( - - - -
- {typeof children === "string" ? ( - - ) : ( - children - )} -
-
-
-
- ); -} - -export function ChatMockupTool({ - title, - input, - output, - state = "output-available", - delay = 0, -}: { - title: string; - input?: string; - output?: string | ReactNode; - state?: - | "output-available" - | "input-available" - | "input-streaming" - | "output-error"; - delay?: number; -}) { - return ( - - - - - {input && } - {output && ( - - )} - {typeof output !== "string" && output && ( -
{output}
- )} -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/control.tsx b/apps/seo-www/src/routes/-components/seo-experts/control.tsx deleted file mode 100644 index 6e98e6f1b..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/control.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Section } from "@rectangular-labs/ui/components/ui/section"; - -const checkpoints = ["Approve outline?", "Adjust tone?", "Publish now?"]; - -export function Control() { - return ( -
-
-
-

- You stay in control -

-

- Built to execute exactly what you intend. -

-

- Approve direction, adjust tone, and publish without losing momentum. - You decide what matters - we handle the heavy lifting. -

-
-
-

- Live checkpoints -

-
    - {checkpoints.map((item) => ( -
  • - {item} - ready -
  • - ))} -
-

- Instant iteration -

-
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/cta.tsx b/apps/seo-www/src/routes/-components/seo-experts/cta.tsx deleted file mode 100644 index b29f39a0d..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/cta.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { MoveRight } from "@rectangular-labs/ui/components/icon"; -import { Button } from "@rectangular-labs/ui/components/ui/button"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { WaitListDialog } from "../waitlist-dialog"; - -export function CTA() { - return ( -
-
-

- Put your expertise to work —
- without the ceiling. -

-

- Limitless SEO starts here. -

- -
- - Join the waitlist - - } - /> -
-
-

- Launching in End-Jan 2026 -

-
-
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/data.tsx b/apps/seo-www/src/routes/-components/seo-experts/data.tsx deleted file mode 100644 index ca710ea9f..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/data.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Section } from "@rectangular-labs/ui/components/ui/section"; - -const cards = [ - { - title: "GSC-aware Chat", - body: "Connects directly to Google Search Console so every plan is grounded in real demand.", - }, - { - title: "Article Writer", - body: "Understands your voice, drafts pillar pieces, and tags each paragraph with the briefs you approve.", - }, - { - title: "Direct Publisher", - body: "Publishes to your CMS, tracks rankings, and reports performance alongside the same chat that planned it.", - }, -]; - -export function Data() { - return ( -
-
-
-

- From data to pages -

-

- End-to-end. -

-

- Fluid Posts connects directly to Google Search Console and keyword - data, understands your site’s voice, and writes articles aligned to - real search demand. -

-

- Planning, writing, and publishing live in one place. -

-
-
- {cards.map((card) => ( -
-

- {card.title} -

-

{card.body}

-
- ))} -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/expertise.tsx b/apps/seo-www/src/routes/-components/seo-experts/expertise.tsx deleted file mode 100644 index 55baf475a..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/expertise.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { - ArrowRight, - BarChart3, - Check, - Clock, - FileText, - Target, - Zap, -} from "@rectangular-labs/ui/components/icon"; -import { Button } from "@rectangular-labs/ui/components/ui/button"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { cn } from "@rectangular-labs/ui/utils/cn"; -import { AnimatePresence, motion } from "motion/react"; -import { useState } from "react"; -import { ChatMockup, ChatMockupTool } from "./chat-mockup"; - -export function Expertise() { - const [showDetail, setShowDetail] = useState(true); - - return ( -
-
-
-

- Never start strategy
- from zero again -

-

- Fluid Posts analyzes keyword data, studies your industry, and - surfaces data-backed strategic directions before you even ask. -

-
- -
- - - -
-

- Your strategy for aiappbuilder.example is - ready for approval: -

- - -
-
- - )} - - - - {!showDetail && ( -

- Click the strategy to see keywords, stats, and expectations. -

- )} -
- - - -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/hero.tsx b/apps/seo-www/src/routes/-components/seo-experts/hero.tsx deleted file mode 100644 index 3e6775d39..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/hero.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import { MoveRight, Search } from "@rectangular-labs/ui/components/icon"; -import { buttonVariants } from "@rectangular-labs/ui/components/ui/button"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { useState } from "react"; -import { WaitListDialog } from "../waitlist-dialog"; - -export const Hero = () => { - const [dnOk, setDnOk] = useState(true); - const [chatgptOk, setChatgptOk] = useState(true); - - const GoogleMark = () => ( - - Google - - - - - - ); - - const ChatGptMark = () => ( -
- {chatgptOk ? ( - ChatGPT setChatgptOk(false)} - src="/logos/chatgpt.png" - /> - ) : ( - - ChatGPT - - - )} -
- ); - - return ( -
-
-
-
-
-

- Move from SEO employee to
- - decision-maker. - -

-

- Fluid Posts handles execution across audits, planning, writing, - and reporting — leaving you to make the decisions that matter. -

-
-
- - Join the waitlist - - } - /> -

- Launching End-Jan 2026 -

-
- -
-

- Early results -

-

- In early pilots, we helped 2 clients reach{" "} - - #1 on Google - {" "} - and appear on{" "} - ChatGPT{" "} - for targeted terms within a month. -

- -
-
-

- Pilot highlight -

- -
- {/* Google SERP mock */} -
-
- - Google -
-
- - gambling chargebacks -
-
-

- #1 result -

-

- Gambling Chargebacks: How to Dispute Online Casino... -

-
- {dnOk ? ( - Dispute Ninja setDnOk(false)} - src="/logos/dispute-ninjas.png" - /> - ) : ( -
- DN -
- )} - - Dispute Ninjas - -
-
-
- - {/* ChatGPT mock */} -
-
- - - - ChatGPT -
- -
- - best chargeback softwares -
- -
-

- #5 Result -

-

- Top Chargeback Management & Prevention Software -

-
- {dnOk ? ( - Dispute Ninja setDnOk(false)} - src="/logos/dispute-ninjas.png" - /> - ) : ( -
- DN -
- )} - - Dispute Ninjas - -
-
-
-
-
-
-
-
-
-
-
- ); -}; diff --git a/apps/seo-www/src/routes/-components/seo-experts/judgement.tsx b/apps/seo-www/src/routes/-components/seo-experts/judgement.tsx deleted file mode 100644 index 50fc86f37..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/judgement.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { motion } from "motion/react"; -import { ChatMockup, ChatMockupMessage, ChatMockupTool } from "./chat-mockup"; - -export function Judgement() { - return ( -
-
-
-

- Limitless output,
- - anchored by your judgement - -

-

- Fluid Posts is designed around the reality that automation works - best when guided by an expert. You’re always in the loop - approving - and defining the strategy, structure the thinking, and approving - outlines and reviewing the final output. -

-
- -
- - - I have 5 article outlines ready for your review. - - - - {/* Decorative breakthrough elements */} - -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/proof.tsx b/apps/seo-www/src/routes/-components/seo-experts/proof.tsx deleted file mode 100644 index dc47f2d39..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/proof.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { MoveRight } from "@rectangular-labs/ui/components/icon"; -import { buttonVariants } from "@rectangular-labs/ui/components/ui/button"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { ONBOARD_LINK } from "../constants"; - -export function Proof() { - return ( -
-
-
-

- Proven, even early -

-

- One of our first clients reached first-page rankings in two - competitive categories within two weeks of using Fluid Posts. -

-

- Not by chasing keywords, but by executing a clear strategy, fast. -

-
-
-
-

- Dispute Ninja -

-

- SERP snapshot -

-

- #1 • Data disputes{" "} - / 2 weeks -

-
- - Sign up today - -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/reporting.tsx b/apps/seo-www/src/routes/-components/seo-experts/reporting.tsx deleted file mode 100644 index 16178313d..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/reporting.tsx +++ /dev/null @@ -1,256 +0,0 @@ -import { - ArrowRight, - FileText, - TrendingUp, - Zap, -} from "@rectangular-labs/ui/components/icon"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { motion } from "motion/react"; -import { useState } from "react"; -import { ChatMockup } from "./chat-mockup"; - -export function Reporting() { - const [isFullReportOpen, setIsFullReportOpen] = useState(false); - - const recentArticles = [ - { - title: "Build an MVP With AI (Step-by-Step)", - keyword: "AI MVP", - clicks: 1420, - impressions: "34.9k", - ctr: "4.1%", - }, - { - title: "AI App Builder vs hiring a Developer", - keyword: "Cost vs ROI", - clicks: 1030, - impressions: "28.1k", - ctr: "3.7%", - }, - { - title: "SaaS Prototype Checklist", - keyword: "SaaS Prototype", - clicks: 760, - impressions: "19.6k", - ctr: "3.9%", - }, - { - title: "What Is an AI App Builder?", - keyword: "Definition", - clicks: 510, - impressions: "26.7k", - ctr: "1.9%", - }, - { - title: "Custom Software for Small Business", - keyword: "Guide", - clicks: 890, - impressions: "36.4k", - ctr: "2.4%", - }, - ]; - - return ( -
-
- {/* Heading */} -
-

- Turn SEO reporting into your
- - unfair advantage. - -

-

- Fluid Posts briefs you at a glance — analysing performance with real - signals and objective diagnosis. -

-
- - {/* Report */} -
- -
-
-
- -
-
-

- Monthly Performance Report -

-

aiappbuilder.example

-
-
-
-

- Period -

-

Jan 2026

-
-
- -
-
-

- Clicks -

-

4,820

-

+41%

-
-
-

- Impr -

-

168k

-

+58%

-
-
-

- Avg Pos -

-

11.6

-

+2.6

-
-
- - {isFullReportOpen && ( -
-
-

- Executive Summary -

-

- This month, we successfully published the articles agreed - upon, all within the "AI Execution" cluster. We - are seeing strong initial traction on high-intent comparison - queries. -

-
- -
-
-

- Article Performance -

-
- - - - - - - - - - {recentArticles.map((art) => ( - - - - - - ))} - -
Article - Clicks - - CTR -
- - {art.title} - - - {art.clicks} - - {art.ctr} -
-
- -
-
-
-
-
-
-
-
- -
-
-
- Performance Thesis -
-

- Comparison and decision-based content is ranking faster - and converting at 2x the rate of generic definitions. - Google is rewarding our highly-structured, actionable - frameworks over surface-level guides. -

-
- -
-
- Actionables -
-
-
-

- Double Down -

-

- Expand the "Education" cluster with 3 new - companion articles targeting follow-up intent. -

-
-
-

- Quick Fix -

-

- Rewrite meta titles for template articles posts to - be outcome-led, targeting a 5% CTR lift. -

-
-
-
-
-
- -
-

- More in the report -

-
-
-
-
-
-
-
- )} - -
- -
- - -
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/strategy.tsx b/apps/seo-www/src/routes/-components/seo-experts/strategy.tsx deleted file mode 100644 index 8bc2eae78..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/strategy.tsx +++ /dev/null @@ -1,312 +0,0 @@ -import { - BarChart3, - Grid, - MousePointer2, - Target, - TrendingUp, -} from "@rectangular-labs/ui/components/icon"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { cn } from "@rectangular-labs/ui/utils/cn"; -import { AnimatePresence, motion } from "motion/react"; -import { useMemo, useState } from "react"; -import { ChatMockup, ChatMockupMessage } from "./chat-mockup"; - -export function Strategy() { - const [selectedId, setSelectedId] = useState("cta"); - - type ActionColor = "emerald" | "blue" | "rose"; - - const actionColorStyles: Record< - ActionColor, - { expanded: string; icon: string; approveButton: string } - > = { - emerald: { - expanded: - "border-emerald-500 bg-emerald-500/[0.03] ring-1 ring-inset ring-emerald-500/20", - icon: "bg-emerald-500/10 text-emerald-600", - approveButton: "bg-emerald-600 hover:bg-emerald-700", - }, - blue: { - expanded: - "border-blue-500 bg-blue-500/[0.03] ring-1 ring-inset ring-blue-500/20", - icon: "bg-blue-500/10 text-blue-600", - approveButton: "bg-blue-600 hover:bg-blue-700", - }, - rose: { - expanded: - "border-rose-500 bg-rose-500/[0.03] ring-1 ring-inset ring-rose-500/20", - icon: "bg-rose-500/10 text-rose-600", - approveButton: "bg-rose-600 hover:bg-rose-700", - }, - }; - - const actions = [ - { - id: "cta", - icon: MousePointer2, - color: "emerald", - title: "Fixing CTAs in published articles", - shortTitle: "Fixing CTAs in Published Articles", - summary: "High impressions but low conversion path engagement.", - issue: - "Current articles rank well but use generic 'Contact Us' buttons, resulting in a 0.5% lead conversion rate.", - actionable: - "Implement context-specific CTAs (e.g., 'Download MVP Checklist') mapped to the reader's decision stage.", - impact: - "Projected 3x increase in lead capture without requiring new traffic or higher rankings.", - }, - { - id: "mvp", - icon: Target, - color: "blue", - title: "Double down on MVP building cluster", - shortTitle: "Double Down on MVP Cluster", - summary: "Topical authority established; high CTR on parent pillar.", - issue: - "The '/resources/ai-mvp/' pillar is over-performing, but lacks depth in technical child pages to keep users on-site.", - actionable: - "Launch 4 new child articles covering 'Cost', 'Tech Stack', and 'Timeline' to own the cluster end-to-end.", - impact: - "Establish absolute topical authority, making it harder for competitors to displace our Page 1 positions.", - }, - { - id: "internal", - icon: Grid, - color: "rose", - title: "New Cluster: internal tools for SMBs", - shortTitle: "New Cluster", - summary: "Identified gap in low-competition, high-ACV keywords.", - issue: - "Competitors are ignoring small business internal automation queries like 'custom inventory tracker for SMB'.", - actionable: - "Create a new cluster targeting 'Workflow Automation' and 'Internal Dashboards' for service businesses.", - impact: - "Capture high-intent leads who are specifically looking for build partners, leading to higher quality sales calls.", - }, - ] satisfies [ - { - id: string; - icon: typeof Target; - color: ActionColor; - title: string; - shortTitle: string; - summary: string; - issue: string; - actionable: string; - impact: string; - }, - ...Array<{ - id: string; - icon: typeof Target; - color: ActionColor; - title: string; - shortTitle: string; - summary: string; - issue: string; - actionable: string; - impact: string; - }>, - ]; - - const selected = useMemo( - () => actions.find((a) => a.id === selectedId) ?? actions[0], - [actions, selectedId], - ); - - return ( -
-
-
-

- Always Ready with
- the Next Win -

-

- Fluid Posts is always working ahead of you — surfacing gaps to fill, - winners to double down on, and underperformers to fix. -

-
- -
-
-
-
- -
-
-

Detailed Reasoning

-

- Logic, stats, and competitor comparisons behind every move. -

-
-
-
-
- -
-
-

Statistical Confidence

-

- Every win comes with an evidence-backed confidence signal. -

-
-
-
- -
- - -
-

- - Ready with 3 actionables for aiappbuilder.example - -

- -
- {/* Left list */} -
- {actions.map((act) => { - const isSelected = selectedId === act.id; - const selectionRing = - act.color === "emerald" - ? "ring-emerald-500/25 border-emerald-500/25 bg-emerald-500/[0.03]" - : act.color === "blue" - ? "ring-blue-500/25 border-blue-500/25 bg-blue-500/[0.03]" - : "ring-rose-500/25 border-rose-500/25 bg-rose-500/[0.03]"; - return ( - - ); - })} -
- - {/* Right detail panel */} -
-
- - - -
- - {selected.shortTitle} -
- -
-

- i) Issue / Opportunity -

-

- {selected.issue} -

-
-
-

- ii) Suggested Actionable -

-

- {selected.actionable} -

-
-
-

- iii) Impact -

-

- {selected.impact} -

-
- -
- - -
-
-
-
-
-
- - - -
-
-
-
- ); -} diff --git a/apps/seo-www/src/routes/-components/seo-experts/writer.tsx b/apps/seo-www/src/routes/-components/seo-experts/writer.tsx deleted file mode 100644 index b1edf37d6..000000000 --- a/apps/seo-www/src/routes/-components/seo-experts/writer.tsx +++ /dev/null @@ -1,227 +0,0 @@ -import { - ArrowRight, - Check, - ExternalLink, - FileText, - Search, - Sparkles, - Target, -} from "@rectangular-labs/ui/components/icon"; -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { cn } from "@rectangular-labs/ui/utils/cn"; -import { AnimatePresence, motion } from "motion/react"; -import { useState } from "react"; -import { ChatMockup, ChatMockupMessage } from "./chat-mockup"; - -export function Writer() { - const [showPreview, setShowPreview] = useState(false); - - return ( -
-
-
-

- Your Writing Team,
- - at Your Fingertips. - -

-

- Approve, and it goes to work. Fluid Posts writes in your brand’s - voice, grounded in fulfilling real search intent. -

-
- -
-
- - -
-

- The first draft is ready. I've focused on visibility across - traditional search and AI-driven discovery (GEO). -

- - -
-
-
- - )} - - -
- - - -
- -
- {[ - { - icon: Search, - lead: "Search Intent Uncovered", - rest: " through analysis of top-ranking SERPs and AI overviews", - }, - { - icon: Target, - lead: "Focused, Clearly Structured Writing", - rest: " that prioritises usefulness and readability", - }, - { - icon: Check, - lead: "SEO and GEO Applied", - rest: " intentionally and effectively", - }, - { - icon: Sparkles, - lead: "Visibility Across Search", - rest: " and AI-driven discovery", - }, - ].map((item, index) => ( - -
- -
- - {item.lead} - {item.rest} - -
- ))} -
-
-
- - ); -} diff --git a/apps/seo-www/src/routes/-components/waitlist-dialog.tsx b/apps/seo-www/src/routes/-components/waitlist-dialog.tsx index 93737ca96..9619ff8d3 100644 --- a/apps/seo-www/src/routes/-components/waitlist-dialog.tsx +++ b/apps/seo-www/src/routes/-components/waitlist-dialog.tsx @@ -179,7 +179,12 @@ export function WaitListDialog({ trigger, className }: Props) { ) : null}
- @@ -94,25 +96,25 @@ function Page() {
setSearchQuery(e.target.value)} placeholder="Search articles..." + type="text" value={searchQuery} - onChange={(e) => setSearchQuery(e.target.value)} - className="w-full rounded-xl border border-neutral-200 bg-white py-3 pr-4 pl-12 text-neutral-900 placeholder:text-neutral-400 focus:border-emerald-500 focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-neutral-700 dark:bg-neutral-900 dark:text-white dark:focus:border-emerald-400 dark:placeholder:text-neutral-500" />
@@ -121,14 +123,14 @@ function Page() {
{CATEGORIES.map((cat) => ( @@ -138,17 +140,19 @@ function Page() { {/* Posts grid */} {filteredPosts.length === 0 ? (
-

No articles found.

+

+ No articles found. +

) : (
{filteredPosts.map((post, index) => ( {/* Cover image */} {post.cover ? ( @@ -174,8 +178,8 @@ function Page() {
{post.tags.slice(0, 3).map((tag) => ( {tag} @@ -187,22 +191,22 @@ function Page() {
{post.authorDetail?.image ? ( {post.authorDetail.name ) : (
@@ -215,11 +219,14 @@ function Page() { <> · - {new Date(post.createdAt).toLocaleDateString("en-US", { - month: "short", - day: "numeric", - year: "numeric", - })} + {new Date(post.createdAt).toLocaleDateString( + "en-US", + { + month: "short", + day: "numeric", + year: "numeric", + }, + )} )} diff --git a/apps/seo-www/src/routes/index.tsx b/apps/seo-www/src/routes/index.tsx index 598ce7fe5..e0bfa0123 100644 --- a/apps/seo-www/src/routes/index.tsx +++ b/apps/seo-www/src/routes/index.tsx @@ -1,9 +1,8 @@ import { createFileRoute } from "@tanstack/react-router"; -import { motion, AnimatePresence } from "motion/react"; -import { useState, useMemo, useEffect, useCallback } from "react"; -import { Logo } from "@rectangular-labs/ui/components/icon"; -import { SerpClimbDemo } from "~/routes/-components/founders/serp-climb-v2"; +import { AnimatePresence, motion } from "motion/react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { LiquidGradientBackground } from "~/routes/-components/founders/landing-sections-demo"; +import { SerpClimbDemo } from "~/routes/-components/founders/serp-climb-v2"; import { WaitListDialog } from "~/routes/-components/waitlist-dialog"; export const Route = createFileRoute("/")({ @@ -40,7 +39,8 @@ function SocialProofSection() {
- "Our website ranked #1 for relevant keywords within a month of using Fluid Posts." + "Our website ranked #1 for relevant keywords within a month of + using Fluid Posts."

Bowen Xue · Founder, Dispute Ninja @@ -54,9 +54,19 @@ function SocialProofSection() { // ANIMATED NETWORK GRAPH // ============================================ +const NETWORK_FLOAT_AMP = 1.5; + function NetworkGraph() { + const [phase, setPhase] = useState(0); + const nodes = useMemo(() => { - const generated: Array<{ id: number; x: number; y: number; size: number; opacity: number }> = []; + const generated: Array<{ + id: number; + x: number; + y: number; + size: number; + opacity: number; + }> = []; for (let i = 0; i < 80; i++) { generated.push({ id: i, @@ -76,49 +86,72 @@ function NetworkGraph() { for (let j = 0; j < numConnections; j++) { const target = Math.floor(Math.random() * nodes.length); if (target !== i) { - lines.push({ from: i, to: target, opacity: Math.random() * 0.3 + 0.1 }); + lines.push({ + from: i, + to: target, + opacity: Math.random() * 0.3 + 0.1, + }); } } } return lines; }, [nodes]); + useEffect(() => { + let raf = 0; + const tick = () => { + setPhase((p) => (p + 0.048) % (Math.PI * 2)); + raf = requestAnimationFrame(tick); + }; + raf = requestAnimationFrame(tick); + return () => cancelAnimationFrame(raf); + }, []); + + const offset = (nodeId: number) => ({ + x: NETWORK_FLOAT_AMP * Math.sin(phase + nodeId * 0.4), + y: NETWORK_FLOAT_AMP * Math.cos(phase + nodeId * 0.4), + }); + return (

-
); @@ -133,20 +166,38 @@ function JourneySection() {
{/* Grid pattern with subtle fade - animated */}
-

- Complete SEO, automated. + Complete SEO & GEO, automated + .

From strategy to publishing—we handle it all. @@ -160,28 +211,58 @@ function JourneySection() {

- 01 + + 01 + Content Strategy

- Based on your onboarding, we research your business, target users, and tailor strategies to reach your audience. + Based on your onboarding, we research your business, target + users, and tailor strategies to reach your audience.

  • - Custom strategy based on your business goals
  • - SEO-optimized articles written for you
  • - Automated publishing to your CMS
  • @@ -194,27 +275,59 @@ function JourneySection() {
    Suggestion
    -

    Electric Toothbrush Buyer's Guide Cluster

    -

    Goal: 12,000 impressions per month

    +

    + Electric Toothbrush Buyer's Guide Cluster +

    +

    + Goal:{" "} + + 12,000 impressions per month + +

-

Motivation

+

+ Motivation +

- High-intent buyers searching "best electric toothbrush" are ready to purchase. Capturing these queries drives qualified leads directly to your product pages. + High-intent buyers searching "best electric + toothbrush" are ready to purchase. Capturing these + queries drives qualified leads directly to your product + pages.

-

Description

+

+ Description +

- Create comparison guides targeting "how to choose a toothbrush", "electric vs manual toothbrush", and "best toothbrush for sensitive teeth". + Create comparison guides targeting "how to choose a + toothbrush", "electric vs manual + toothbrush", and "best toothbrush for sensitive + teeth".

- - - + + +
@@ -229,11 +342,14 @@ function JourneySection() {

- 02 + + 02 + Authority Network

- We pass trusted backlinks across our network, strengthening domain authority and compounding visibility. + We pass trusted backlinks across our network, strengthening + domain authority and compounding visibility.

@@ -252,13 +368,30 @@ function ResultsSection() {
{/* Circle grid pattern */}
-
@@ -271,49 +404,91 @@ function ResultsSection() {
{/* Dispute Ninja Card */} -
+
-

DisputeNinja

-

B2B SaaS

+

+ DisputeNinja +

+

+ B2B SaaS +

- 0 → 1,000 - monthly visitors + + 0 → 1,000 + + + monthly visitors +
- #1 on Google for target keywords + + #1 on Google for target keywords +
- Cited on ChatGPT + + Cited on ChatGPT +
-

Results achieved within 1 month

+

+ Results achieved within 1 month +

{/* QuantumByte Card */}
-

QuantumByte

+

+ QuantumByte +

B2C SaaS

- +486% + + +486% + clicks
- +906% - impressions + + +906% + + + impressions +
-

Results achieved within 1 month

+

+ Results achieved within 1 month +

@@ -327,40 +502,95 @@ function ResultsSection() { function PerformanceIcon({ className }: { className?: string }) { return ( -
-

- The Whole Suite. And More. + The Whole Suite + .{" "} + And More + .

- Fluid Posts is the only point of contact you need for SEO. Monitor performance, create articles, - ask questions, and watch it audit itself biweekly. + Fluid Posts is the only point of contact you need for SEO. Monitor + performance, create articles, ask questions, and watch it audit + itself biweekly.

@@ -461,35 +719,35 @@ function FeaturesSection() { {/* Tab switcher */}
@@ -497,27 +755,33 @@ function FeaturesSection() { {/* Platform mockup - with dark mode support */}
-
+
- FluidPosts + + FluidPosts +
{activeTab === "performance" && (
-

BrightSmile Dental Co

-

Monitor clicks, impressions, and top queries

+

+ BrightSmile Dental Co +

+

+ Monitor clicks, impressions, and top queries +

Last 28 days @@ -525,19 +789,38 @@ function FeaturesSection() {
-

Total Clicks

-

4,821

-

+892%

+

+ Total Clicks +

+

+ 4,821 +

+

+ +892% +

-

Total Impressions

-

1.2M

-

+1,247%

+

+ Total Impressions +

+

+ 1.2M +

+

+ +1,247% +

-

Clicks & Impressions over time

-

+ Clicks & Impressions over time +

+
-

Active Strategies

-

Strategies currently executing

+

+ Active Strategies +

+

+ Strategies currently executing +

Active
-
Electric Toothbrush Buyer's Guide
-

Goal: 12,000 impressions per month

+
+ Electric Toothbrush Buyer's Guide +
+

+ Goal: 12,000 impressions per month +

Suggestion
-
Dental Care Tips for Sensitive Teeth
-

Goal: 8,000 impressions per month

+
+ Dental Care Tips for Sensitive Teeth +
+

+ Goal: 8,000 impressions per month +

@@ -594,38 +895,71 @@ function FeaturesSection() { {activeTab === "chat" && (
-

Chat

-

Ask anything about your SEO performance

+

+ Chat +

+

+ Ask anything about your SEO performance +

{/* User message */}
- How has performance been this last week compared to the previous week, and why? + How has performance been this last week compared to + the previous week, and why?
{/* AI response */}
-

Great question! This week showed a 23% increase in impressions compared to last week.

-

The main driver was your article "Best Electric Toothbrush 2025" which gained traction on Google's featured snippets...

-

.....

+

+ Great question! This week showed a{" "} + + 23% increase + {" "} + in impressions compared to last week. +

+

+ The main driver was your article "Best Electric + Toothbrush 2025" which gained traction on + Google's featured snippets... +

+

+ ..... +

{/* Input bar */}
- -
@@ -637,19 +971,31 @@ function FeaturesSection() { {/* Feature list - grouped with icons */}
{featureGroups.map((group) => ( -
+
-

{group.title}

+

+ {group.title} +

{group.desc && ( -

{group.desc}

+

+ {group.desc} +

)} {group.items && (
    {group.items.map((item) => ( -
  • • {item}
  • +
  • + • {item} +
  • ))}
)} @@ -663,18 +1009,6 @@ function FeaturesSection() { ); } -// ============================================ -// FLUID POSTS LOGO COMPONENT -// ============================================ - -function FluidPostsLogo({ className, centered }: { className?: string; centered?: boolean }) { - return ( -
- - Fluid Posts -
- ); -} // ============================================ // PRICING - COMPARISON SECTION @@ -685,13 +1019,30 @@ function PricingSection() {
{/* Dot pattern - same as Real Results */}
-
@@ -700,66 +1051,133 @@ function PricingSection() { Pricing.

- We believe SEO should be accessible to businesses of all sizes. That's why we're priced competitively—a fraction of traditional agencies, with better results. + We believe SEO should be accessible to businesses of all sizes. + That's why we're priced competitively—a fraction of + traditional agencies, with better results.

- {/* Traditional Agency */} + {/* SEO Agency */}
- {/* Header section - price aligned with other cards */} -
-
-

Traditional SEO Agency

-
+ {/* 1) Name on top - same plane across cards */} +
+

+ SEO Agency +

+
+ {/* 2) Price - same plane across cards */} +
- $3,000-$10,000 - /mo + + $3K to $10K + + + / mo +
{/* Features section */}
-

What you get:

+

+ What you get: +

  • - 3-4 Articles / month + 3-4 SEO articles / month
  • - 6-12 month lock-in period
  • - Monthly Reporting
- -

What you don't get:

+ +

+ What you don't get: +

  • - Real-time traffic updates
  • - Search strategy
  • - Transparent Self-auditing
  • @@ -767,63 +1185,130 @@ function PricingSection() {
- {/* Fluid Posts - HIGHLIGHTED */} + {/* Fluid Posts Starter */}
- BEST FOR SMALL BUSINESSES + STARTER
- {/* Header section - price aligned with other cards */} -
-
- -
+ {/* 1) Name on top - same plane across cards */} +
+

+ Fluid Posts Starter +

+
+ {/* 2) Price - same plane across cards */} +
- $99 - /mo + + $99 + + + /mo +
- $199/mo - 50% OFF + + $199/mo + + + 50% OFF +
{/* Features section */}
-

What you get:

+

+ What you get: +

  • - 5 GEO/SEO-optimized articles/month
  • - 1 quality backlink/month + Access to backlink exchange
  • - Clear strategies upon onboarding
  • - Self-auditing platform
  • - Automated CMS publishing
  • - Control over published content
  • @@ -833,8 +1318,8 @@ function PricingSection() { Join the waitlist @@ -842,54 +1327,107 @@ function PricingSection() { />
- {/* Enterprise - HIGHLIGHTED */} -
-
- BEST FOR ENTERPRISES + {/* Business */} +
+
+ BUSINESS
- {/* Header section - price aligned with other cards */} -
-
- - Fluid Posts Enterprise -
+ {/* 1) Name on top - same plane across cards */} +
+

+ Fluid Posts Business +

+
+ {/* 2) Price - same plane across cards */} +
- Custom + + Custom +
-

Accelerated results for serious growth

+

+ Accelerated results for serious growth +

{/* Features section */}
-

What you get:

+

+ What you get: +

  • - 30+ SEO-optimized articles/month + Everything in Starter
  • - 3+ quality backlinks/month + 30+ GEO/SEO-optimized articles/month
  • - Direct contact with founders
  • - Personalized onboarding
  • - Quicker results
  • @@ -899,8 +1437,8 @@ function PricingSection() { Join the waitlist @@ -922,17 +1460,20 @@ function CTASection() {

    - Let's Get Ranking. + Let's Get Ranking + .

    - Unlock the value of SEO for your business today, and watch visibility compound while you sit and watch. + Unlock the value of SEO for your business today, and watch visibility + compound while you sit and watch + .

    Join the waitlist diff --git a/apps/seo-www/src/routes/landing-demo.tsx b/apps/seo-www/src/routes/landing-demo.tsx deleted file mode 100644 index c4a30ba5c..000000000 --- a/apps/seo-www/src/routes/landing-demo.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; -import { LandingSectionsDemo } from "~/routes/-components/founders/landing-sections-demo"; - -export const Route = createFileRoute("/landing-demo")({ - component: LandingDemoPage, -}); - -function LandingDemoPage() { - return ( -
    - -
    - ); -} diff --git a/apps/seo-www/src/routes/landing-mockup.tsx b/apps/seo-www/src/routes/landing-mockup.tsx deleted file mode 100644 index 7480be765..000000000 --- a/apps/seo-www/src/routes/landing-mockup.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; -import { LandingPageMockup } from "~/routes/-components/founders/landing-page-mockup"; - -export const Route = createFileRoute("/landing-mockup")({ - component: LandingMockupPage, -}); - -function LandingMockupPage() { - return ( -
    - -
    - ); -} diff --git a/apps/seo-www/src/routes/seo-experts.tsx b/apps/seo-www/src/routes/seo-experts.tsx deleted file mode 100644 index 51e12bb21..000000000 --- a/apps/seo-www/src/routes/seo-experts.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; -import { CTA } from "~/routes/-components/seo-experts/cta"; -import { Expertise } from "~/routes/-components/seo-experts/expertise"; -import { Hero } from "~/routes/-components/seo-experts/hero"; -import { Judgement } from "~/routes/-components/seo-experts/judgement"; -import { Reporting } from "~/routes/-components/seo-experts/reporting"; -import { Strategy } from "~/routes/-components/seo-experts/strategy"; -import { Writer } from "~/routes/-components/seo-experts/writer"; - -export const Route = createFileRoute("/seo-experts")({ - component: SEOExpertsPage, -}); - -function SEOExpertsPage() { - return ( -
    - - - - - - - -
    - ); -} diff --git a/biome.jsonc b/biome.jsonc index da6ebbbf6..c59f5fcc2 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.4.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.4.4/schema.json", "assist": { "actions": { "source": { "organizeImports": "on", "useSortedAttributes": "on" } diff --git a/package.json b/package.json index 93b46a414..a0d240839 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "dev": "docker compose up -d && pnpm turbo watch dev --continue", "dev:seo": "docker compose up -d && pnpm turbo watch dev --continue --filter=seo... --filter=!seo-www", "dev:seo-www": "pnpm turbo watch dev --continue --filter=seo-www", - "dev:localhost": "pnpm --filter seo-www dev", "build": "turbo build", "build:preview": "turbo build:preview", "build:production": "turbo build:production", @@ -43,7 +42,7 @@ "sso": "aws sso login --sso-session=rectangular-labs" }, "devDependencies": { - "@biomejs/biome": "2.4.0", + "@biomejs/biome": "2.4.4", "@changesets/cli": "^2.29.7", "@dotenvx/dotenvx": "^1.51.1", "@rectangular-labs/typescript": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7b7fc6eb8..5bc970bf3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: .: devDependencies: '@biomejs/biome': - specifier: 2.4.0 - version: 2.4.0 + specifier: 2.4.4 + version: 2.4.4 '@changesets/cli': specifier: ^2.29.7 version: 2.29.7(@types/node@24.10.13) @@ -2115,55 +2115,55 @@ packages: '@better-fetch/fetch@1.1.21': resolution: {integrity: sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==} - '@biomejs/biome@2.4.0': - resolution: {integrity: sha512-iluT61cORUDIC5i/y42ljyQraCemmmcgbMLLCnYO+yh+2hjTmcMFcwY8G0zTzWCsPb3t3AyKc+0t/VuhPZULUg==} + '@biomejs/biome@2.4.4': + resolution: {integrity: sha512-tigwWS5KfJf0cABVd52NVaXyAVv4qpUXOWJ1rxFL8xF1RVoeS2q/LK+FHgYoKMclJCuRoCWAPy1IXaN9/mS61Q==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.4.0': - resolution: {integrity: sha512-L+YpOtPSuU0etomfvFTPWRsa7+8ejaJL3yaROEoT/96HDJbR6OsvZQk0C8JUYou+XFdP+JcGxqZknkp4n934RA==} + '@biomejs/cli-darwin-arm64@2.4.4': + resolution: {integrity: sha512-jZ+Xc6qvD6tTH5jM6eKX44dcbyNqJHssfl2nnwT6vma6B1sj7ZLTGIk6N5QwVBs5xGN52r3trk5fgd3sQ9We9A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.4.0': - resolution: {integrity: sha512-Aq+S7ffpb5ynTyLgtnEjG+W6xuTd2F7FdC7J6ShpvRhZwJhjzwITGF9vrqoOnw0sv1XWkt2Q1Rpg+hleg/Xg7Q==} + '@biomejs/cli-darwin-x64@2.4.4': + resolution: {integrity: sha512-Dh1a/+W+SUCXhEdL7TiX3ArPTFCQKJTI1mGncZNWfO+6suk+gYA4lNyJcBB+pwvF49uw0pEbUS49BgYOY4hzUg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.4.0': - resolution: {integrity: sha512-1rhDUq8sf7xX3tg7vbnU3WVfanKCKi40OXc4VleBMzRStmQHdeBY46aFP6VdwEomcVjyNiu+Zcr3LZtAdrZrjQ==} + '@biomejs/cli-linux-arm64-musl@2.4.4': + resolution: {integrity: sha512-+sPAXq3bxmFwhVFJnSwkSF5Rw2ZAJMH3MF6C9IveAEOdSpgajPhoQhbbAK12SehN9j2QrHpk4J/cHsa/HqWaYQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.4.0': - resolution: {integrity: sha512-u2p54IhvNAWB+h7+rxCZe3reNfQYFK+ppDw+q0yegrGclFYnDPZAntv/PqgUacpC3uxTeuWFgWW7RFe3lHuxOA==} + '@biomejs/cli-linux-arm64@2.4.4': + resolution: {integrity: sha512-V/NFfbWhsUU6w+m5WYbBenlEAz8eYnSqRMDMAW3K+3v0tYVkNyZn8VU0XPxk/lOqNXLSCCrV7FmV/u3SjCBShg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.4.0': - resolution: {integrity: sha512-Omo0xhl63z47X+CrE5viEWKJhejJyndl577VoXg763U/aoATrK3r5+8DPh02GokWPeODX1Hek00OtjjooGan9w==} + '@biomejs/cli-linux-x64-musl@2.4.4': + resolution: {integrity: sha512-gGvFTGpOIQDb5CQ2VC0n9Z2UEqlP46c4aNgHmAMytYieTGEcfqhfCFnhs6xjt0S3igE6q5GLuIXtdQt3Izok+g==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.4.0': - resolution: {integrity: sha512-WVFOhsnzhrbMGOSIcB9yFdRV2oG2KkRRhIZiunI9gJqSU3ax9ErdnTxRfJUxZUI9NbzVxC60OCXNcu+mXfF/Tw==} + '@biomejs/cli-linux-x64@2.4.4': + resolution: {integrity: sha512-R4+ZCDtG9kHArasyBO+UBD6jr/FcFCTH8QkNTOCu0pRJzCWyWC4EtZa2AmUZB5h3e0jD7bRV2KvrENcf8rndBg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.4.0': - resolution: {integrity: sha512-aqRwW0LJLV1v1NzyLvLWQhdLmDSAV1vUh+OBdYJaa8f28XBn5BZavo+WTfqgEzALZxlNfBmu6NGO6Al3MbCULw==} + '@biomejs/cli-win32-arm64@2.4.4': + resolution: {integrity: sha512-trzCqM7x+Gn832zZHgr28JoYagQNX4CZkUZhMUac2YxvvyDRLJDrb5m9IA7CaZLlX6lTQmADVfLEKP1et1Ma4Q==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.4.0': - resolution: {integrity: sha512-g47s+V+OqsGxbSZN3lpav6WYOk0PIc3aCBAq+p6dwSynL3K5MA6Cg6nkzDOlu28GEHwbakW+BllzHCJCxnfK5Q==} + '@biomejs/cli-win32-x64@2.4.4': + resolution: {integrity: sha512-gnOHKVPFAAPrpoPt2t+Q6FZ7RPry/FDV3GcpU53P3PtLNnQjBmKyN2Vh/JtqXet+H4pme8CC76rScwdjDcT1/A==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -12452,6 +12452,7 @@ packages: prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. hasBin: true prelude-ls@1.2.1: @@ -16225,39 +16226,39 @@ snapshots: '@better-fetch/fetch@1.1.21': {} - '@biomejs/biome@2.4.0': + '@biomejs/biome@2.4.4': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.0 - '@biomejs/cli-darwin-x64': 2.4.0 - '@biomejs/cli-linux-arm64': 2.4.0 - '@biomejs/cli-linux-arm64-musl': 2.4.0 - '@biomejs/cli-linux-x64': 2.4.0 - '@biomejs/cli-linux-x64-musl': 2.4.0 - '@biomejs/cli-win32-arm64': 2.4.0 - '@biomejs/cli-win32-x64': 2.4.0 + '@biomejs/cli-darwin-arm64': 2.4.4 + '@biomejs/cli-darwin-x64': 2.4.4 + '@biomejs/cli-linux-arm64': 2.4.4 + '@biomejs/cli-linux-arm64-musl': 2.4.4 + '@biomejs/cli-linux-x64': 2.4.4 + '@biomejs/cli-linux-x64-musl': 2.4.4 + '@biomejs/cli-win32-arm64': 2.4.4 + '@biomejs/cli-win32-x64': 2.4.4 - '@biomejs/cli-darwin-arm64@2.4.0': + '@biomejs/cli-darwin-arm64@2.4.4': optional: true - '@biomejs/cli-darwin-x64@2.4.0': + '@biomejs/cli-darwin-x64@2.4.4': optional: true - '@biomejs/cli-linux-arm64-musl@2.4.0': + '@biomejs/cli-linux-arm64-musl@2.4.4': optional: true - '@biomejs/cli-linux-arm64@2.4.0': + '@biomejs/cli-linux-arm64@2.4.4': optional: true - '@biomejs/cli-linux-x64-musl@2.4.0': + '@biomejs/cli-linux-x64-musl@2.4.4': optional: true - '@biomejs/cli-linux-x64@2.4.0': + '@biomejs/cli-linux-x64@2.4.4': optional: true - '@biomejs/cli-win32-arm64@2.4.0': + '@biomejs/cli-win32-arm64@2.4.4': optional: true - '@biomejs/cli-win32-x64@2.4.0': + '@biomejs/cli-win32-x64@2.4.4': optional: true '@borewit/text-codec@0.1.1': {} From 8dc716ed9ed3b0937d25c1c5093cf684b54be542 Mon Sep 17 00:00:00 2001 From: Marcellolepoe <67198779+Marcellolepoe@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:23:27 +0800 Subject: [PATCH 3/8] style(seo-www): apply biome format to index.tsx Made-with: Cursor --- apps/seo-www/src/routes/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/seo-www/src/routes/index.tsx b/apps/seo-www/src/routes/index.tsx index e0bfa0123..1b4629408 100644 --- a/apps/seo-www/src/routes/index.tsx +++ b/apps/seo-www/src/routes/index.tsx @@ -1009,7 +1009,6 @@ function FeaturesSection() { ); } - // ============================================ // PRICING - COMPARISON SECTION // ============================================ From 84fb88f74f24ec1a53be261cb8fac25546a8a290 Mon Sep 17 00:00:00 2001 From: Marcellolepoe <67198779+Marcellolepoe@users.noreply.github.com> Date: Sun, 1 Mar 2026 02:15:25 +0800 Subject: [PATCH 4/8] feat(seo-www): add AI Overviews blog post, update nav and about page Made-with: Cursor --- .../one-year-ai-overviews-google-search.mdx | 177 ++++++++++++ apps/seo-www/src/routeTree.gen.ts | 21 -- .../seo-www/src/routes/-components/footer.tsx | 4 +- .../seo-www/src/routes/-components/header.tsx | 2 +- apps/seo-www/src/routes/index.tsx | 5 +- apps/seo-www/src/routes/referral.tsx | 127 --------- apps/seo-www/src/routes/who-we-are.tsx | 263 ++++++++++++++---- apps/seo-www/vite.config.ts | 5 +- packages/content/src/components/blog-post.tsx | 29 +- 9 files changed, 425 insertions(+), 208 deletions(-) create mode 100644 apps/seo-www/content/one-year-ai-overviews-google-search.mdx delete mode 100644 apps/seo-www/src/routes/referral.tsx diff --git a/apps/seo-www/content/one-year-ai-overviews-google-search.mdx b/apps/seo-www/content/one-year-ai-overviews-google-search.mdx new file mode 100644 index 000000000..506652f3e --- /dev/null +++ b/apps/seo-www/content/one-year-ai-overviews-google-search.mdx @@ -0,0 +1,177 @@ +--- +title: "One Year of AI Overviews: How Google's Response to ChatGPT Has Reshaped Search" +description: "A data-driven look at what has changed in search—SERP real estate, CTR, zero-click behaviour—and what has stayed the same: authority, citations, and foundational SEO." +icon: "BarChart3" +cover: "https://images.unsplash.com/photo-1573804633927-bfcbcd909acd?q=80&w=1600&auto=format&fit=crop" +author: "winston" +tags: + - "SEO Insights" + - "AI Overviews" + - "Google" + - "search" + - "strategy" +--- + +## Introduction + +The year is 2026 and I'm finally confident enough to make an observation that I'm guessing no one else has made before: the arrival of ChatGPT and LLMs has changed the way people search, and is, dare I say, going to change even further. I'll be here all day. + +More seriously, anyone that has used Google, ChatGPT, Claude, or Gemini in the last two years (so really everyone, period) is bound to have perceived changes in the way that they can search, the way that search results are being presented to them, and maybe thus changing the way they search. + +### When ChatGPT changed the game + +When ChatGPT entered the mainstream, it undeniably altered expectations. For the first time at scale, users experienced a system that could respond to complex, layered questions phrased in a conversational manner that synthesised results rather than ranking them in a list of links. The contrast with traditional search was sharp—Google had trained users to be selective in the words they choose, emphasising concision and precision, while LLMs permitted users to be less intentional and more conversational in their queries. For that and many more reasons, users flocked to ChatGPT, and Google had to respond. + +### Google's response: AI Overviews + +On top of introducing their own ChatGPT-esque platform, Gemini, Google recognised that it had to respond with a solution integrated within the existing architecture of search that they pioneered and propagated for the last two decades. What began as Search Generative Experience evolved into AI Overviews, and within a year expanded to over 100 countries and territories with more than one billion monthly users. By May 2025, it reported availability in 200+ countries and 40+ languages, describing over 1.5 billion users engaging with AI Overviews globally ([Google, Oct 2024 rollout announcement](https://blog.google/products/search/ai-overviews-expansion/)) ([Google, May 2025 expansion update](https://blog.google/products/search/google-search-ai-overviews-update/)). + +### 2026: The data is here + +Google may have prevented an exodus of users by introducing AI Overviews, and nearly two years on, we have an ample amount of data on AIOs to analyse how it is constructed, when it appears, and how users are interacting with it. More importantly, we can draw inferences from this data to predict where search is headed next. + +## What the Data Shows + +### AI Overviews appear between 18–25% of the time + +AI Overviews do not appear on every query, and it seems Google is still figuring out how often AIOs should appear, with the percentage shifting inconsistently. + +SE Ranking reported AI Overviews appearing on 7.47 percent of sampled US keywords in July 2024, rising to 18.76 percent by November 2024, with UK prevalence at 19.23 percent in the same period ([SE Ranking SERP study, 2024](https://seranking.com/blog/ai-overviews-study/)). Semrush, analysing more than 10 million keywords, reported 6.49 percent prevalence in January 2025, peaking at 24.61 percent in July 2025 before stabilising at 15.69 percent in November 2025 ([Semrush AI Overview analysis, 2025](https://www.semrush.com/blog/ai-overviews-study/)). A real-user browsing panel from Pew Research Center observed AI summaries in 18 percent of Google searches in its March 2025 dataset ([Pew Research Center, AI summaries user panel study, 2025](https://www.pewresearch.org/internet/2025/ai-summaries-in-google-search/)). + +--- + +### Longer, Conversational Queries Trigger AI Modules Disproportionately + +With regard to when AI Overviews are triggered, data shows that the structure of the user's query is a strong influence. + +Pew's behavioural analysis found that searches containing ten or more words triggered AI summaries 53 percent of the time, compared to just 8 percent for one- to two-word searches ([Pew Research Center query-length findings, 2025](https://www.pewresearch.org/internet/2025/ai-summaries-in-google-search/)). SE Ranking reported that four-plus word queries triggered AI Overviews 60.85 percent of the time in its November 2024 dataset ([SE Ranking long-tail findings, 2024](https://seranking.com/blog/ai-overviews-study/)). Semrush similarly observed that longer, more specific queries are more likely to produce AI modules ([Semrush AI Overview analysis, 2025](https://www.semrush.com/blog/ai-overviews-study/)). + +As users increasingly phrase searches as natural-language prompts, AI synthesis becomes more common. + +--- + +### AI Exposure Is Expanding Beyond Informational Queries + +AI Overview's early rollout was heavily skewed toward appearing in informational queries, but that pattern is shifting. + +Informational queries accounted for 91.3 percent of AI-triggering keywords in January 2025, declining to 57.1 percent by October 2025. During the same period, navigational queries triggering AI Overviews increased from 0.74 percent to 10.33 percent, with commercial and transactional categories also rising ([Semrush intent shift analysis, 2025](https://www.semrush.com/blog/ai-overviews-study/)). + +This means that organic results are not only under threat for informational searches, but also with branded and purchase-adjacent search queries. + +--- + +### AI Overviews are displacing #1 results... + +Outside of the fact that AI Overviews have been structurally integrated into a significant share of queries, the placement of AI Overviews - always the top of a search query - means that the top organic result's position is displaced. That means that #1 is now #2, although probably more accurately, #1 is probably around #4 or #5, with Sponsored Results, Featured Snippets, People Also Ask also taking up precious real estate in search results pre-AIO. + +This is even more prevalent on mobile, where screen real estate is even more scarce. 51.29% of search queries are on mobile, which, depending on the length of the AI Overview, could mean if the user does not scroll down, all they will see (and maybe even need) is the AI Overview. + +--- + +### ... Causing the decline of click-through rate + +This visual displacement's impact has been felt with significant user behavioural shifts. + +Seer Interactive analysed 3,119 informational queries across 42 organisations and found that organic CTR declined by 61 percent on queries with AI Overviews, with paid CTR declining by 68 percent over the same window ([Seer Interactive CTR analysis, 2024–2025](https://www.seerinteractive.com/blog/ai-overviews-impact-ctr/)). Ahrefs independently re-ran analysis using December 2025 data and observed a 58 percent lower average CTR for the top-ranking page when an AI Overview was present ([Ahrefs AI Overview CTR study, 2025](https://ahrefs.com/blog/ai-overviews-ctr/)). + +These figures do not indicate that search is vanishing, but instead the way users interact with search is - if an AI Overview appears, the need for clicking into an article decreases dramatically. + +--- + +### Zero-Click Behaviour Continues to Rise + +The decline in click-through rate, however, cannot be purely attributed to the rise of AI Overviews. The decline in clicks aligns with broader zero-click trends that predate the introduction of AIOs. + +Clickstream research conducted using Datos and SparkToro estimated that 58.5 percent of US searches and 59.7 percent of EU searches in 2024 ended without any click, meaning no ad, no Google-owned property, and no external website was visited. Only 360 per 1,000 US searches resulted in a click to the open web ([SparkToro & Datos zero-click study, 2024](https://sparktoro.com/blog/zero-click-search-study-2024/)). + +Desktop-only figures are lower but rising. In the US, desktop no-click searches increased from 24.4 percent in March 2024 to 27.2 percent in March 2025, with EU and UK figures rising from 23.6 percent to 26.1 percent in the same period ([SparkToro desktop search analysis, 2025](https://sparktoro.com/blog/desktop-search-zero-click-update/)). + +AI Overviews did not create zero-click behaviour, but it is reinforcing the trajectory that was already underway. + +--- + +## What the Data Shows Has Not Fundamentally Changed + +With so much change in the structure of search results, the behaviour of Google, and the behaviour of search users, some continuity lies in the composition of AI Overviews. + +### AI Overviews Still Draw From Established Organic Rankings + +Despite visual shifts, citation patterns remain anchored in traditional ranking strength. + +75 percent of sites cited within AI Overviews came from the top 12 organic rankings, and 90 percent from position 35 or higher ([Botify & DemandSphere AI citation study, 2025](https://www.botify.com/blog/ai-overviews-study/)). SE Ranking reported that 92.36 percent of US AI Overviews linked to at least one domain ranking in the top 10, with UK figures at 93.78 percent ([SE Ranking citation overlap findings, 2024](https://seranking.com/blog/ai-overviews-study/)). + +This substantial overlap suggests that AI synthesis layers draw primarily from the same authority pool that traditional organic rankings have prioritised for years. AI Overviews, and LLM search responses in general, are still drawing their results from Google's rankings, and have not changed that playbook. + +--- + +### Semantic Relevance Remains Central + +Botify and DemandSphere also observed that semantic similarity between AI summaries and cited pages strongly correlates with citation likelihood ([Botify & DemandSphere semantic findings, 2025](https://www.botify.com/blog/ai-overviews-study/)). Google's documentation explains that AI Overviews use "query fan-out" techniques and do not require additional technical configuration beyond standard indexing and snippet eligibility ([Google Search documentation on AI Overviews](https://developers.google.com/search/docs/appearance/ai-overviews)). + +This means that foundational SEO principles such as structured clarity, semantic alignment, and topical authority remain central to visibility, and articles that answer the user's search intent using natural language will still be regarded as authoritative sources and cited. + +--- + +### Dominant Domains Continue to Dominate + +Pew's study found that Wikipedia, YouTube, Reddit, and .gov domains frequently appear within AI summaries ([Pew Research Center citation analysis, 2025](https://www.pewresearch.org/internet/2025/ai-summaries-in-google-search/)). These are domains long recognised for strong authority signals within traditional search. + +The continuity indicates that while presentation evolves, the hierarchy of credibility remains largely intact. + +--- + +## So What Is Next for Search? + +Two prevailing narratives dominate discussions about search's future. The first declares SEO dead—that generative interfaces will replace ranked links entirely, and that optimising for Google will become as relevant as optimising for Yahoo. The second insists that the bulk of the change has already occurred, and that this is what search will look like for the foreseeable future. + +We at Fluid Posts believe in neither of these extremes (which might have been unfairly represented for the sake of simplicity), but lean closer to the latter. + +### The "SEO Is Dead" Argument Doesn't Hold Up + +The popularised, overly simplified "SEO is dead" argument goes something like this: users are abandoning Google for ChatGPT and Perplexity, AI will synthesise answers without needing to cite sources, and the era of click-based discovery is over. + +The numbers tell a different story. Google still processes roughly 210 times more searches than ChatGPT ([Ahrefs, 2025](https://ahrefs.com/blog/chatgpt-has-12-percent-of-googles-search-volume/)). More importantly, Google sends 190 times more traffic to websites than ChatGPT does — ChatGPT's click-through rate is 96 percent lower than Google's because the product is designed to keep users in conversation, not send them elsewhere. + +Even among users who have adopted AI tools, Google search usage has increased, not decreased ([SparkToro, 2024](https://sparktoro.com/blog/new-research-google-search-grew-20-in-2024-receives-373x-more-searches-than-chatgpt/)). The "exodus" narrative is not supported by behavioural data. + +Then there's the question of where AI tools get their answers. ChatGPT Search is powered by Microsoft Bing's index. Google's AI Overviews draw from their own organic rankings — as aforementioned, 92 percent of US AI Overviews link to at least one domain in the top 10. These systems are not replacing search indexes, but being built on top of them. + +The infrastructure that determines what is credible — the ranking algorithms refined over two decades across trillions of queries—remains the foundation. Generative models excel at synthesis, but synthesis still requires grounding. They cannot extract answers from nothing. + +### The "Nothing Has Changed" Argument Is Equally Flawed + +Dismissing AI Overviews as irrelevant ignores real shifts in user behaviour. A 61 percent decline in organic CTR when an AI Overview appears is not trivial. Zero-click searches approaching 60 percent means the majority of queries now resolve without a single click to the open web. + +The interface is changing. The way users interact with search results is changing. The visual hierarchy of the SERP has been fundamentally restructured. + +What has not changed is how credibility is measured. The same signals that determined authority in 2015 — topical depth, semantic relevance, domain trust, backlink profiles — still determine which sources get cited in AI summaries. The presentation layer is new, but the underlying ranking logic is not. + +### Our Perspective + +#### Concentration, not extinction + +We at Fluid Posts believe the next phase of search is concentration, not extinction. + +Fewer clicks will reach the open web, citation share within AI modules will become more prevalent, and established domains with sustained authority and topical depth will compound their advantage as interface space tightens. This all means that it will get lonelier at the top, with fewer clicks and less brand visibility to go around. + +The value of SEO and optimising brand visibility on search engines has never been higher—getting your brand seen, in however competitive or uncompetitive a space, will bring you the right users in bulk. + +#### The playbook hasn't changed + +The good news is that the playbook is the same as it has always been: produce content that genuinely answers user intent, build authority through consistent topical coverage, and earn trust through accuracy and depth. The sites that do this well will surface in AI Overviews and generative AI search queries because they draw from the same authority pool that organic rankings have always used. + +#### What we're seeing at Fluid Posts + +Here at Fluid Posts, our experience confirms this interpretation. One of our clients, Dispute Ninja, was cited by both ChatGPT and Gemini within days of ranking #1 on Google for their target keyword. That pattern has repeated across our client base: organic rankings remain the leading indicator of AI visibility. + +#### The trajectory and our bet + +This does not mean search will stay static. Google's market share has dipped below 90 percent for the first time since 2010. Younger users show higher preference for ChatGPT. AI-driven traffic to retail sites surged 1,200 percent since mid-2024, and users arriving via LLMs convert at seven times the rate of Google traffic ([Forbes, 2025](https://www.forbes.com/sites/kevinkruse/2025/08/14/seo-is-dead-3-strategies-to-win-in-the-age-of-ai-search/)). + +The trajectory is clear: AI interfaces will continue to grow in prominence, but the systems determining what those interfaces surface remain anchored in traditional search infrastructure. We believe this tracks. Google has been the leading presenter of information for two decades, indexing and ranking more content than any system in human history. The algorithm they have devised, refined across trillions of queries and under constant adversarial pressure, has been king of search for two decades for a reason—it works. + +Could AI systems develop independent authority signals? Absolutely. But building that infrastructure would require the same scale, iteration, and adversarial refinement that Google's algorithm accumulated over twenty years—all to fulfil the same central tenet of search: satisfying user intent. Our bet is that even if LLMs devise a credibility system of their own, it will not look too dissimilar to what Google has built. + +In any case, even if LLMs manage to devise a completely independent infrastructure to evaluate authority signals, it will not happen overnight, and when that shift occurs, it will be noticed. Case in point: when Reddit started being cited heavily by ChatGPT, it did not occur in secret. + +For now, the presentation of search results is new, but authority remains the central currency. Which theory ultimately proves correct—whether AI fully displaces traditional search or remains a layer on top of it—will unfold over the next several years, as everyone watches with three eyes open. diff --git a/apps/seo-www/src/routeTree.gen.ts b/apps/seo-www/src/routeTree.gen.ts index e3f77c3aa..06a5a122f 100644 --- a/apps/seo-www/src/routeTree.gen.ts +++ b/apps/seo-www/src/routeTree.gen.ts @@ -10,7 +10,6 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as WhoWeAreRouteImport } from './routes/who-we-are' -import { Route as ReferralRouteImport } from './routes/referral' import { Route as BlogRouteRouteImport } from './routes/blog/route' import { Route as IndexRouteImport } from './routes/index' import { Route as BlogIndexRouteImport } from './routes/blog/index' @@ -26,11 +25,6 @@ const WhoWeAreRoute = WhoWeAreRouteImport.update({ path: '/who-we-are', getParentRoute: () => rootRouteImport, } as any) -const ReferralRoute = ReferralRouteImport.update({ - id: '/referral', - path: '/referral', - getParentRoute: () => rootRouteImport, -} as any) const BlogRouteRoute = BlogRouteRouteImport.update({ id: '/blog', path: '/blog', @@ -81,7 +75,6 @@ const ApiBlogSearchRoute = ApiBlogSearchRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/blog': typeof BlogRouteRouteWithChildren - '/referral': typeof ReferralRoute '/who-we-are': typeof WhoWeAreRoute '/blog/$': typeof BlogSplatRoute '/blog/rss.xml': typeof BlogRssDotxmlRoute @@ -93,7 +86,6 @@ export interface FileRoutesByFullPath { } export interface FileRoutesByTo { '/': typeof IndexRoute - '/referral': typeof ReferralRoute '/who-we-are': typeof WhoWeAreRoute '/blog/$': typeof BlogSplatRoute '/blog/rss.xml': typeof BlogRssDotxmlRoute @@ -107,7 +99,6 @@ export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/blog': typeof BlogRouteRouteWithChildren - '/referral': typeof ReferralRoute '/who-we-are': typeof WhoWeAreRoute '/blog/$': typeof BlogSplatRoute '/blog/rss.xml': typeof BlogRssDotxmlRoute @@ -122,7 +113,6 @@ export interface FileRouteTypes { fullPaths: | '/' | '/blog' - | '/referral' | '/who-we-are' | '/blog/$' | '/blog/rss.xml' @@ -134,7 +124,6 @@ export interface FileRouteTypes { fileRoutesByTo: FileRoutesByTo to: | '/' - | '/referral' | '/who-we-are' | '/blog/$' | '/blog/rss.xml' @@ -147,7 +136,6 @@ export interface FileRouteTypes { | '__root__' | '/' | '/blog' - | '/referral' | '/who-we-are' | '/blog/$' | '/blog/rss.xml' @@ -161,7 +149,6 @@ export interface FileRouteTypes { export interface RootRouteChildren { IndexRoute: typeof IndexRoute BlogRouteRoute: typeof BlogRouteRouteWithChildren - ReferralRoute: typeof ReferralRoute WhoWeAreRoute: typeof WhoWeAreRoute LegalDataProcessingAgreementRoute: typeof LegalDataProcessingAgreementRoute LegalPrivacyPolicyRoute: typeof LegalPrivacyPolicyRoute @@ -178,13 +165,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof WhoWeAreRouteImport parentRoute: typeof rootRouteImport } - '/referral': { - id: '/referral' - path: '/referral' - fullPath: '/referral' - preLoaderRoute: typeof ReferralRouteImport - parentRoute: typeof rootRouteImport - } '/blog': { id: '/blog' path: '/blog' @@ -270,7 +250,6 @@ const BlogRouteRouteWithChildren = BlogRouteRoute._addFileChildren( const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, BlogRouteRoute: BlogRouteRouteWithChildren, - ReferralRoute: ReferralRoute, WhoWeAreRoute: WhoWeAreRoute, LegalDataProcessingAgreementRoute: LegalDataProcessingAgreementRoute, LegalPrivacyPolicyRoute: LegalPrivacyPolicyRoute, diff --git a/apps/seo-www/src/routes/-components/footer.tsx b/apps/seo-www/src/routes/-components/footer.tsx index de1d406c1..c7dcc4189 100644 --- a/apps/seo-www/src/routes/-components/footer.tsx +++ b/apps/seo-www/src/routes/-components/footer.tsx @@ -14,8 +14,8 @@ const links = [ href: "/who-we-are", }, { - title: "Referral", - href: "/referral", + title: "Pricing", + href: "/#pricing", }, { title: "Blog", diff --git a/apps/seo-www/src/routes/-components/header.tsx b/apps/seo-www/src/routes/-components/header.tsx index 47223e844..fede8253a 100644 --- a/apps/seo-www/src/routes/-components/header.tsx +++ b/apps/seo-www/src/routes/-components/header.tsx @@ -6,7 +6,7 @@ import { useState } from "react"; const menuItems = [ { name: "Blog", href: "/blog" }, - { name: "Referral", href: "/referral" }, + { name: "Pricing", href: "/#pricing" }, { name: "About us", href: "/who-we-are" }, ]; diff --git a/apps/seo-www/src/routes/index.tsx b/apps/seo-www/src/routes/index.tsx index 1b4629408..4bf2282d2 100644 --- a/apps/seo-www/src/routes/index.tsx +++ b/apps/seo-www/src/routes/index.tsx @@ -1015,7 +1015,10 @@ function FeaturesSection() { function PricingSection() { return ( -
    +
    {/* Dot pattern - same as Real Results */}
    -
    -
    -

    - Referral program -

    -

    - Help anyone win their SEO Co-Founder. Get rewarded. -

    -

    - Word of mouth matters a lot to us — and we'd love to show our - appreciation to anyone who refers customers our way. -

    -
    -
    - -
    -
    -
    -

    - 1) Share -

    -

    - Send your referral link -

    -

    - Share it with anyone you think would benefit. -

    -
    -
    -

    - 2) They onboard -

    -

    - Referee is onboarded -

    -

    - And enjoys their SEO Co-Founder — strategy, content, and reporting - handled end-to-end. -

    -
    -
    -

    - 3) You get rewarded -

    -

    - Reward unlocked after month 2 -

    -

    - Once your referral completes their first 2 months with us, - you'll receive a reward worth the full value of their first - two months. -

    -
    -
    -
    - -
    -
    -
    -
    -

    - Referral rewards -

    -

    - Here's how we'll say thanks. -

    -
    - -
    -

    - Current program (beta) -

    -
    -
    -

    - Reward = 2 months of their plan -

    -

    - After they complete their first 2 months with us, - you'll get a reward worth the full price of those first - two months. -

    -
    -
    -

    - Super-referrer perks (coming soon) -

    -

    - Refer more than 5 businesses and we'll unlock - additional rewards and priority perks. -

    -
    -

    - Terms may evolve as we scale the program. We'll always - confirm the current terms before onboarding your referral. -

    -
    -
    -
    - -
    -

    How to refer

    -

    - Email{" "} - - aaron@fluidposts.com - {" "} - with the subject “Referral” and we'll send you a referral - link. (We're keeping it lightweight while the program is in - beta.) -

    -
    -
    -
    - - ); -} diff --git a/apps/seo-www/src/routes/who-we-are.tsx b/apps/seo-www/src/routes/who-we-are.tsx index a5683cf4e..ba5a6882c 100644 --- a/apps/seo-www/src/routes/who-we-are.tsx +++ b/apps/seo-www/src/routes/who-we-are.tsx @@ -1,6 +1,4 @@ -import { Section } from "@rectangular-labs/ui/components/ui/section"; -import { createFileRoute } from "@tanstack/react-router"; -import { FAQ } from "~/routes/-components/original/faq"; +import { Link, createFileRoute } from "@tanstack/react-router"; export const Route = createFileRoute("/who-we-are")({ component: WhoWeArePage, @@ -8,62 +6,233 @@ export const Route = createFileRoute("/who-we-are")({ function WhoWeArePage() { return ( -
    -
    -
    -

    - About us -

    -

    - We're Winston and Aaron. -
    - - An engineer and a strategist. - -

    -

    - We actually build and rank sites ourselves — and we're - productizing the system that works. -

    +
    +
    +
    + +
    +
    + +
    +
    +

    + About Fluid Posts +

    +

    + We help businesses grow + . +
    + + Organically. + +

    +

    + Fluid Posts is an SEO company built by practitioners. We've + ranked our own sites, learned what works, and productised that + system so other businesses can achieve the same results. +

    +
    +
    -
    +
    -
    -
    -
    -
    -

    - Winston +

    +
    + +
    + +
    +
    +

    + The Team + . +

    +
    +
    + +
    +
    +
    +

    + Winston +

    +

    + Co-founder · Engineering +

    +
    +

    + Five years building automation systems in Silicon Valley. + Winston handles the technical infrastructure—data pipelines, + content automation, and the systems that keep everything running + reliably at scale.

    -

    - Winston spent 5 years in Silicon Valley building automation - systems for startups. Now he uses that same engineering - precision to automate growth processes and get results fast. +

    + +
    +
    +

    + Aaron +

    +

    + Co-founder · Strategy +

    +
    +

    + Law background from Oxford, now focused on content strategy. + Aaron leads keyword research, competitor analysis, and the + editorial process that turns topics into pages that rank. +

    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    + Our Approach + . +

    +
    +
    + +
    +
    +

    + We started by ranking our own projects. Through trial and error, + we figured out which SEO practices actually move the needle and + which are noise. That experience became the foundation for Fluid + Posts.

    -
    -

    - Aaron + +

    +

    + We now apply that same methodology to help businesses grow their + organic traffic—without the typical agency overhead or the need + for in-house expertise.

    -

    - Aaron, trained in law at Oxford, knows how to make words rank. - He's taken multiple pages to the top of Google through - structure, clarity, and intent-driven writing. +

    + +
    +

    + Every client gets a strategy tailored to their market, content + written to rank, and the ongoing support needed to sustain + results over time.

    +
    +
    -
    -

    - We know what we're doing in SEO — and we're productizing - that knowledge so it's accessible to everyone, not just teams - with time and budget. -

    +
    +
    +

    + Get in Touch + . +

    +

    + Questions about how we work? Reach out—we're happy to talk + through whether Fluid Posts is the right fit. +

    +
    +
    + + contact@fluidposts.com + + + Privacy Policy +
    +

    + Fluid Posts Pte. Ltd. · UEN: 202546443Z · Singapore +

    -
    - - +
    ); } diff --git a/apps/seo-www/vite.config.ts b/apps/seo-www/vite.config.ts index 77272c321..259127b91 100644 --- a/apps/seo-www/vite.config.ts +++ b/apps/seo-www/vite.config.ts @@ -3,7 +3,6 @@ import tailwindcss from "@tailwindcss/vite"; import { tanstackStart } from "@tanstack/react-start/plugin/vite"; import viteReact from "@vitejs/plugin-react"; import { generateSitemap } from "tanstack-router-sitemap"; -import mkcert from "vite-plugin-mkcert"; import viteTsConfigPaths from "vite-tsconfig-paths"; import { defineConfig } from "vitest/config"; import { serverEnv } from "./src/lib/env"; @@ -18,7 +17,6 @@ const config = defineConfig({ projects: ["./tsconfig.json"], }), tailwindcss(), - mkcert(), generateSitemap(sitemap), tanstackStart({ prerender: { @@ -39,8 +37,9 @@ const config = defineConfig({ viteReact(), ], server: { - host: "localhost", + host: true, port: 4242, + strictPort: false, }, }); diff --git a/packages/content/src/components/blog-post.tsx b/packages/content/src/components/blog-post.tsx index 221f1c2d1..db42493fb 100644 --- a/packages/content/src/components/blog-post.tsx +++ b/packages/content/src/components/blog-post.tsx @@ -68,12 +68,6 @@ export function BlogPost({ breadcrumb={{ enabled: false, }} - editOnGithub={{ - owner: "rectangular-labs", - repo: "monorepo", - sha: "main", - path: `packages/content/posts/${data._meta.fileName}`, - }} footer={{ enabled: true, }} @@ -139,6 +133,29 @@ export function BlogPost({ {data.description ? ( {data.description} ) : null} + {data.createdAt || data.authorDetail ? ( +
    + {data.authorDetail?.name ? ( + By {data.authorDetail.name} + ) : null} + {data.authorDetail?.name && data.createdAt ? · : null} + {data.createdAt ? ( + + ) : null} + {data.readingTime ? ( + <> + · + {data.readingTime} + + ) : null} +
    + ) : null} Date: Sun, 1 Mar 2026 02:25:48 +0800 Subject: [PATCH 5/8] feat(seo-www): section images, H2/H3 styling, who-we-are copy and layout Made-with: Cursor --- .../one-year-ai-overviews-google-search.mdx | 16 ++- apps/seo-www/src/routes/who-we-are.tsx | 120 +++++++----------- apps/seo-www/src/styles.css | 44 +++++++ packages/content/src/components/blog-post.tsx | 14 +- 4 files changed, 110 insertions(+), 84 deletions(-) diff --git a/apps/seo-www/content/one-year-ai-overviews-google-search.mdx b/apps/seo-www/content/one-year-ai-overviews-google-search.mdx index 506652f3e..59f3089c9 100644 --- a/apps/seo-www/content/one-year-ai-overviews-google-search.mdx +++ b/apps/seo-www/content/one-year-ai-overviews-google-search.mdx @@ -30,6 +30,8 @@ On top of introducing their own ChatGPT-esque platform, Gemini, Google recognise Google may have prevented an exodus of users by introducing AI Overviews, and nearly two years on, we have an ample amount of data on AIOs to analyse how it is constructed, when it appears, and how users are interacting with it. More importantly, we can draw inferences from this data to predict where search is headed next. +Charts and data analysis on screen + ## What the Data Shows ### AI Overviews appear between 18–25% of the time @@ -88,7 +90,7 @@ Desktop-only figures are lower but rising. In the US, desktop no-click searches AI Overviews did not create zero-click behaviour, but it is reinforcing the trajectory that was already underway. ---- +Search and data on a laptop ## What the Data Shows Has Not Fundamentally Changed @@ -120,6 +122,8 @@ The continuity indicates that while presentation evolves, the hierarchy of credi --- +AI and digital future concept + ## So What Is Next for Search? Two prevailing narratives dominate discussions about search's future. The first declares SEO dead—that generative interfaces will replace ranked links entirely, and that optimising for Google will become as relevant as optimising for Yahoo. The second insists that the bulk of the change has already occurred, and that this is what search will look like for the foreseeable future. @@ -146,9 +150,9 @@ The interface is changing. The way users interact with search results is changin What has not changed is how credibility is measured. The same signals that determined authority in 2015 — topical depth, semantic relevance, domain trust, backlink profiles — still determine which sources get cited in AI summaries. The presentation layer is new, but the underlying ranking logic is not. -### Our Perspective +## Our Perspective -#### Concentration, not extinction +### Concentration, not extinction We at Fluid Posts believe the next phase of search is concentration, not extinction. @@ -156,15 +160,15 @@ Fewer clicks will reach the open web, citation share within AI modules will beco The value of SEO and optimising brand visibility on search engines has never been higher—getting your brand seen, in however competitive or uncompetitive a space, will bring you the right users in bulk. -#### The playbook hasn't changed +### The playbook hasn't changed The good news is that the playbook is the same as it has always been: produce content that genuinely answers user intent, build authority through consistent topical coverage, and earn trust through accuracy and depth. The sites that do this well will surface in AI Overviews and generative AI search queries because they draw from the same authority pool that organic rankings have always used. -#### What we're seeing at Fluid Posts +### What we're seeing at Fluid Posts Here at Fluid Posts, our experience confirms this interpretation. One of our clients, Dispute Ninja, was cited by both ChatGPT and Gemini within days of ranking #1 on Google for their target keyword. That pattern has repeated across our client base: organic rankings remain the leading indicator of AI visibility. -#### The trajectory and our bet +### The trajectory and our bet This does not mean search will stay static. Google's market share has dipped below 90 percent for the first time since 2010. Younger users show higher preference for ChatGPT. AI-driven traffic to retail sites surged 1,200 percent since mid-2024, and users arriving via LLMs convert at seven times the rate of Google traffic ([Forbes, 2025](https://www.forbes.com/sites/kevinkruse/2025/08/14/seo-is-dead-3-strategies-to-win-in-the-age-of-ai-search/)). diff --git a/apps/seo-www/src/routes/who-we-are.tsx b/apps/seo-www/src/routes/who-we-are.tsx index ba5a6882c..d9565ebd9 100644 --- a/apps/seo-www/src/routes/who-we-are.tsx +++ b/apps/seo-www/src/routes/who-we-are.tsx @@ -89,46 +89,36 @@ function WhoWeArePage() {
    -
    -
    -

    - The Team - . -

    -
    -
    - -
    -
    -
    -

    - Winston -

    -

    - Co-founder · Engineering -

    -
    -

    - Five years building automation systems in Silicon Valley. - Winston handles the technical infrastructure—data pipelines, - content automation, and the systems that keep everything running - reliably at scale. +

    +

    + The Team + . +

    +

    + Fluid Posts is run by two people. Winston spent five years in + Silicon Valley building automation systems for startups; he handles + the technical side—data pipelines, content systems, and + infrastructure that runs reliably at scale. Aaron trained in law at + Oxford and moved into content strategy; he leads keyword research, + competitor analysis, and the editorial process that turns topics + into pages that rank. We built the company after ranking our own + projects and seeing the same approach work for clients. +

    +
    +
    +

    + Winston +

    +

    + Co-founder · Engineering

    - -
    -
    -

    - Aaron -

    -

    - Co-founder · Strategy -

    -
    -

    - Law background from Oxford, now focused on content strategy. - Aaron leads keyword research, competitor analysis, and the - editorial process that turns topics into pages that rank. +

    +

    + Aaron +

    +

    + Co-founder · Strategy

    @@ -165,40 +155,26 @@ function WhoWeArePage() {
    -
    -
    -

    - Our Approach - . -

    -
    -
    - -
    -
    -

    - We started by ranking our own projects. Through trial and error, - we figured out which SEO practices actually move the needle and - which are noise. That experience became the foundation for Fluid - Posts. -

    -
    - -
    -

    - We now apply that same methodology to help businesses grow their - organic traffic—without the typical agency overhead or the need - for in-house expertise. -

    -
    - -
    -

    - Every client gets a strategy tailored to their market, content - written to rank, and the ongoing support needed to sustain - results over time. -

    -
    +
    +

    + How We Work + . +

    +
    +

    + We started by ranking our own sites. That meant testing what + actually moved the needle—keyword research, content structure, + technical SEO—and ignoring the rest. The process we use for + clients is the same one we use for ourselves: understand the + market, identify gaps, produce content that answers real queries, + and keep optimising over time. +

    +

    + Every engagement includes a strategy tailored to your market, + content written to rank, and ongoing support so results hold. We + don’t do long-term contracts or opaque retainers; we work in clear + phases and report on what’s done. +

    diff --git a/apps/seo-www/src/styles.css b/apps/seo-www/src/styles.css index cc819efbe..6b8dd9538 100644 --- a/apps/seo-www/src/styles.css +++ b/apps/seo-www/src/styles.css @@ -21,3 +21,47 @@ .animate-grid-flow { animation: grid-flow 25s ease-in-out infinite; } + +/* Blog article: differentiate H2 (section) vs H3 (subheading) */ +.blog-article-prose h2 { + font-size: 1.75rem; + font-weight: 600; + letter-spacing: -0.02em; + margin-top: 2.5rem; + margin-bottom: 1rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid oklch(0.88 0 0); +} + +.blog-article-prose h2:first-child { + margin-top: 0; +} + +.blog-article-prose h3 { + font-size: 1.25rem; + font-weight: 600; + letter-spacing: -0.01em; + margin-top: 1.75rem; + margin-bottom: 0.5rem; + color: oklch(0.45 0 0); +} + +:root.dark .blog-article-prose h2, +.dark .blog-article-prose h2 { + border-bottom-color: oklch(0.28 0 0); +} + +:root.dark .blog-article-prose h3, +.dark .blog-article-prose h3 { + color: oklch(0.65 0 0); +} + +.blog-article-prose img { + border-radius: 0.75rem; + overflow: hidden; + margin-top: 1.5rem; + margin-bottom: 1.5rem; + width: 100%; + max-height: 320px; + object-fit: cover; +} diff --git a/packages/content/src/components/blog-post.tsx b/packages/content/src/components/blog-post.tsx index db42493fb..41bd38a34 100644 --- a/packages/content/src/components/blog-post.tsx +++ b/packages/content/src/components/blog-post.tsx @@ -156,12 +156,14 @@ export function BlogPost({ ) : null}
) : null} - - - +
+ + + +
{prevPost ? ( From 58971bc4fdcac228921b2e61fd6c571a409c7c2d Mon Sep 17 00:00:00 2001 From: Marcellolepoe <67198779+Marcellolepoe@users.noreply.github.com> Date: Sun, 1 Mar 2026 02:34:23 +0800 Subject: [PATCH 6/8] fix(seo-www): make navbar sticky on all viewports Made-with: Cursor --- apps/seo-www/src/routes/-components/header.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/seo-www/src/routes/-components/header.tsx b/apps/seo-www/src/routes/-components/header.tsx index fede8253a..5969461f0 100644 --- a/apps/seo-www/src/routes/-components/header.tsx +++ b/apps/seo-www/src/routes/-components/header.tsx @@ -48,9 +48,9 @@ export function Header() { const [menuState, setMenuState] = useState(false); return ( -
+