# SaaS Landing

> Complete SaaS marketing homepage template assembled from free blocks: hero section, social proof, features, stats, testimonials, pricing, FAQ, and a closing CTA.

A shadcn/ui block from the [@7ovr](https://7ovr.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/7ovr/saas-landing).

- Page, with a live preview: https://shadcn.exchange/r/7ovr/saas-landing
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/7ovr/saas-landing-light-855cdbfb2b100ad3.png
- Registry item: https://7ovr.com/r/saas-landing.json
- Categories: bento, cta, faqs, features, footer, header, hero, logo-cloud, pricing, stats, testimonials
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://7ovr.com/r/saas-landing.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@base-ui/react`, `next-themes`
- Registry items: `accordion`, `avatar`, `badge`, `button`, `card`, `dialog`, `dropdown-menu`, `field`, `input`, `separator`, `sheet`, `sonner`, `textarea`, `utils`

## Notes from the registry

Requires a `base-*` style in components.json (the `shadcn init` default). Legacy `new-york`/`radix-*` styles install Radix primitives, which reject the `render` prop this block uses.

## Files

### `registry/templates/saas-landing/install-page.tsx`

```tsx
import { Toaster } from "@/components/ui/sonner"
import Bento from "@/components/saas-landing/bento"
import Cta from "@/components/saas-landing/cta"
import Faqs from "@/components/saas-landing/faqs"
import Features from "@/components/saas-landing/features"
import Footer from "@/components/saas-landing/footer"
import Header from "@/components/saas-landing/header"
import Hero from "@/components/saas-landing/hero"
import LogoCloud from "@/components/saas-landing/logo-cloud"
import Pricing from "@/components/saas-landing/pricing"
import Stats from "@/components/saas-landing/stats"
import Testimonials from "@/components/saas-landing/testimonials"

const pool = (size: string, color: string, mid: string, out: string) =>
  `radial-gradient(${size}, ${color}, ${mid} 38%, ${out} 78%)`

const wash = (base: string, a: number, b: number) => {
  const at = (v: number) => `rgba(${base},${v})`
  return [
    pool("38% 13% at 84% 9%", at(a), at(a / 2), at(0)),
    pool("42% 13% at 12% 28%", at(b), at(b / 2), at(0)),
    pool("40% 12% at 70% 47%", at(a), at(a / 2), at(0)),
    pool("42% 12% at 14% 66%", at(b), at(b / 2), at(0)),
    pool("40% 13% at 74% 87%", at(a), at(a / 2), at(0)),
  ].join(",")
}

const WASH_LIGHT = wash("0,0,0", 0.04, 0.034)
const WASH_DARK = wash("255,255,255", 0.06, 0.051)

export default function SaasLandingTemplate() {
  return (
    <div className="relative isolate flex min-h-svh w-full flex-col bg-background text-foreground">
      <div
        aria-hidden="true"
        className="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[720px] bg-[radial-gradient(65%_60%_at_50%_-8%,rgba(0,0,0,0.06),transparent_72%)] dark:bg-[radial-gradient(65%_60%_at_50%_-8%,rgba(255,255,255,0.13),transparent_72%)]"
      />
      <div
        aria-hidden="true"
        className="pointer-events-none absolute inset-0 -z-10 dark:hidden"
        style={{ backgroundImage: WASH_LIGHT }}
      />
      <div
        aria-hidden="true"
        className="pointer-events-none absolute inset-0 -z-10 hidden dark:block"
        style={{ backgroundImage: WASH_DARK }}
      />
      <div
        aria-hidden="true"
        className="pointer-events-none absolute inset-x-0 bottom-0 -z-10 h-[560px] bg-[radial-gradient(55%_50%_at_50%_100%,rgba(0,0,0,0.05),transparent_70%)] dark:bg-[radial-gradient(55%_50%_at_50%_100%,rgba(255,255,255,0.08),transparent_70%)]"
      />
      <Toaster />
      <Header />
      <main className="flex w-full flex-col">
        <Hero />
        <LogoCloud />
        <Features />
        <Bento />
        <Stats />
        <Testimonials />
        <Pricing />
        <Faqs />
        <Cta />
      </main>
      <div className="border-t border-border/50">
        <Footer />
      </div>
    </div>
  )
}
```

### `registry/templates/saas-landing/install-route.tsx`

```tsx
export { default } from "@/components/saas-landing/page"
```

### `registry/templates/saas-landing/components/bento.tsx`

```tsx
import { Badge } from "@/components/ui/badge"
import { Card } from "@/components/ui/card"
import { cn } from "@/lib/utils"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"
import type * as React from "react"

type IconProps = { className?: string; size?: number | string }

type IconRenderer = (props: IconProps) => React.ReactNode

export default function Bento() {
  return (
    <section className="flex w-full items-center justify-center px-6 py-16 sm:py-24">
      <div className="mx-auto w-full max-w-6xl">
        <div className="max-w-2xl">
          <Badge variant="outline" className="mb-4 tracking-widest uppercase">
            Capabilities
          </Badge>
          <h2 className="font-heading text-3xl font-bold tracking-tight text-balance sm:text-4xl">
            Everything Acme runs on, in one grid
          </h2>
          <p className="mt-4 text-muted-foreground">
            A composable platform that scales from your first deploy to your
            millionth request, without changing tools.
          </p>
        </div>

        <div className="mt-12 grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4 md:grid-rows-[repeat(2,minmax(0,1fr))_auto]">
          <Card className="relative flex flex-col justify-between gap-8 overflow-hidden rounded-lg border-border p-8 sm:col-span-2 md:col-span-2 md:row-span-2">
            <div className="flex flex-col gap-4">
              <span className="flex size-12 items-center justify-center rounded-lg border border-border bg-primary text-primary-foreground">
                <IconPlaceholder
                  lucide="Sparkles"
                  tabler="IconSparkles"
                  hugeicons="SparklesIcon"
                  phosphor="Sparkle"
                  remixicon="RiSparklingLine"
                  className="size-6"
                  aria-hidden="true"
                />
              </span>
              <div>
                <h3 className="font-heading text-2xl font-semibold tracking-tight">
                  Intelligent automation engine
                </h3>
                <p className="mt-3 max-w-sm text-muted-foreground">
                  Define workflows once and let Acme orchestrate retries,
                  scaling, and rollbacks across every environment automatically.
                </p>
              </div>
            </div>
            <div className="flex items-end gap-1.5" aria-hidden="true">
              {[28, 40, 33, 52, 45, 66, 54, 78, 64, 92].map((h, i, arr) => (
                <div
                  key={i}
                  className={cn(
                    "flex-1",
                    i === arr.length - 1 ? "bg-primary" : "bg-primary/25"
                  )}
                  style={{ height: `${h}px` }}
                />
              ))}
            </div>
          </Card>

          <Tile
            icon={(p: IconProps) => (
              <IconPlaceholder
                lucide="Clock"
                tabler="IconClock"
                hugeicons="TimeIcon"
                phosphor="Clock"
                remixicon="RiTimeLine"
                {...p}
              />
            )}
            title="Sub-second deploys"
            description="Ship globally in under 30 seconds from any branch."
          >
            <div className="mt-5 flex items-center gap-2" aria-hidden="true">
              <span className="text-3xl font-bold tracking-tight">0.4</span>
              <span className="text-sm text-muted-foreground">sec avg</span>
            </div>
          </Tile>

          <Tile
            icon={(p: IconProps) => (
              <IconPlaceholder
                lucide="ShieldCheck"
                tabler="IconShieldCheck"
                hugeicons="Shield01Icon"
                phosphor="ShieldCheck"
                remixicon="RiShieldCheckLine"
                {...p}
              />
            )}
            title="Zero-trust security"
            description="Granular policies and encryption on by default."
          >
            <div className="mt-5 space-y-2" aria-hidden="true">
              {[92, 74, 88].map((w, i) => (
                <div key={i} className="flex items-center gap-2">
                  <span className="size-2.5 shrink-0 bg-primary" />
                  <span className="h-1.5 flex-1 bg-muted">
                    <span
                      className="block h-full bg-primary/40"
                      style={{ width: `${w}%` }}
                    />
                  </span>
                </div>
              ))}
            </div>
          </Tile>

          <Tile
            icon={(p: IconProps) => (
              <IconPlaceholder
                lucide="ChartBar"
                tabler="IconChartBar"
                hugeicons="BarChartIcon"
                phosphor="ChartBar"
                remixicon="RiBarChartBoxLine"
                {...p}
              />
            )}
            title="Live analytics"
            description="Custom metrics with sub-second refresh."
          >
            <div className="mt-5 flex items-end gap-1.5" aria-hidden="true">
              {[34, 50, 40, 60, 48, 74].map((h, i, arr) => (
                <div
                  key={i}
                  className={cn(
                    "flex-1",
                    i === arr.length - 1 ? "bg-primary" : "bg-primary/30"
                  )}
                  style={{ height: `${h}px` }}
                />
              ))}
            </div>
          </Tile>

          <Tile
            icon={(p: IconProps) => (
              <IconPlaceholder
                lucide="Cpu"
                tabler="IconCpu"
                hugeicons="CpuIcon"
                phosphor="Cpu"
                remixicon="RiCpuLine"
                {...p}
              />
            )}
            title="Elastic compute"
            description="Scale to zero, burst to thousands of cores."
          >
            <div className="mt-5 space-y-1.5" aria-hidden="true">
              <div className="h-2 w-full rounded-sm bg-muted">
                <div className="h-full w-3/4 rounded-lg bg-primary/40" />
              </div>
              <div className="h-2 w-full rounded-sm bg-muted">
                <div className="h-full w-1/2 rounded-sm bg-primary/40" />
              </div>
            </div>
          </Tile>

          <Tile
            className="sm:col-span-2 md:col-span-4"
            icon={(p: IconProps) => (
              <IconPlaceholder
                lucide="GitBranch"
                tabler="IconGitBranch"
                hugeicons="GitBranchIcon"
                phosphor="GitBranch"
                remixicon="RiGitBranchLine"
                {...p}
              />
            )}
            title="Preview every branch"
            description="Each pull request gets an isolated, shareable environment with its own URL and data snapshot."
          >
            <div className="mt-5 flex items-center gap-3" aria-hidden="true">
              <span className="size-3 rounded-md bg-primary" />
              <span className="h-px flex-1 bg-border" />
              <span className="size-2.5 rounded-sm border border-border bg-muted" />
              <span className="h-px flex-1 bg-border" />
              <span className="size-2.5 rounded-sm border border-border bg-muted" />
            </div>
          </Tile>
        </div>
      </div>
    </section>
  )
}

function Tile({
  icon: Icon,
  title,
  description,
  className,
  children,
}: {
  icon: IconRenderer
  title: string
  description: string
  className?: string
  children?: React.ReactNode
}) {
  return (
    <Card
      className={cn("flex flex-col rounded-lg border-border p-6", className)}
    >
      <span className="flex size-10 items-center justify-center rounded-md border border-border bg-muted">
        <Icon className="size-5" aria-hidden="true" />
      </span>
      <h3 className="mt-4 font-heading font-semibold tracking-tight">
        {title}
      </h3>
      <p className="mt-2 text-sm text-muted-foreground">{description}</p>
      {children}
    </Card>
  )
}
```

### `registry/templates/saas-landing/components/cta.tsx`

```tsx
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

export default function Cta() {
  return (
    <section className="flex w-full items-center justify-center px-6 py-16 sm:py-24">
      <div className="mx-auto w-full max-w-6xl rounded-xl border border-border bg-muted/30 px-6 py-14 text-center sm:px-12 sm:py-20">
        <Badge variant="outline" className="mb-4 tracking-widest uppercase">
          Get Started
        </Badge>
        <h2 className="font-heading text-3xl font-bold tracking-tight text-balance sm:text-4xl">
          Start building faster today.
        </h2>
        <p className="mx-auto mt-4 max-w-xl text-base text-muted-foreground">
          Ship production-ready interfaces in minutes with composable blocks,
          sensible defaults, and zero configuration.
        </p>

        <div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
          <Button
            render={<a href="#" />}
            nativeButton={false}
            className="w-full sm:w-auto"
          >
            Get Started
            <IconPlaceholder
              lucide="ArrowRight"
              tabler="IconArrowRight"
              hugeicons="ArrowRightIcon"
              phosphor="ArrowRight"
              remixicon="RiArrowRightLine"
              data-icon="inline-end"
              aria-hidden="true"
            />
          </Button>
          <Button
            variant="secondary"
            render={<a href="#" />}
            nativeButton={false}
            className="w-full sm:w-auto"
          >
            Read the Docs
          </Button>
        </div>

        <p className="mt-6 text-xs text-muted-foreground">
          No credit card required.
        </p>
      </div>
    </section>
  )
}
```

### `registry/templates/saas-landing/components/faqs.tsx`

```tsx
"use client"

import { useState } from "react"
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { toast } from "sonner"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

const faqs = [
  {
    q: "How do I get started with Acme?",
    a: "Sign up for a free account, create your first workspace, and follow the onboarding checklist. You will be up and running in under five minutes.",
  },
  {
    q: "Can I use Acme for multiple projects?",
    a: "Yes. Every account supports unlimited projects. You can organise them into separate workspaces and control access permissions per workspace.",
  },
  {
    q: "What payment methods do you accept?",
    a: "We accept all major credit and debit cards as well as ACH bank transfers for annual plans. Invoiced billing is available for Enterprise customers.",
  },
  {
    q: "How do I cancel my subscription?",
    a: "You can cancel at any time from Billing in your account settings. Your plan remains active until the end of the current billing period and will not renew.",
  },
  {
    q: "Is my data portable?",
    a: "Absolutely. You can export all your data as JSON or CSV from the Settings page at any time, with no restrictions or exit fees.",
  },
  {
    q: "Do you offer discounts for non-profits?",
    a: "We offer a 40% discount for verified non-profit organisations. Reach out to our team with your registration documents to apply.",
  },
]

export default function Faqs() {
  const [open, setOpen] = useState(false)

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    setOpen(false)
    toast.success("Message sent", {
      description: "Our support team typically replies within a few hours.",
    })
  }

  return (
    <section className="flex w-full items-center justify-center px-6 py-16 sm:py-24">
      <div className="mx-auto w-full max-w-6xl">
        <div className="grid grid-cols-1 gap-12 md:grid-cols-[1fr_1.6fr] md:gap-16">
          <div className="flex flex-col gap-6">
            <div className="flex flex-col gap-4">
              <Badge variant="outline" className="tracking-widest uppercase">
                FAQ
              </Badge>
              <h2 className="font-heading text-3xl font-bold tracking-tight text-balance sm:text-4xl">
                Questions &amp; answers
              </h2>
              <p className="text-sm leading-relaxed text-muted-foreground">
                Browse the most common questions about Acme below. If you do not
                find what you are looking for, our support team is always happy
                to help.
              </p>
            </div>

            <div className="flex flex-col gap-4 rounded-lg border border-border bg-card p-5">
              <div className="flex items-center gap-3">
                <div className="flex size-9 items-center justify-center rounded-md border border-border bg-background">
                  <IconPlaceholder
                    lucide="Mail"
                    tabler="IconMail"
                    hugeicons="MailIcon"
                    phosphor="Envelope"
                    remixicon="RiMailLine"
                    className="size-4 text-muted-foreground"
                  />
                </div>
                <div className="flex flex-col gap-0.5">
                  <span className="text-sm font-medium">
                    Still have questions?
                  </span>
                  <span className="text-xs text-muted-foreground">
                    We typically reply within a few hours.
                  </span>
                </div>
              </div>
              <Dialog open={open} onOpenChange={setOpen}>
                <DialogTrigger
                  render={<Button className="w-full justify-between" />}
                >
                  Contact Support
                  <IconPlaceholder
                    lucide="ArrowRight"
                    tabler="IconArrowRight"
                    hugeicons="ArrowRightIcon"
                    phosphor="ArrowRight"
                    remixicon="RiArrowRightLine"
                    data-icon="inline-end"
                  />
                </DialogTrigger>
                <DialogContent>
                  <form onSubmit={handleSubmit}>
                    <DialogHeader>
                      <DialogTitle>Contact support</DialogTitle>
                      <DialogDescription>
                        Tell us what is going on and we will get back to you,
                        usually within a few hours.
                      </DialogDescription>
                    </DialogHeader>

                    <FieldGroup className="my-4 gap-4">
                      <Field>
                        <FieldLabel htmlFor="support-email">Email</FieldLabel>
                        <Input
                          id="support-email"
                          type="email"
                          required
                          placeholder="jane@company.com"
                        />
                      </Field>
                      <Field>
                        <FieldLabel htmlFor="support-message">
                          How can we help?
                        </FieldLabel>
                        <Textarea
                          id="support-message"
                          required
                          rows={4}
                          className="min-h-24 resize-none"
                          placeholder="Describe your question or issue…"
                        />
                      </Field>
                    </FieldGroup>

                    <DialogFooter>
                      <DialogClose render={<Button variant="outline" />}>
                        Cancel
                      </DialogClose>
                      <Button type="submit">Send Message</Button>
                    </DialogFooter>
                  </form>
                </DialogContent>
              </Dialog>
            </div>
          </div>

          <Accordion defaultValue={[faqs[0].q]}>
            {faqs.map(({ q, a }) => (
              <AccordionItem key={q} value={q}>
                <AccordionTrigger className="py-3.5 text-sm font-medium">
                  {q}
                </AccordionTrigger>
                <AccordionContent className="pb-3.5 text-sm text-muted-foreground">
                  {a}
                </AccordionContent>
              </AccordionItem>
            ))}
          </Accordion>
        </div>
      </div>
    </section>
  )
}
```

### `registry/templates/saas-landing/components/features.tsx`

```tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Separator } from "@/components/ui/separator"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

type IconProps = { className?: string; size?: number | string }

const rows = [
  {
    eyebrow: "Collaboration",
    Icon: (p: IconProps) => (
      <IconPlaceholder
        lucide="Users"
        tabler="IconUsersGroup"
        hugeicons="UserGroupIcon"
        phosphor="UsersThree"
        remixicon="RiTeamLine"
        {...p}
      />
    ),
    title: "Work as one, ship faster together",
    body: "One shared workspace where roles, live presence, and threaded comments keep everyone aligned.",
    bullets: [
      "Granular roles: viewer, editor, admin",
      "Real-time presence and inline comments",
      "Version history with one-click restore",
      "Guest access with expiring links",
    ],
    cta: "Explore Collaboration",
    img: "https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=800&q=80",
    imgAlt: "Team collaboration interface showing shared workspace",
    avatars: [
      {
        name: "Sarah Kim",
        initials: "SK",
        src: "https://i.pravatar.cc/150?img=47",
      },
      {
        name: "Marcus Webb",
        initials: "MW",
        src: "https://i.pravatar.cc/150?img=12",
      },
      {
        name: "Priya Nair",
        initials: "PN",
        src: "https://i.pravatar.cc/150?img=32",
      },
    ],
    stat: { value: "4.2×", label: "Faster Review Cycles" },
  },
  {
    eyebrow: "Analytics",
    Icon: (p: IconProps) => (
      <IconPlaceholder
        lucide="BarChart"
        tabler="IconChartBar"
        hugeicons="BarChartIcon"
        phosphor="ChartBar"
        remixicon="RiBarChartLine"
        {...p}
      />
    ),
    title: "Decisions grounded in real data",
    body: "Turn raw events into clear, actionable dashboards in minutes, with no SQL or data-engineering bottleneck.",
    bullets: [
      "Sub-second query engine for large datasets",
      "Funnel, retention, and cohort views built-in",
      "Scheduled email and Slack reports",
      "CSV and REST API export",
    ],
    cta: "See Analytics in Action",
    img: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=800&q=80",
    imgAlt: "Analytics dashboard with funnel and retention charts",
    avatars: [
      {
        name: "James Okafor",
        initials: "JO",
        src: "https://i.pravatar.cc/150?img=68",
      },
      {
        name: "Lena Strauss",
        initials: "LS",
        src: "https://i.pravatar.cc/150?img=5",
      },
    ],
    stat: { value: "98%", label: "Query Success Rate" },
  },
  {
    eyebrow: "Security",
    Icon: (p: IconProps) => (
      <IconPlaceholder
        lucide="ShieldCheck"
        tabler="IconShieldCheck"
        hugeicons="Shield01Icon"
        phosphor="ShieldCheck"
        remixicon="RiShieldCheckLine"
        {...p}
      />
    ),
    title: "Enterprise-grade protection, zero friction",
    body: "Controls your compliance team will love and developers barely notice, with SSO, MFA, audit logs, and data residency built in.",
    bullets: [
      "SOC 2 Type II and ISO 27001 certified",
      "SSO via SAML 2.0 and OIDC",
      "Immutable audit log with SIEM export",
      "EU and US data-residency regions",
    ],
    cta: "Review Security Docs",
    img: "https://images.unsplash.com/photo-1555949963-ff9fe0c870eb?w=800&q=80",
    imgAlt: "Security controls panel with audit log",
    avatars: [
      {
        name: "Diana Reyes",
        initials: "DR",
        src: "https://i.pravatar.cc/150?img=9",
      },
      {
        name: "Tom Eriksen",
        initials: "TE",
        src: "https://i.pravatar.cc/150?img=53",
      },
      {
        name: "Aiko Tanaka",
        initials: "AT",
        src: "https://i.pravatar.cc/150?img=25",
      },
    ],
    stat: { value: "0", label: "Reported Breaches" },
  },
]

export default function Features() {
  return (
    <section className="flex w-full items-center justify-center px-6 py-16 sm:py-24">
      <div className="mx-auto w-full max-w-6xl">
        <div className="mx-auto mb-16 max-w-xl text-center">
          <Badge variant="outline" className="mb-4 tracking-widest uppercase">
            Platform
          </Badge>
          <h2 className="font-heading text-3xl font-bold tracking-tight text-balance sm:text-4xl">
            Built for every part of your workflow
          </h2>
          <p className="mt-4 text-base leading-relaxed text-muted-foreground">
            Acme brings collaboration, analytics, and security into one cohesive
            platform, so nothing falls between the cracks.
          </p>
        </div>

        <div className="flex flex-col">
          {rows.map((row, index) => {
            const isEven = index % 2 === 0
            return (
              <div key={row.eyebrow}>
                <div
                  className={`flex flex-col gap-10 py-16 md:flex-row md:items-center md:gap-16 ${
                    isEven ? "" : "md:flex-row-reverse"
                  }`}
                >
                  <div className="flex flex-1 flex-col gap-6">
                    <div className="flex items-center gap-2">
                      <span className="flex size-6 shrink-0 items-center justify-center rounded-md border border-border bg-muted">
                        <row.Icon
                          className="size-3.5 text-muted-foreground"
                          aria-hidden="true"
                        />
                      </span>
                      <span className="text-xs font-semibold tracking-widest text-muted-foreground uppercase">
                        {row.eyebrow}
                      </span>
                    </div>

                    <h3 className="font-heading text-2xl font-bold tracking-tight sm:text-[1.75rem] sm:leading-snug">
                      {row.title}
                    </h3>

                    <p className="leading-relaxed text-muted-foreground">
                      {row.body}
                    </p>

                    <ul className="flex flex-col gap-3">
                      {row.bullets.map((bullet) => (
                        <li
                          key={bullet}
                          className="flex items-center gap-3 text-sm"
                        >
                          <span className="flex size-[18px] shrink-0 items-center justify-center rounded-md bg-primary text-primary-foreground">
                            <IconPlaceholder
                              lucide="Check"
                              tabler="IconCheck"
                              hugeicons="Tick02Icon"
                              phosphor="Check"
                              remixicon="RiCheckLine"
                              className="size-2.5"
                              aria-hidden="true"
                            />
                          </span>
                          <span className="text-foreground">{bullet}</span>
                        </li>
                      ))}
                    </ul>

                    <div className="flex items-center gap-4 border-t border-border pt-5">
                      <div className="flex -space-x-2">
                        {row.avatars.map((av) => (
                          <Avatar
                            key={av.name}
                            className="size-7 border-2 border-background"
                          >
                            <AvatarImage
                              src={av.src}
                              alt={av.name}
                              className="grayscale"
                            />
                            <AvatarFallback className="text-[10px]">
                              {av.initials}
                            </AvatarFallback>
                          </Avatar>
                        ))}
                      </div>
                      <div className="flex items-baseline gap-1.5">
                        <span className="text-lg font-bold tabular-nums">
                          {row.stat.value}
                        </span>
                        <span className="text-xs text-muted-foreground">
                          {row.stat.label}
                        </span>
                      </div>
                    </div>

                    <div>
                      <Button variant="outline" size="sm">
                        {row.cta}
                        <IconPlaceholder
                          lucide="ArrowRight"
                          tabler="IconArrowRight"
                          hugeicons="ArrowRightIcon"
                          phosphor="ArrowRight"
                          remixicon="RiArrowRightLine"
                          data-icon="inline-end"
                        />
                      </Button>
                    </div>
                  </div>

                  <div className="flex flex-1 items-center justify-center">
                    <div className="relative aspect-[4/3] w-full overflow-hidden rounded-lg border border-border bg-muted">
                      <img
                        src={row.img}
                        alt={row.imgAlt}
                        className="size-full object-cover"
                      />
                      <div className="absolute inset-x-0 bottom-0 flex items-center gap-2 border-t border-border bg-background/95 px-4 py-2.5 backdrop-blur-sm">
                        <span className="flex size-5 shrink-0 items-center justify-center rounded-md border border-border bg-background">
                          <row.Icon
                            className="size-3 text-foreground"
                            aria-hidden="true"
                          />
                        </span>
                        <span className="text-[11px] font-medium tracking-wide text-foreground">
                          {row.eyebrow} Preview
                        </span>
                      </div>
                    </div>
                  </div>
                </div>

                {index < rows.length - 1 && <Separator />}
              </div>
            )
          })}
        </div>
      </div>
    </section>
  )
}
```

### `registry/templates/saas-landing/components/footer.tsx`

```tsx
"use client"

import * as React from "react"
import { useTheme } from "next-themes"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Separator } from "@/components/ui/separator"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

type IconProps = { className?: string; size?: number | string }

const columns = [
  {
    title: "Product",
    links: ["Features", "Integrations", "Pricing", "Changelog", "Roadmap"],
  },
  {
    title: "Company",
    links: ["About", "Careers", "Blog", "Press", "Contact"],
  },
  {
    title: "Resources",
    links: [
      "Documentation",
      "Guides",
      "Help Center",
      "API Status",
      "Community",
    ],
  },
  {
    title: "Legal",
    links: ["Privacy", "Terms", "Security", "Cookies", "Licenses"],
  },
]

const socials = [
  { label: "X", icon: (p: IconProps) => <XOutlineMark {...p} /> },
  { label: "GitHub", icon: (p: IconProps) => <GithubMark {...p} /> },
  { label: "LinkedIn", icon: (p: IconProps) => <LinkedinBoxMark {...p} /> },
]

const locales = [
  { code: "en", label: "English" },
  { code: "es", label: "Español" },
  { code: "de", label: "Deutsch" },
  { code: "fr", label: "Français" },
  { code: "ja", label: "日本語" },
]

export default function Footer() {
  const [locale, setLocale] = React.useState(locales[0])
  const { resolvedTheme, setTheme } = useTheme()
  const mounted = React.useSyncExternalStore(
    () => () => {},
    () => true,
    () => false
  )
  const isDark = mounted && resolvedTheme === "dark"

  return (
    <section className="flex w-full items-center justify-center px-6 py-16">
      <footer className="mx-auto w-full max-w-6xl">
        <div className="grid grid-cols-2 gap-10 sm:grid-cols-3 md:grid-cols-6">
          <div className="col-span-2 sm:col-span-3 md:col-span-2">
            <div className="flex items-center gap-2">
              <svg
                viewBox="0 0 24 24"
                fill="currentColor"
                aria-hidden="true"
                className="size-7 shrink-0 text-primary"
              >
                <rect
                  x="3"
                  y="3"
                  width="8"
                  height="8"
                  transform="rotate(-6 7 7)"
                />
                <rect
                  x="3"
                  y="13"
                  width="8"
                  height="8"
                  transform="rotate(5 7 17)"
                />
                <rect
                  x="13"
                  y="13"
                  width="8"
                  height="8"
                  transform="rotate(-4 17 17)"
                />
                <rect
                  x="13"
                  y="3"
                  width="8"
                  height="8"
                  transform="rotate(15 17 7)"
                />
              </svg>
              <span className="text-lg font-semibold tracking-tight">Acme</span>
            </div>
            <p className="mt-4 max-w-xs text-sm leading-relaxed text-muted-foreground">
              The composable platform teams use to ship polished products
              faster, from first prototype to global scale.
            </p>
            <div className="mt-6 flex items-center gap-2">
              {socials.map((social) => (
                <Button
                  key={social.label}
                  variant="outline"
                  size="icon"
                  aria-label={social.label}
                  className="rounded-lg"
                >
                  <social.icon className="size-4" />
                </Button>
              ))}
            </div>
          </div>

          {columns.map((column) => (
            <nav key={column.title} className="flex flex-col gap-3">
              <h3 className="font-heading text-sm font-semibold text-foreground">
                {column.title}
              </h3>
              <ul className="flex flex-col gap-2.5">
                {column.links.map((link) => (
                  <li key={link}>
                    <a
                      href="#"
                      className="text-sm text-muted-foreground transition-colors hover:text-foreground"
                    >
                      {link}
                    </a>
                  </li>
                ))}
              </ul>
            </nav>
          ))}
        </div>

        <Separator className="my-8" />

        <div className="flex flex-col-reverse items-start gap-4 sm:flex-row sm:items-center sm:justify-between">
          <p className="text-sm text-muted-foreground">
            © <span suppressHydrationWarning>{new Date().getFullYear()}</span>{" "}
            Acme, Inc. All rights reserved.
          </p>

          <div className="flex items-center gap-2">
            <DropdownMenu>
              <DropdownMenuTrigger
                render={
                  <Button variant="outline" size="sm" className="rounded-lg" />
                }
              >
                {locale.label}
                <IconPlaceholder
                  lucide="ChevronDown"
                  tabler="IconChevronDown"
                  hugeicons="ArrowDown01Icon"
                  phosphor="CaretDown"
                  remixicon="RiArrowDownSLine"
                  className="size-4 text-muted-foreground"
                  data-icon="inline-start"
                />
              </DropdownMenuTrigger>
              <DropdownMenuContent align="end" className="rounded-lg">
                {locales.map((item) => (
                  <DropdownMenuItem
                    key={item.code}
                    onClick={() => setLocale(item)}
                    className={cn(
                      "rounded-lg",
                      item.code === locale.code && "font-medium text-foreground"
                    )}
                  >
                    {item.label}
                  </DropdownMenuItem>
                ))}
              </DropdownMenuContent>
            </DropdownMenu>

            <Button
              variant="outline"
              size="icon-sm"
              aria-label={
                isDark ? "Switch to light mode" : "Switch to dark mode"
              }
              aria-pressed={isDark}
              onClick={() => setTheme(isDark ? "light" : "dark")}
              className="rounded-lg"
            >
              {isDark ? (
                <IconPlaceholder
                  lucide="Sun"
                  tabler="IconSun"
                  hugeicons="SunIcon"
                  phosphor="Sun"
                  remixicon="RiSunLine"
                  className="size-4"
                />
              ) : (
                <IconPlaceholder
                  lucide="Moon"
                  tabler="IconMoon"
                  hugeicons="MoonIcon"
                  phosphor="Moon"
                  remixicon="RiMoonLine"
                  className="size-4"
                />
              )}
            </Button>
          </div>
        </div>
      </footer>
    </section>
  )
}

type MarkProps = React.ComponentProps<"svg"> & { size?: number | string }

function GithubMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M12.001 2C6.47598 2 2.00098 6.475 2.00098 12C2.00098 16.425 4.86348 20.1625 8.83848 21.4875C9.33848 21.575 9.52598 21.275 9.52598 21.0125C9.52598 20.775 9.51348 19.9875 9.51348 19.15C7.00098 19.6125 6.35098 18.5375 6.15098 17.975C6.03848 17.6875 5.55098 16.8 5.12598 16.5625C4.77598 16.375 4.27598 15.9125 5.11348 15.9C5.90098 15.8875 6.46348 16.625 6.65098 16.925C7.55098 18.4375 8.98848 18.0125 9.56348 17.75C9.65098 17.1 9.91348 16.6625 10.201 16.4125C7.97598 16.1625 5.65098 15.3 5.65098 11.475C5.65098 10.3875 6.03848 9.4875 6.67598 8.7875C6.57598 8.5375 6.22598 7.5125 6.77598 6.1375C6.77598 6.1375 7.61348 5.875 9.52598 7.1625C10.326 6.9375 11.176 6.825 12.026 6.825C12.876 6.825 13.726 6.9375 14.526 7.1625C16.4385 5.8625 17.276 6.1375 17.276 6.1375C17.826 7.5125 17.476 8.5375 17.376 8.7875C18.0135 9.4875 18.401 10.375 18.401 11.475C18.401 15.3125 16.0635 16.1625 13.8385 16.4125C14.201 16.725 14.5135 17.325 14.5135 18.2625C14.5135 19.6 14.501 20.675 14.501 21.0125C14.501 21.275 14.6885 21.5875 15.1885 21.4875C19.259 20.1133 21.9999 16.2963 22.001 12C22.001 6.475 17.526 2 12.001 2Z" />
    </svg>
  )
}

function LinkedinBoxMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M18.3362 18.339H15.6707V14.1622C15.6707 13.1662 15.6505 11.8845 14.2817 11.8845C12.892 11.8845 12.6797 12.9683 12.6797 14.0887V18.339H10.0142V9.75H12.5747V10.9207H12.6092C12.967 10.2457 13.837 9.53325 15.1367 9.53325C17.8375 9.53325 18.337 11.3108 18.337 13.6245V18.339H18.3362ZM7.00373 8.57475C6.14573 8.57475 5.45648 7.88025 5.45648 7.026C5.45648 6.1725 6.14648 5.47875 7.00373 5.47875C7.85873 5.47875 8.55173 6.1725 8.55173 7.026C8.55173 7.88025 7.85798 8.57475 7.00373 8.57475ZM8.34023 18.339H5.66723V9.75H8.34023V18.339ZM19.6697 3H4.32923C3.59498 3 3.00098 3.5805 3.00098 4.29675V19.7033C3.00098 20.4202 3.59498 21 4.32923 21H19.6675C20.401 21 21.001 20.4202 21.001 19.7033V4.29675C21.001 3.5805 20.401 3 19.6675 3H19.6697Z" />
    </svg>
  )
}

function XOutlineMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M10.4883 14.651L15.25 21H22.25L14.3917 10.5223L20.9308 3H18.2808L13.1643 8.88578L8.75 3H1.75L9.26086 13.0145L2.31915 21H4.96917L10.4883 14.651ZM16.25 19L5.75 5H7.75L18.25 19H16.25Z" />
    </svg>
  )
}
```

### `registry/templates/saas-landing/components/header.tsx`

```tsx
"use client"

import { useState } from "react"
import { Button } from "@/components/ui/button"
import {
  Sheet,
  SheetClose,
  SheetContent,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

const navLinks = [
  { label: "Product", href: "#" },
  { label: "Solutions", href: "#" },
  { label: "Pricing", href: "#" },
  { label: "Resources", href: "#" },
]

export default function Header() {
  const [open, setOpen] = useState(false)

  return (
    <header className="sticky top-0 z-30 w-full border-b border-border bg-background/80 backdrop-blur">
      <div className="mx-auto flex h-16 w-full max-w-6xl items-center gap-6 px-6">
        <a href="#" className="flex shrink-0 items-center gap-2.5">
          <svg
            viewBox="0 0 24 24"
            fill="currentColor"
            aria-hidden="true"
            className="size-6 shrink-0 text-primary"
          >
            <rect x="3" y="3" width="8" height="8" transform="rotate(-6 7 7)" />
            <rect
              x="3"
              y="13"
              width="8"
              height="8"
              transform="rotate(5 7 17)"
            />
            <rect
              x="13"
              y="13"
              width="8"
              height="8"
              transform="rotate(-4 17 17)"
            />
            <rect
              x="13"
              y="3"
              width="8"
              height="8"
              transform="rotate(15 17 7)"
            />
          </svg>
          <span className="text-base font-bold tracking-tight">Acme</span>
        </a>

        <nav className="hidden items-center gap-7 md:flex">
          {navLinks.map((link) => (
            <a
              key={link.label}
              href={link.href}
              className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
            >
              {link.label}
            </a>
          ))}
        </nav>

        <div className="ml-auto hidden items-center gap-2 md:flex">
          <Button
            render={<a href="#" />}
            nativeButton={false}
            variant="ghost"
            className="text-muted-foreground hover:text-foreground"
          >
            Sign in
          </Button>
          <Button render={<a href="#" />} nativeButton={false}>
            Get Started
            <IconPlaceholder
              lucide="ArrowRight"
              tabler="IconArrowRight"
              hugeicons="ArrowRightIcon"
              phosphor="ArrowRight"
              remixicon="RiArrowRightLine"
              data-icon="inline-end"
              aria-hidden="true"
            />
          </Button>
        </div>

        <Sheet open={open} onOpenChange={setOpen}>
          <SheetTrigger
            render={
              <Button
                variant="outline"
                size="icon"
                aria-label="Open menu"
                className="ml-auto md:hidden"
              />
            }
          >
            <IconPlaceholder
              lucide="Menu"
              tabler="IconMenu"
              hugeicons="MenuIcon"
              phosphor="List"
              remixicon="RiMenuLine"
              aria-hidden="true"
            />
          </SheetTrigger>
          <SheetContent side="right" className="w-3/4 max-w-xs">
            <SheetHeader>
              <SheetTitle className="flex items-center gap-2.5">
                <svg
                  viewBox="0 0 24 24"
                  fill="currentColor"
                  aria-hidden="true"
                  className="size-5 shrink-0 text-primary"
                >
                  <rect
                    x="3"
                    y="3"
                    width="8"
                    height="8"
                    transform="rotate(-6 7 7)"
                  />
                  <rect
                    x="3"
                    y="13"
                    width="8"
                    height="8"
                    transform="rotate(5 7 17)"
                  />
                  <rect
                    x="13"
                    y="13"
                    width="8"
                    height="8"
                    transform="rotate(-4 17 17)"
                  />
                  <rect
                    x="13"
                    y="3"
                    width="8"
                    height="8"
                    transform="rotate(15 17 7)"
                  />
                </svg>
                Acme
              </SheetTitle>
            </SheetHeader>

            <nav className="flex flex-col px-4">
              {navLinks.map((link) => (
                <SheetClose
                  key={link.label}
                  nativeButton={false}
                  render={
                    <a
                      href={link.href}
                      className="border-b border-border py-3 text-sm font-medium text-muted-foreground transition-colors last:border-b-0 hover:text-foreground"
                    />
                  }
                >
                  {link.label}
                </SheetClose>
              ))}
            </nav>

            <SheetFooter>
              <SheetClose
                nativeButton={false}
                render={
                  <Button
                    render={<a href="#" />}
                    nativeButton={false}
                    variant="outline"
                    className="w-full"
                  />
                }
              >
                Sign in
              </SheetClose>
              <SheetClose
                nativeButton={false}
                render={
                  <Button
                    render={<a href="#" />}
                    nativeButton={false}
                    className="w-full"
                  />
                }
              >
                Get Started
                <IconPlaceholder
                  lucide="ArrowRight"
                  tabler="IconArrowRight"
                  hugeicons="ArrowRightIcon"
                  phosphor="ArrowRight"
                  remixicon="RiArrowRightLine"
                  data-icon="inline-end"
                  aria-hidden="true"
                />
              </SheetClose>
            </SheetFooter>
          </SheetContent>
        </Sheet>
      </div>
    </header>
  )
}
```

### `registry/templates/saas-landing/components/hero.tsx`

```tsx
"use client"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Separator } from "@/components/ui/separator"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

const TRUST_ITEMS = [
  "No credit card required",
  "14-day free trial",
  "Cancel anytime",
]

const SCREENSHOT_ROWS = [
  {
    label: "Revenue",
    value: "$48,290",
    change: "+12.4%",
  },
  {
    label: "Users",
    value: "3,841",
    change: "+8.1%",
  },
  {
    label: "Churn",
    value: "1.7%",
    change: "-0.3%",
  },
  {
    label: "Session",
    value: "4m 22s",
    change: "+0.9%",
  },
]

const BAR_HEIGHTS = [30, 55, 42, 70, 48, 80, 65, 90, 58, 75, 62, 88]

const TOP_CHANNELS = [
  { name: "Organic search", pct: 74, sessions: "2,841" },
  { name: "Direct", pct: 53, sessions: "2,032" },
  { name: "Referral", pct: 31, sessions: "1,190" },
]

export default function Hero() {
  return (
    <section className="flex w-full items-center justify-center px-6 py-16 sm:py-24">
      <div className="mx-auto grid w-full max-w-6xl grid-cols-1 gap-12 md:grid-cols-2 md:items-center md:gap-16">
        <div className="flex flex-col">
          <Badge variant="outline" className="w-fit">
            Version 2.0 Is Live
          </Badge>

          <h1 className="mt-6 font-heading text-4xl font-bold tracking-tight text-balance sm:text-5xl">
            The analytics platform
            <br className="hidden sm:block" /> built for scale.
          </h1>

          <p className="mt-5 text-lg text-muted-foreground">
            Acme gives your team real-time visibility into every metric that
            matters, from acquisition to retention, in a single, unified
            dashboard.
          </p>

          <div className="mt-8 flex flex-col gap-3 sm:flex-row sm:items-center">
            <Button
              render={<a href="#" />}
              nativeButton={false}
              className="w-full sm:w-auto"
            >
              Start for Free
              <IconPlaceholder
                lucide="ArrowRight"
                tabler="IconArrowRight"
                hugeicons="ArrowRightIcon"
                phosphor="ArrowRight"
                remixicon="RiArrowRightLine"
                data-icon="inline-end"
                aria-hidden="true"
              />
            </Button>
            <Dialog>
              <DialogTrigger
                render={<Button variant="ghost" className="w-full sm:w-auto" />}
              >
                <IconPlaceholder
                  lucide="PlayCircle"
                  tabler="IconPlayerPlay"
                  hugeicons="PlayCircleIcon"
                  phosphor="PlayCircle"
                  remixicon="RiPlayCircleLine"
                  data-icon="inline-start"
                  aria-hidden="true"
                />
                Watch Demo
              </DialogTrigger>
              <DialogContent className="sm:max-w-2xl">
                <DialogHeader>
                  <DialogTitle>Product demo</DialogTitle>
                  <DialogDescription>
                    A 2-minute tour of the Acme analytics dashboard.
                  </DialogDescription>
                </DialogHeader>
                <div className="relative flex aspect-video w-full items-center justify-center rounded-lg border border-border bg-muted">
                  <span
                    className="flex size-14 items-center justify-center rounded-full bg-background/80 ring-1 ring-border"
                    aria-hidden="true"
                  >
                    <IconPlaceholder
                      lucide="Play"
                      tabler="IconPlayerPlay"
                      hugeicons="PlayIcon"
                      phosphor="Play"
                      remixicon="RiPlayFill"
                      className="size-6 text-foreground"
                    />
                  </span>
                  <span className="sr-only">Demo video placeholder</span>
                </div>
              </DialogContent>
            </Dialog>
          </div>

          <Separator className="my-8" />

          <ul className="flex flex-col gap-2.5">
            {TRUST_ITEMS.map((item) => (
              <li
                key={item}
                className="flex items-center gap-2 text-sm text-muted-foreground"
              >
                <IconPlaceholder
                  lucide="Check"
                  tabler="IconCheck"
                  hugeicons="Tick02Icon"
                  phosphor="Check"
                  remixicon="RiCheckLine"
                  className="size-4 shrink-0 text-foreground"
                  aria-hidden="true"
                />
                {item}
              </li>
            ))}
          </ul>
        </div>

        <div className="relative">
          <div className="rounded-xl border border-border bg-card p-1">
            <div className="flex items-center gap-1.5 rounded-t-lg border-b border-border bg-muted px-3 py-2">
              <span className="size-2.5 border border-border bg-background" />
              <span className="size-2.5 border border-border bg-background" />
              <span className="size-2.5 border border-border bg-background" />
              <span className="ml-3 h-4 flex-1 rounded-md border border-border bg-background" />
            </div>

            <div className="flex flex-col rounded-b-lg bg-background p-4">
              <div className="grid grid-cols-2 gap-3">
                {SCREENSHOT_ROWS.map((row) => (
                  <div
                    key={row.label}
                    className="flex flex-col rounded-lg border border-border bg-card p-3"
                  >
                    <p className="text-xs text-muted-foreground">{row.label}</p>
                    <p className="mt-1 text-lg font-bold tabular-nums">
                      {row.value}
                    </p>
                    <p className="mt-0.5 text-xs whitespace-nowrap text-muted-foreground">
                      {row.change} vs last mo.
                    </p>
                  </div>
                ))}
              </div>

              <div className="mt-3 rounded-lg border border-border bg-card p-4">
                <div className="mb-3 flex items-center justify-between">
                  <p className="text-xs font-semibold">Revenue over time</p>
                  <Badge variant="secondary" className="text-xs">
                    Last 12 months
                  </Badge>
                </div>
                <div className="flex h-28 items-end gap-1">
                  {BAR_HEIGHTS.map((h, i) => (
                    <div
                      key={i}
                      className="flex-1 bg-foreground/15"
                      style={{ height: `${h}%` }}
                      aria-hidden="true"
                    />
                  ))}
                </div>
                <div className="mt-2 flex justify-between">
                  {["Jan", "Mar", "May", "Jul", "Sep", "Nov"].map((m) => (
                    <span key={m} className="text-xs text-muted-foreground">
                      {m}
                    </span>
                  ))}
                </div>
              </div>

              <div className="mt-3 rounded-lg border border-border bg-card">
                <div className="flex items-center justify-between border-b border-border px-4 py-2">
                  <p className="text-xs font-semibold">Top channels</p>
                </div>
                {TOP_CHANNELS.map((row) => (
                  <div
                    key={row.name}
                    className="flex items-center gap-3 border-b border-border px-4 py-2 last:border-0"
                  >
                    <span className="w-24 truncate text-xs">{row.name}</span>
                    <div className="flex-1 border border-border bg-muted">
                      <div
                        className="h-1.5 bg-foreground/40"
                        style={{ width: `${row.pct}%` }}
                        aria-hidden="true"
                      />
                    </div>
                    <span className="w-12 text-right text-xs text-muted-foreground tabular-nums">
                      {row.sessions}
                    </span>
                  </div>
                ))}
              </div>
            </div>
          </div>

          <div
            className="absolute -right-3 -bottom-3 -z-10 size-full rounded-xl border border-border bg-muted"
            aria-hidden="true"
          />
        </div>
      </div>
    </section>
  )
}
```

### `registry/templates/saas-landing/components/logo-cloud.tsx`

```tsx
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

type IconProps = { className?: string; size?: number | string }

const logos = [
  { name: "Slack", Icon: (p: IconProps) => <SlackMark {...p} /> },
  { name: "GitHub", Icon: (p: IconProps) => <GithubMark {...p} /> },
  { name: "Notion", Icon: (p: IconProps) => <NotionMark {...p} /> },
  { name: "Figma", Icon: (p: IconProps) => <FigmaMark {...p} /> },
  { name: "Vercel", Icon: (p: IconProps) => <VercelMark {...p} /> },
  {
    name: "Supabase",
    Icon: (p: IconProps) => (
      <IconPlaceholder
        lucide="Database"
        tabler="IconDatabase"
        hugeicons="DatabaseIcon"
        phosphor="Database"
        remixicon="RiSupabaseFill"
        {...p}
      />
    ),
  },
  { name: "Google", Icon: (p: IconProps) => <GoogleMark {...p} /> },
  { name: "Discord", Icon: (p: IconProps) => <DiscordMark {...p} /> },
  { name: "Dropbox", Icon: (p: IconProps) => <DropboxMark {...p} /> },
]

export default function LogoCloud() {
  return (
    <section className="flex w-full flex-col items-center px-6 py-14 sm:py-16">
      <style>{`
        @keyframes saaslanding-marquee {
          from { transform: translateX(0); }
          to { transform: translateX(-50%); }
        }
        .saaslanding-track {
          animation: saaslanding-marquee 32s linear infinite;
        }
        .saaslanding-mask:hover .saaslanding-track {
          animation-play-state: paused;
        }
        @media (prefers-reduced-motion: reduce) {
          .saaslanding-track {
            animation: none;
          }
        }
      `}</style>

      <div className="mx-auto w-full max-w-6xl text-center">
        <p className="text-xs font-semibold tracking-widest text-muted-foreground uppercase">
          Trusted by fast-moving teams at Acme
        </p>

        <div className="saaslanding-mask relative mt-10 overflow-hidden [mask-image:linear-gradient(to_right,transparent,black_12%,black_88%,transparent)]">
          <div className="saaslanding-track flex w-max items-center">
            {[...logos, ...logos].map(({ name, Icon }, index) => (
              <div
                key={`${name}-${index}`}
                className="flex shrink-0 items-center gap-2.5 px-8 text-muted-foreground transition-colors duration-200 hover:text-foreground"
                aria-hidden={index >= logos.length ? "true" : undefined}
              >
                <Icon className="h-6 w-6" aria-hidden="true" />
                <span className="text-lg font-semibold tracking-tight whitespace-nowrap">
                  {name}
                </span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  )
}

type MarkProps = React.ComponentProps<"svg"> & { size?: number | string }

function DiscordMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M19.3034 5.33716C17.9344 4.71103 16.4805 4.2547 14.9629 4C14.7719 4.32899 14.5596 4.77471 14.411 5.12492C12.7969 4.89144 11.1944 4.89144 9.60255 5.12492C9.45397 4.77471 9.2311 4.32899 9.05068 4C7.52251 4.2547 6.06861 4.71103 4.70915 5.33716C1.96053 9.39111 1.21766 13.3495 1.5891 17.2549C3.41443 18.5815 5.17612 19.388 6.90701 19.9187C7.33151 19.3456 7.71356 18.73 8.04255 18.0827C7.41641 17.8492 6.82211 17.5627 6.24904 17.2231C6.39762 17.117 6.5462 17.0003 6.68416 16.8835C10.1438 18.4648 13.8911 18.4648 17.3082 16.8835C17.4568 17.0003 17.5948 17.117 17.7434 17.2231C17.1703 17.5627 16.576 17.8492 15.9499 18.0827C16.2789 18.73 16.6609 19.3456 17.0854 19.9187C18.8152 19.388 20.5875 18.5815 22.4033 17.2549C22.8596 12.7341 21.6806 8.80747 19.3034 5.33716ZM8.5201 14.8459C7.48007 14.8459 6.63107 13.9014 6.63107 12.7447C6.63107 11.5879 7.45884 10.6434 8.5201 10.6434C9.57071 10.6434 10.4303 11.5879 10.4091 12.7447C10.4091 13.9014 9.57071 14.8459 8.5201 14.8459ZM15.4936 14.8459C14.4535 14.8459 13.6034 13.9014 13.6034 12.7447C13.6034 11.5879 14.4323 10.6434 15.4936 10.6434C16.5442 10.6434 17.4038 11.5879 17.3825 12.7447C17.3825 13.9014 16.5548 14.8459 15.4936 14.8459Z" />
    </svg>
  )
}

function DropboxMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M17.2847 10.6683L22.5 13.9909L17.248 17.3368L12 13.9934L6.75198 17.3368L1.5 13.9909L6.7152 10.6684L1.5 7.34587L6.75206 4L11.9999 7.34335L17.2481 4L22.5 7.34587L17.2847 10.6683ZM17.2112 10.6684L11.9999 7.3484L6.78869 10.6683L12 13.9883L17.2112 10.6684ZM6.78574 18.4456L12.0377 15.1L17.2898 18.4456L12.0377 21.7916L6.78574 18.4456Z" />
    </svg>
  )
}

function FigmaMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M5.33317 5.33333C5.33317 3.49238 6.82556 2 8.6665 2H11.9997H11.9998H15.333C17.174 2 18.6663 3.49238 18.6663 5.33333C18.6663 7.17428 17.174 8.66667 15.333 8.66667H11.9998H11.9997L11.9997 12L11.9997 15.3333V18.6667C11.9997 20.5076 10.5073 22 8.66634 22C6.82539 22 5.33301 20.5076 5.33301 18.6667C5.33301 16.8257 6.82539 15.3333 8.66634 15.3333C6.82539 15.3333 5.33301 13.841 5.33301 12C5.33301 10.1591 6.82539 8.66667 8.66634 8.66667H8.6665C6.82555 8.66667 5.33317 7.17428 5.33317 5.33333ZM11.9997 12C11.9997 13.841 13.4921 15.3333 15.333 15.3333C17.174 15.3333 18.6663 13.841 18.6663 12C18.6663 10.1591 17.174 8.66667 15.333 8.66667C13.4921 8.66667 11.9997 10.1591 11.9997 12Z" />
    </svg>
  )
}

function GithubMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M12.001 2C6.47598 2 2.00098 6.475 2.00098 12C2.00098 16.425 4.86348 20.1625 8.83848 21.4875C9.33848 21.575 9.52598 21.275 9.52598 21.0125C9.52598 20.775 9.51348 19.9875 9.51348 19.15C7.00098 19.6125 6.35098 18.5375 6.15098 17.975C6.03848 17.6875 5.55098 16.8 5.12598 16.5625C4.77598 16.375 4.27598 15.9125 5.11348 15.9C5.90098 15.8875 6.46348 16.625 6.65098 16.925C7.55098 18.4375 8.98848 18.0125 9.56348 17.75C9.65098 17.1 9.91348 16.6625 10.201 16.4125C7.97598 16.1625 5.65098 15.3 5.65098 11.475C5.65098 10.3875 6.03848 9.4875 6.67598 8.7875C6.57598 8.5375 6.22598 7.5125 6.77598 6.1375C6.77598 6.1375 7.61348 5.875 9.52598 7.1625C10.326 6.9375 11.176 6.825 12.026 6.825C12.876 6.825 13.726 6.9375 14.526 7.1625C16.4385 5.8625 17.276 6.1375 17.276 6.1375C17.826 7.5125 17.476 8.5375 17.376 8.7875C18.0135 9.4875 18.401 10.375 18.401 11.475C18.401 15.3125 16.0635 16.1625 13.8385 16.4125C14.201 16.725 14.5135 17.325 14.5135 18.2625C14.5135 19.6 14.501 20.675 14.501 21.0125C14.501 21.275 14.6885 21.5875 15.1885 21.4875C19.259 20.1133 21.9999 16.2963 22.001 12C22.001 6.475 17.526 2 12.001 2Z" />
    </svg>
  )
}

function GoogleMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M3.06364 7.50914C4.70909 4.24092 8.09084 2 12 2C14.6954 2 16.959 2.99095 18.6909 4.60455L15.8227 7.47274C14.7864 6.48185 13.4681 5.97727 12 5.97727C9.39542 5.97727 7.19084 7.73637 6.40455 10.1C6.2045 10.7 6.09086 11.3409 6.09086 12C6.09086 12.6591 6.2045 13.3 6.40455 13.9C7.19084 16.2636 9.39542 18.0227 12 18.0227C13.3454 18.0227 14.4909 17.6682 15.3864 17.0682C16.4454 16.3591 17.15 15.3 17.3818 14.05H12V10.1818H21.4181C21.5364 10.8363 21.6 11.5182 21.6 12.2273C21.6 15.2727 20.5091 17.8363 18.6181 19.5773C16.9636 21.1046 14.7 22 12 22C8.09084 22 4.70909 19.7591 3.06364 16.4909C2.38638 15.1409 2 13.6136 2 12C2 10.3864 2.38638 8.85911 3.06364 7.50914Z" />
    </svg>
  )
}

function NotionMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M6.1039 5.90972C6.68754 6.38386 6.90648 6.34768 8.00238 6.27457L18.3342 5.65418C18.5533 5.65418 18.3711 5.43557 18.2981 5.39924L16.5822 4.15879C16.2534 3.90354 15.8153 3.61122 14.9758 3.68434L4.9715 4.41403C4.60665 4.45021 4.53377 4.63262 4.67909 4.77886L6.1039 5.90972ZM6.72422 8.31752L6.72422 19.1884C6.72422 19.7726 7.01618 19.9912 7.6733 19.955L19.028 19.298C19.6854 19.2619 19.7586 18.86 19.7586 18.3854V7.58753C19.7586 7.1137 19.5764 6.85816 19.1739 6.89464L7.30815 7.58753C6.87027 7.62433 6.72422 7.84337 6.72422 8.31752ZM17.9335 8.90066C18.0063 9.22933 17.9335 9.55767 17.6043 9.5946L17.0571 9.70361V17.7292C16.5822 17.9845 16.1441 18.1304 15.7791 18.1304C15.1947 18.1304 15.0484 17.9479 14.6107 17.401L11.0321 11.783V17.2186L12.1645 17.4741C12.1645 17.4741 12.1645 18.1304 11.2509 18.1304L8.73222 18.2765C8.65905 18.1304 8.73222 17.7659 8.98769 17.6929L9.64494 17.5108V10.324L8.73237 10.2509C8.6592 9.92222 8.84146 9.44837 9.35298 9.41159L12.0549 9.22946L15.7791 14.9205V9.88603L14.8296 9.77704C14.7567 9.37526 15.0484 9.08353 15.4135 9.04735L17.9335 8.90066ZM4.13151 3.4291L14.5376 2.66279C15.8155 2.55318 16.1443 2.6266 16.9475 3.21005L20.2692 5.54473C20.8173 5.9462 21 6.05551 21 6.49316V19.298C21 20.1005 20.7077 20.5751 19.6856 20.6477L7.60101 21.3775C6.83376 21.4141 6.4686 21.3047 6.0668 20.7937L3.6206 17.6199C3.18227 17.0357 3 16.5986 3 16.0873L3 4.70545C3 4.04918 3.29242 3.50177 4.13151 3.4291Z" />
    </svg>
  )
}

function SlackMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M6.52739 14.5136C6.52739 15.5966 5.64264 16.4814 4.55959 16.4814C3.47654 16.4814 2.5918 15.5966 2.5918 14.5136C2.5918 13.4305 3.47654 12.5458 4.55959 12.5458H6.52739V14.5136ZM7.51892 14.5136C7.51892 13.4305 8.40366 12.5458 9.48671 12.5458C10.5698 12.5458 11.4545 13.4305 11.4545 14.5136V19.4407C11.4545 20.5238 10.5698 21.4085 9.48671 21.4085C8.40366 21.4085 7.51892 20.5238 7.51892 19.4407V14.5136ZM9.48671 6.52715C8.40366 6.52715 7.51892 5.6424 7.51892 4.55935C7.51892 3.4763 8.40366 2.59155 9.48671 2.59155C10.5698 2.59155 11.4545 3.4763 11.4545 4.55935V6.52715H9.48671ZM9.48671 7.51867C10.5698 7.51867 11.4545 8.40342 11.4545 9.48647C11.4545 10.5695 10.5698 11.4543 9.48671 11.4543H4.55959C3.47654 11.4543 2.5918 10.5695 2.5918 9.48647C2.5918 8.40342 3.47654 7.51867 4.55959 7.51867H9.48671ZM17.4732 9.48647C17.4732 8.40342 18.3579 7.51867 19.4409 7.51867C20.524 7.51867 21.4087 8.40342 21.4087 9.48647C21.4087 10.5695 20.524 11.4543 19.4409 11.4543H17.4732V9.48647ZM16.4816 9.48647C16.4816 10.5695 15.5969 11.4543 14.5138 11.4543C13.4308 11.4543 12.546 10.5695 12.546 9.48647V4.55935C12.546 3.4763 13.4308 2.59155 14.5138 2.59155C15.5969 2.59155 16.4816 3.4763 16.4816 4.55935V9.48647ZM14.5138 17.4729C15.5969 17.4729 16.4816 18.3577 16.4816 19.4407C16.4816 20.5238 15.5969 21.4085 14.5138 21.4085C13.4308 21.4085 12.546 20.5238 12.546 19.4407V17.4729H14.5138ZM14.5138 16.4814C13.4308 16.4814 12.546 15.5966 12.546 14.5136C12.546 13.4305 13.4308 12.5458 14.5138 12.5458H19.4409C20.524 12.5458 21.4087 13.4305 21.4087 14.5136C21.4087 15.5966 20.524 16.4814 19.4409 16.4814H14.5138Z" />
    </svg>
  )
}

function VercelMark({ size = 24, ...props }: MarkProps) {
  return (
    <svg
      viewBox="0 0 24 24"
      width={size}
      height={size}
      fill="currentColor"
      aria-hidden="true"
      {...props}
    >
      <path d="M23 21.6479H1L12 2.35205L23 21.6479Z" />
    </svg>
  )
}
```

### `registry/templates/saas-landing/components/pricing.tsx`

```tsx
"use client"

import { useState } from "react"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import { cn } from "@/lib/utils"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

const tiers = [
  {
    name: "Starter",
    monthly: 0,
    annual: 0,
    description: "For side projects and getting started.",
    features: ["Up to 3 projects", "Community support", "1 GB storage"],
    cta: "Get Started",
    featured: false,
  },
  {
    name: "Pro",
    monthly: 29,
    annual: 24,
    description: "For growing teams that ship every day.",
    features: [
      "Unlimited projects",
      "Priority support",
      "50 GB storage",
      "Advanced analytics",
    ],
    cta: "Start Free Trial",
    featured: true,
  },
  {
    name: "Enterprise",
    monthly: 99,
    annual: 82,
    description: "For organizations with advanced needs.",
    features: [
      "Everything in Pro",
      "Dedicated support",
      "Unlimited storage",
      "SSO and audit logs",
    ],
    cta: "Contact Sales",
    featured: false,
  },
]

export default function Pricing() {
  const [annual, setAnnual] = useState(false)

  return (
    <section className="flex w-full items-center justify-center px-6 py-16 sm:py-24">
      <div className="mx-auto w-full max-w-6xl">
        <div className="mx-auto max-w-2xl text-center">
          <Badge variant="outline" className="mb-4 tracking-widest uppercase">
            Acme Plans
          </Badge>
          <h2 className="font-heading text-3xl font-bold tracking-tight text-balance sm:text-4xl">
            Pricing that scales with you
          </h2>
          <p className="mt-4 text-muted-foreground">
            Start for free, then upgrade when you&apos;re ready to grow. Save up
            to 17% with annual billing.
          </p>
        </div>

        <div className="mt-8 flex justify-center">
          <div
            role="group"
            aria-label="Billing period"
            className="inline-flex items-center gap-1 rounded-lg border border-border bg-muted/50 p-1"
          >
            <button
              type="button"
              onClick={() => setAnnual(false)}
              aria-pressed={!annual}
              className={cn(
                "px-4 py-1.5 text-sm font-medium transition-colors",
                !annual
                  ? "bg-background text-foreground shadow-sm"
                  : "text-muted-foreground hover:text-foreground"
              )}
            >
              Monthly
            </button>
            <button
              type="button"
              onClick={() => setAnnual(true)}
              aria-pressed={annual}
              className={cn(
                "flex items-center gap-2 px-4 py-1.5 text-sm font-medium transition-colors",
                annual
                  ? "bg-background text-foreground shadow-sm"
                  : "text-muted-foreground hover:text-foreground"
              )}
            >
              Annual
              <Badge className="px-1.5 text-[10px] font-semibold">-17%</Badge>
            </button>
          </div>
        </div>

        <div className="mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3">
          {tiers.map((tier) => {
            const price = annual ? tier.annual : tier.monthly
            return (
              <Card
                key={tier.name}
                className={cn(
                  "flex flex-col",
                  tier.featured && "bg-muted/30 ring-2 ring-primary"
                )}
              >
                <CardHeader>
                  <CardTitle className="text-base font-semibold">
                    {tier.name}
                  </CardTitle>
                  {tier.featured && (
                    <CardAction>
                      <Badge className="gap-1.5">
                        <IconPlaceholder
                          lucide="Sparkles"
                          tabler="IconSparkles"
                          hugeicons="SparklesIcon"
                          phosphor="Sparkle"
                          remixicon="RiSparklingFill"
                          data-icon="inline-start"
                          className="size-3.5"
                          aria-hidden="true"
                        />
                        Most popular
                      </Badge>
                    </CardAction>
                  )}
                  <CardDescription className="text-sm sm:min-h-10">
                    {tier.description}
                  </CardDescription>
                </CardHeader>
                <CardContent className="flex flex-1 flex-col gap-6">
                  <div>
                    <p className="flex items-baseline gap-1">
                      <span className="text-4xl font-bold tracking-tight text-foreground tabular-nums">
                        ${price}
                      </span>
                      <span className="text-sm text-muted-foreground">
                        /Month
                      </span>
                    </p>
                    <p className="mt-1 h-5 text-xs text-muted-foreground">
                      {annual && price > 0
                        ? `$${price * 12} billed yearly`
                        : " "}
                    </p>
                  </div>
                  <ul className="flex flex-1 flex-col gap-3 text-sm text-foreground">
                    {tier.features.map((feature) => (
                      <li key={feature} className="flex items-center gap-2">
                        <IconPlaceholder
                          lucide="Check"
                          tabler="IconCheck"
                          hugeicons="Tick02Icon"
                          phosphor="Check"
                          remixicon="RiCheckLine"
                          className="size-4 shrink-0 text-primary"
                          aria-hidden="true"
                        />
                        {feature}
                      </li>
                    ))}
                  </ul>
                </CardContent>
                <CardFooter>
                  <Button
                    nativeButton={false}
                    variant={tier.featured ? "default" : "outline"}
                    size="lg"
                    className="w-full"
                    render={<a href="#" />}
                  >
                    {tier.cta}
                  </Button>
                </CardFooter>
              </Card>
            )
          })}
        </div>
      </div>
    </section>
  )
}
```

### `registry/templates/saas-landing/components/stats.tsx`

```tsx
"use client"

import { useEffect, useRef, useState } from "react"
import { Badge } from "@/components/ui/badge"
import { cn } from "@/lib/utils"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

type IconProps = { className?: string; size?: number | string }

type IconRenderer = (props: IconProps) => React.ReactNode

type Metric = {
  id: string
  icon: IconRenderer
  target: number
  decimals: number
  prefix: string
  suffix: string
  label: string
  delta: string
}

const metrics: Metric[] = [
  {
    id: "uptime",
    icon: (p: IconProps) => (
      <IconPlaceholder
        lucide="Globe"
        tabler="IconGlobe"
        hugeicons="GlobalIcon"
        phosphor="Globe"
        remixicon="RiGlobalLine"
        {...p}
      />
    ),
    target: 99.9,
    decimals: 1,
    prefix: "",
    suffix: "%",
    label: "Service uptime",
    delta: "+0.4%",
  },
  {
    id: "users",
    icon: (p: IconProps) => (
      <IconPlaceholder
        lucide="Users"
        tabler="IconUsersGroup"
        hugeicons="UserGroupIcon"
        phosphor="UsersThree"
        remixicon="RiTeamLine"
        {...p}
      />
    ),
    target: 12,
    decimals: 0,
    prefix: "",
    suffix: "k+",
    label: "Active teams",
    delta: "+18%",
  },
  {
    id: "rating",
    icon: (p: IconProps) => (
      <IconPlaceholder
        lucide="Star"
        tabler="IconStar"
        hugeicons="StarIcon"
        phosphor="Star"
        remixicon="RiStarSmileLine"
        {...p}
      />
    ),
    target: 4.9,
    decimals: 1,
    prefix: "",
    suffix: "/5",
    label: "Average rating",
    delta: "+0.2",
  },
  {
    id: "integrations",
    icon: (p: IconProps) => (
      <IconPlaceholder
        lucide="Clock"
        tabler="IconClock"
        hugeicons="TimeIcon"
        phosphor="Clock"
        remixicon="RiTimeLine"
        {...p}
      />
    ),
    target: 250,
    decimals: 0,
    prefix: "",
    suffix: "+",
    label: "Integrations shipped",
    delta: "+32",
  },
]

function formatValue(value: number, metric: Metric) {
  const fixed = value.toFixed(metric.decimals)
  return `${metric.prefix}${fixed}${metric.suffix}`
}

export default function Stats() {
  const sectionRef = useRef<HTMLElement | null>(null)
  const [progress, setProgress] = useState(1)

  useEffect(() => {
    const node = sectionRef.current
    if (!node) return

    const prefersReduced = window.matchMedia(
      "(prefers-reduced-motion: reduce)"
    ).matches
    if (prefersReduced) return

    let frame = 0
    let started = false

    const animate = (start: number) => {
      const duration = 1600

      const step = (now: number) => {
        const elapsed = now - start
        const linear = Math.min(elapsed / duration, 1)
        const eased = 1 - Math.pow(1 - linear, 3)
        setProgress(eased)
        if (linear < 1) {
          frame = requestAnimationFrame(step)
        }
      }

      frame = requestAnimationFrame(step)
    }

    const box = node.getBoundingClientRect()
    const alreadyVisible = box.top < window.innerHeight && box.bottom > 0
    if (alreadyVisible) return

    setProgress(0)

    const observer = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting && !started) {
            started = true
            animate(performance.now())
            observer.disconnect()
          }
        }
      },
      { threshold: 0.35 }
    )

    observer.observe(node)

    return () => {
      observer.disconnect()
      if (frame) cancelAnimationFrame(frame)
    }
  }, [])

  return (
    <section
      ref={sectionRef}
      className="flex w-full items-center justify-center px-6 py-16 sm:py-24"
    >
      <div className="mx-auto w-full max-w-6xl">
        <div className="mx-auto max-w-2xl text-center">
          <Badge variant="outline" className="mb-4 tracking-widest uppercase">
            By The Numbers
          </Badge>
          <h2 className="font-heading text-3xl font-bold tracking-tight text-balance sm:text-4xl">
            Numbers teams at Acme trust
          </h2>
          <p className="mt-4 text-base text-balance text-muted-foreground">
            Real performance from a platform built to scale with you, measured
            and reported every single quarter.
          </p>
        </div>

        <ul className="mt-12 grid grid-cols-1 gap-px overflow-hidden rounded-lg border border-border bg-border sm:grid-cols-2 md:grid-cols-4">
          {metrics.map((metric) => {
            const Icon = metric.icon
            const current = metric.target * progress
            return (
              <li
                key={metric.id}
                className="group flex flex-col gap-4 bg-card p-6 transition-colors hover:bg-card/60 sm:p-8"
              >
                <div className="flex items-center justify-between">
                  <span className="flex size-10 items-center justify-center rounded-md bg-muted text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary">
                    <Icon className="size-5" aria-hidden="true" />
                  </span>
                  <Badge
                    variant="outline"
                    className="border-transparent bg-primary/10 text-primary"
                  >
                    <IconPlaceholder
                      lucide="ArrowUp"
                      tabler="IconArrowUp"
                      hugeicons="ArrowUpIcon"
                      phosphor="ArrowUp"
                      remixicon="RiArrowUpLine"
                      data-icon="inline-start"
                    />
                    {metric.delta}
                  </Badge>
                </div>
                <div className="mt-auto">
                  <p
                    className={cn(
                      "text-4xl font-semibold tracking-tight tabular-nums sm:text-5xl"
                    )}
                  >
                    {formatValue(current, metric)}
                  </p>
                  <p className="mt-2 text-sm text-muted-foreground">
                    {metric.label}
                  </p>
                </div>
              </li>
            )
          })}
        </ul>
      </div>
    </section>
  )
}
```

### `registry/templates/saas-landing/components/testimonials.tsx`

```tsx
import { Badge } from "@/components/ui/badge"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Card } from "@/components/ui/card"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

const testimonials = [
  {
    quote:
      "We shipped a polished marketing site in a single afternoon. The blocks dropped in cleanly and looked right in both light and dark themes, exactly what our team needed without a single tweak.",
    name: "Maya Chen",
    role: "Founder",
    company: "Northwind",
    avatar: "https://i.pravatar.cc/150?img=47",
    rating: 5,
  },
  {
    quote:
      "Accessible, sharp, and zero config. Our engineers stopped reinventing layouts and started shipping features again within days of adopting Acme. Onboarding went from weeks to a single morning.",
    name: "Priya Nair",
    role: "Engineering Manager",
    company: "Vela",
    avatar: "https://i.pravatar.cc/150?img=32",
    rating: 5,
  },
  {
    quote:
      "Adopting Acme cut our component backlog in half by the end of the first sprint.",
    name: "Tomás Herrera",
    role: "Frontend Lead",
    company: "Cobalt",
    avatar: "https://i.pravatar.cc/150?img=13",
    rating: 4,
  },
  {
    quote:
      "I expected to fight the defaults. Instead everything just composed: spacing, typography, focus states. It feels like it was designed by someone who actually ships product.",
    name: "Sofia Lindqvist",
    role: "Product Designer",
    company: "Fernweh",
    avatar: "https://i.pravatar.cc/150?img=45",
    rating: 5,
  },
  {
    quote:
      "Our agency standardized on Acme across six client projects. Handoffs are clean and reviews are faster.",
    name: "Marcus Bell",
    role: "Creative Director",
    company: "Studio Atlas",
    avatar: "https://i.pravatar.cc/150?img=8",
    rating: 5,
  },
  {
    quote:
      "The dark mode story alone paid for itself. No more one-off overrides scattered through the codebase, and our QA pass on theming dropped to almost nothing.",
    name: "Aisha Rahman",
    role: "Staff Engineer",
    company: "Quanta",
    avatar: "https://i.pravatar.cc/150?img=26",
    rating: 5,
  },
]

function getInitials(name: string) {
  return name
    .split(" ")
    .map((part) => part[0])
    .join("")
}

export default function Testimonials() {
  return (
    <section className="flex w-full items-center justify-center px-6 py-16 sm:py-24">
      <div className="mx-auto w-full max-w-6xl">
        <div className="mx-auto max-w-xl text-center">
          <Badge variant="outline" className="mb-4 tracking-widest uppercase">
            Wall Of Love
          </Badge>
          <h2 className="font-heading text-3xl font-bold tracking-tight text-balance sm:text-4xl">
            Teams ship faster with Acme
          </h2>
          <p className="mt-4 text-base text-muted-foreground">
            Thousands of engineers, designers, and founders build their products
            on Acme. Here is what a few of them have to say.
          </p>
        </div>

        <div className="mt-14 grid grid-cols-1 gap-5 sm:grid-cols-2 md:grid-cols-3">
          {testimonials.map(
            ({ quote, name, role, company, avatar, rating }) => (
              <Card
                key={name}
                className="flex h-full flex-col border-border bg-card p-6 transition-colors duration-200 hover:border-foreground/20"
              >
                <div className="flex flex-1 flex-col gap-4">
                  <div className="flex items-center justify-between">
                    <IconPlaceholder
                      lucide="Quote"
                      tabler="IconQuotes"
                      hugeicons="QuotesIcon"
                      phosphor="Quotes"
                      remixicon="RiDoubleQuotesL"
                      className="size-7 text-foreground opacity-20"
                      aria-hidden="true"
                    />
                    <div
                      role="img"
                      className="flex items-center gap-0.5"
                      aria-label={`${rating} out of 5 stars`}
                    >
                      {Array.from({ length: 5 }).map((_, i) => (
                        <IconPlaceholder
                          lucide="Star"
                          tabler="IconStar"
                          hugeicons="StarIcon"
                          phosphor="Star"
                          remixicon="RiStarFill"
                          key={i}
                          className={
                            i < rating
                              ? "size-4 text-primary"
                              : "size-4 text-muted-foreground/30"
                          }
                          aria-hidden="true"
                        />
                      ))}
                    </div>
                  </div>
                  <blockquote className="flex-1 text-[15px] leading-relaxed text-foreground">
                    &ldquo;{quote}&rdquo;
                  </blockquote>
                </div>

                <div className="mt-6 flex items-center gap-3">
                  <Avatar className="size-10 border border-border">
                    <AvatarImage
                      src={avatar}
                      alt={name}
                      className="grayscale"
                    />
                    <AvatarFallback className="text-xs font-semibold">
                      {getInitials(name)}
                    </AvatarFallback>
                  </Avatar>
                  <span className="flex flex-col gap-0.5">
                    <span className="text-sm font-semibold text-foreground">
                      {name}
                    </span>
                    <span className="text-xs text-muted-foreground">
                      {role},{" "}
                      <span className="font-medium text-foreground">
                        {company}
                      </span>
                    </span>
                  </span>
                </div>
              </Card>
            )
          )}
        </div>
      </div>
    </section>
  )
}
```
