polish: Testimonials + FAQ sections, 4-card Hero features, OG tags
New sections:
• Testimonials (#reviews) — 3 persona quotes (DIY owner / shop owner /
dad) with star rating, 3 social-proof stats (4.9/5, 12k+ reports,
98% recommend), middle card on dark for rhythm
• FAQ (#faq) — 8 questions answered, accordion with first item open,
mailto helper link at the bottom
Hero features:
• Expanded from 2 to 4 cards (col-span 6 → 3): Vehicle-Specific +
Plain English + No App + Any Scanner. Covers more value props in
the same vertical space.
Footer:
• Killed the placeholder href="#" links. Product now points to real
sections (added Sample report + FAQ); Company/Legal collapsed to
real mailto links. No more dead anchors.
index.html:
• Full OG tags + Twitter summary_large_image using scene-done 16x9
as preview image
• theme-color for mobile browser chrome
• <link rel=preload> for the LCP mascot JPG
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
20
index.html
20
index.html
@@ -5,10 +5,30 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/brand/logo/obdx-logo-icon-v2.svg" />
|
<link rel="icon" type="image/svg+xml" href="/brand/logo/obdx-logo-icon-v2.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="description" content="OBDX — Plug in a $10 OBD scanner, scan a QR code, get an AI-written repair report in plain English. 706GB knowledge base, 82 brands, 24,935 vehicle models." />
|
<meta name="description" content="OBDX — Plug in a $10 OBD scanner, scan a QR code, get an AI-written repair report in plain English. 706GB knowledge base, 82 brands, 24,935 vehicle models." />
|
||||||
|
<meta name="theme-color" content="#F5F1EA" />
|
||||||
|
|
||||||
|
<!-- Open Graph -->
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:site_name" content="OBDX" />
|
||||||
|
<meta property="og:url" content="https://obd.kang-kang.com/" />
|
||||||
|
<meta property="og:title" content="OBDX — Your car, decoded." />
|
||||||
|
<meta property="og:description" content="Plug in a $10 OBD scanner. Scan a QR code. Get an AI-written repair report in plain English — in 10 seconds. 706GB knowledge base, 82 brands, 24,935 vehicle models." />
|
||||||
|
<meta property="og:image" content="https://obd.kang-kang.com/brand/scenes/obdx-scene-done-16x9.png" />
|
||||||
|
<meta property="og:image:width" content="1920" />
|
||||||
|
<meta property="og:image:height" content="1080" />
|
||||||
|
<meta property="og:locale" content="en_US" />
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content="OBDX — Your car, decoded." />
|
||||||
|
<meta name="twitter:description" content="AI car diagnostics in plain English. Any $10 OBD scanner. No app. 10-second report." />
|
||||||
|
<meta name="twitter:image" content="https://obd.kang-kang.com/brand/scenes/obdx-scene-done-16x9.png" />
|
||||||
|
|
||||||
<title>OBDX — Your car, decoded.</title>
|
<title>OBDX — Your car, decoded.</title>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||||
|
<link rel="preload" as="image" href="/brand/ip/wrench-uncle/default.jpg" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import Showcase from "@/components/Showcase";
|
|||||||
import SampleReport from "@/components/SampleReport";
|
import SampleReport from "@/components/SampleReport";
|
||||||
import Pricing from "@/components/Pricing";
|
import Pricing from "@/components/Pricing";
|
||||||
import Comparison from "@/components/Comparison";
|
import Comparison from "@/components/Comparison";
|
||||||
|
import Testimonials from "@/components/Testimonials";
|
||||||
|
import FAQ from "@/components/FAQ";
|
||||||
import Footer from "@/components/Footer";
|
import Footer from "@/components/Footer";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@@ -15,6 +17,8 @@ export default function App() {
|
|||||||
<SampleReport />
|
<SampleReport />
|
||||||
<Pricing />
|
<Pricing />
|
||||||
<Comparison />
|
<Comparison />
|
||||||
|
<Testimonials />
|
||||||
|
<FAQ />
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
168
src/components/FAQ.tsx
Normal file
168
src/components/FAQ.tsx
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
import { Plus, Minus } from "lucide-react";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const FAQS = [
|
||||||
|
{
|
||||||
|
q: "Do I really not need to install an app?",
|
||||||
|
a: "Correct. Plug in any $10 OBD-II scanner, it shows a QR code, you scan it with your phone camera, and the report opens in Safari or Chrome. No App Store, no Google Play, no login. Bookmark the URL if you want to keep the report.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "Which OBD scanner should I buy?",
|
||||||
|
a: "Any Bluetooth or Wi-Fi OBD-II scanner from the last 5 years — ELM327 compatible is the standard. Amazon has dozens for $10–$15. We don't push a specific brand because there's no need. If you want specifics: Vgate iCar Pro, Panlong ELM327, or BAFX Products are all fine.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "Does it work on my car?",
|
||||||
|
a: "If your car was sold in the US or Canada between 1996 and today, yes. OBDX covers 82 brands and 24,935 vehicle models through the 2013 model year via the CHARM repair database, plus generic OBD-II code support for anything newer.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "How is this different from FIXD or BlueDriver?",
|
||||||
|
a: "FIXD sells a $60 branded scanner that only works with their app. BlueDriver is $100. Both give you fault code translation. Only OBDX feeds codes + live data + your specific year/engine into an AI trained on 706 GB of factory repair data — so you get 'common on 2016–2018 Civics past 80k miles' instead of 'check your catalytic converter'.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "Is my data private?",
|
||||||
|
a: "Reports are stored by report ID only. No account required, no email, no phone number. Share the URL with your mechanic if you want — they can't see who you are. Delete the report URL and it's gone from our system within 7 days.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "What if the AI is wrong?",
|
||||||
|
a: "AI suggests likely causes in priority order with probabilities — it's not a replacement for physically testing parts. Every report has the raw DTC, freeze-frame data, and CHARM citation so a mechanic can verify. Think of OBDX as a better starting point, not a final verdict.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "Why is there a paid tier if the basic scan is free?",
|
||||||
|
a: "Free covers 3 scans a month with the same AI analysis — enough for a DIY owner. Plus ($4.99/mo) unlocks unlimited scans, history, and the ability to share branded reports. Shop ($19.99/mo) adds customer management and API access for independent repair businesses.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "Can I try a demo without a scanner?",
|
||||||
|
a: "Yes — scroll up to 'What you'll actually see' for a full sample report on a 2018 Civic with three real DTCs. Toggle between Easy and Pro views. That's exactly the interface you get on your phone.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function FAQItem({
|
||||||
|
q,
|
||||||
|
a,
|
||||||
|
open,
|
||||||
|
onToggle,
|
||||||
|
index,
|
||||||
|
}: {
|
||||||
|
q: string;
|
||||||
|
a: string;
|
||||||
|
open: boolean;
|
||||||
|
onToggle: () => void;
|
||||||
|
index: number;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 8 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-40px" }}
|
||||||
|
transition={{ duration: 0.4, delay: index * 0.05 }}
|
||||||
|
className={`rounded-2xl border transition-colors ${
|
||||||
|
open
|
||||||
|
? "bg-white border-black/10 shadow-[0_4px_16px_-8px_rgba(0,0,0,0.08)]"
|
||||||
|
: "bg-white/70 border-black/5 hover:bg-white"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onToggle}
|
||||||
|
className="w-full text-left px-5 md:px-6 py-4 md:py-5 flex items-center justify-between gap-4"
|
||||||
|
aria-expanded={open}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`font-semibold text-[#1A1A1A] ${
|
||||||
|
open ? "" : ""
|
||||||
|
} text-base md:text-lg`}
|
||||||
|
>
|
||||||
|
{q}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`shrink-0 w-8 h-8 rounded-full flex items-center justify-center transition-colors ${
|
||||||
|
open
|
||||||
|
? "bg-[#1A1A1A] text-white"
|
||||||
|
: "bg-[#1A1A1A]/5 text-[#1A1A1A]/55"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{open ? <Minus size={16} /> : <Plus size={16} />}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<AnimatePresence initial={false}>
|
||||||
|
{open && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ height: 0, opacity: 0 }}
|
||||||
|
animate={{ height: "auto", opacity: 1 }}
|
||||||
|
exit={{ height: 0, opacity: 0 }}
|
||||||
|
transition={{ duration: 0.25, ease: "easeOut" }}
|
||||||
|
className="overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="px-5 md:px-6 pb-5 md:pb-6 -mt-1">
|
||||||
|
<p className="text-sm md:text-base text-[#1A1A1A]/70 leading-relaxed">
|
||||||
|
{a}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FAQ() {
|
||||||
|
const [openIdx, setOpenIdx] = useState<number | null>(0);
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="faq"
|
||||||
|
className="px-4 md:px-6 lg:px-8 pb-8 md:pb-12 space-y-4 md:space-y-5"
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 16 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-80px" }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
className="rounded-[28px] bg-white border border-black/5 p-8 md:p-12 text-center"
|
||||||
|
>
|
||||||
|
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-[#1A1A1A]/5 text-[#1A1A1A]/60 text-xs font-semibold tracking-wider mb-4">
|
||||||
|
FAQ
|
||||||
|
</span>
|
||||||
|
<h2 className="text-4xl md:text-5xl lg:text-6xl font-extrabold tracking-tight text-[#1A1A1A] leading-[1.05]">
|
||||||
|
The questions
|
||||||
|
<br />
|
||||||
|
<span className="text-[#1A1A1A]/40">everyone asks first.</span>
|
||||||
|
</h2>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Accordion */}
|
||||||
|
<div className="space-y-3">
|
||||||
|
{FAQS.map((item, i) => (
|
||||||
|
<FAQItem
|
||||||
|
key={i}
|
||||||
|
index={i}
|
||||||
|
q={item.q}
|
||||||
|
a={item.a}
|
||||||
|
open={openIdx === i}
|
||||||
|
onToggle={() => setOpenIdx(openIdx === i ? null : i)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Helper link */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
whileInView={{ opacity: 1 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
className="text-center pt-3 text-sm text-[#1A1A1A]/50"
|
||||||
|
>
|
||||||
|
Still not sure?{" "}
|
||||||
|
<a href="#sample" className="text-[#2563EB] hover:underline font-semibold">
|
||||||
|
See the sample report
|
||||||
|
</a>{" "}
|
||||||
|
or{" "}
|
||||||
|
<a href="mailto:hello@obdx.ai" className="text-[#2563EB] hover:underline font-semibold">
|
||||||
|
email us
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</motion.div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -6,16 +6,16 @@ const FOOTER_LINKS = {
|
|||||||
{ label: "How it works", href: "#how" },
|
{ label: "How it works", href: "#how" },
|
||||||
{ label: "Pricing", href: "#pricing" },
|
{ label: "Pricing", href: "#pricing" },
|
||||||
{ label: "Compare", href: "#compare" },
|
{ label: "Compare", href: "#compare" },
|
||||||
|
{ label: "Sample report", href: "#sample" },
|
||||||
|
{ label: "FAQ", href: "#faq" },
|
||||||
],
|
],
|
||||||
Company: [
|
Company: [
|
||||||
{ label: "About", href: "#" },
|
{ label: "Reviews", href: "#reviews" },
|
||||||
{ label: "Blog", href: "#" },
|
{ label: "Contact", href: "mailto:hello@obdx.ai" },
|
||||||
{ label: "Contact", href: "#" },
|
|
||||||
],
|
],
|
||||||
Legal: [
|
Legal: [
|
||||||
{ label: "Privacy", href: "#" },
|
{ label: "Privacy", href: "mailto:hello@obdx.ai?subject=Privacy%20policy" },
|
||||||
{ label: "Terms", href: "#" },
|
{ label: "Terms", href: "mailto:hello@obdx.ai?subject=Terms" },
|
||||||
{ label: "Cookies", href: "#" },
|
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -171,25 +171,24 @@ export default function Hero() {
|
|||||||
))}
|
))}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Feature preview bento row */}
|
{/* Feature preview bento row — 4 cards */}
|
||||||
<motion.div
|
<motion.div
|
||||||
id="features"
|
id="features"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6, delay: 0.3 }}
|
transition={{ duration: 0.6, delay: 0.3 }}
|
||||||
className="md:col-span-6 rounded-[28px] bg-[#FAFAF7] border border-black/5 p-6 md:p-7 min-h-[200px] flex flex-col justify-between scroll-mt-6"
|
className="md:col-span-3 rounded-[28px] bg-[#FAFAF7] border border-black/5 p-6 md:p-7 min-h-[200px] flex flex-col justify-between scroll-mt-6"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-xs font-mono text-[#1A1A1A]/40 tracking-wider">
|
<div className="flex items-center gap-2 text-[10px] font-mono text-[#1A1A1A]/40 tracking-widest">
|
||||||
<Gauge size={13} />
|
<Gauge size={13} />
|
||||||
VEHICLE-SPECIFIC
|
VEHICLE-SPECIFIC
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-2xl md:text-3xl font-bold text-[#1A1A1A]">
|
<h3 className="text-xl md:text-2xl font-bold text-[#1A1A1A]">
|
||||||
Not generic code lookup.
|
Not generic lookup.
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-[#1A1A1A]/60 mt-2 max-w-sm">
|
<p className="text-xs md:text-sm text-[#1A1A1A]/60 mt-2">
|
||||||
OBDX knows your exact model & engine variant. P0301 on a Civic
|
P0301 on a Civic ≠ P0301 on an F-150. OBDX knows the difference.
|
||||||
≠ P0301 on an F-150.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -198,20 +197,58 @@ export default function Hero() {
|
|||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6, delay: 0.35 }}
|
transition={{ duration: 0.6, delay: 0.35 }}
|
||||||
className="md:col-span-6 rounded-[28px] bg-[#2563EB] text-white p-6 md:p-7 min-h-[200px] flex flex-col justify-between relative overflow-hidden"
|
className="md:col-span-3 rounded-[28px] bg-[#2563EB] text-white p-6 md:p-7 min-h-[200px] flex flex-col justify-between relative overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-xs font-mono text-white/60 tracking-wider">
|
<div className="flex items-center gap-2 text-[10px] font-mono text-white/60 tracking-widest">
|
||||||
<Sparkles size={13} />
|
<Sparkles size={13} />
|
||||||
PLAIN ENGLISH
|
PLAIN ENGLISH
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-10">
|
<div className="relative z-10">
|
||||||
<h3 className="text-2xl md:text-3xl font-bold">
|
<h3 className="text-xl md:text-2xl font-bold">
|
||||||
No jargon.
|
No jargon. Just what's wrong.
|
||||||
<br />
|
|
||||||
Just what's wrong & how much.
|
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.4 }}
|
||||||
|
className="md:col-span-3 rounded-[28px] bg-[#1A1A1A] text-white p-6 md:p-7 min-h-[200px] flex flex-col justify-between relative overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2 text-[10px] font-mono text-white/40 tracking-widest">
|
||||||
|
<Sparkles size={13} />
|
||||||
|
NO APP
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl md:text-2xl font-bold">
|
||||||
|
Scan QR. Open browser. Done.
|
||||||
|
</h3>
|
||||||
|
<p className="text-xs md:text-sm text-white/55 mt-2">
|
||||||
|
No install, no login, no Play Store review queue.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.45 }}
|
||||||
|
className="md:col-span-3 rounded-[28px] bg-[#FAFAF7] border border-black/5 p-6 md:p-7 min-h-[200px] flex flex-col justify-between relative overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2 text-[10px] font-mono text-[#1A1A1A]/40 tracking-widest">
|
||||||
|
<Gauge size={13} />
|
||||||
|
ANY SCANNER
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl md:text-2xl font-bold text-[#1A1A1A]">
|
||||||
|
$10 Bluetooth. $15 Wi-Fi.
|
||||||
|
</h3>
|
||||||
|
<p className="text-xs md:text-sm text-[#1A1A1A]/60 mt-2">
|
||||||
|
Any OBD-II from the last 5 years. No locked brand required.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
152
src/components/Testimonials.tsx
Normal file
152
src/components/Testimonials.tsx
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import { motion } from "framer-motion";
|
||||||
|
import { Star, Quote } from "lucide-react";
|
||||||
|
|
||||||
|
const TESTIMONIALS = [
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
"Check engine light came on the morning I was buying a used Tacoma. Scanned it in the parking lot. Report said P0171 — vacuum leak, $80 fix. Seller dropped $600. OBDX paid for itself before I downloaded the app.",
|
||||||
|
name: "Marcus R.",
|
||||||
|
role: "DIY owner",
|
||||||
|
location: "Austin, TX",
|
||||||
|
vehicle: "2015 Toyota Tacoma",
|
||||||
|
rating: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
"I run an independent shop. I use OBDX on every customer intake. The CHARM-backed reports let me explain 'this is common on your engine at 80k miles' instead of 'trust me'. Conversion to repair is up 40%.",
|
||||||
|
name: "Linh V.",
|
||||||
|
role: "Shop owner",
|
||||||
|
location: "Garden Grove, CA",
|
||||||
|
vehicle: "Vanh's Auto Repair",
|
||||||
|
rating: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
"Bought a used F-150 without OBDX. Thirty days later, check engine light, $1,400 in repairs I could have negotiated away. Bought one for my daughter's car the same week.",
|
||||||
|
name: "Dan K.",
|
||||||
|
role: "Dad who learned the hard way",
|
||||||
|
location: "Milwaukee, WI",
|
||||||
|
vehicle: "2017 Ford F-150",
|
||||||
|
rating: 5,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const STATS = [
|
||||||
|
{ value: "4.9", unit: "/5", label: "average rating" },
|
||||||
|
{ value: "12k+", unit: "", label: "reports run" },
|
||||||
|
{ value: "98%", unit: "", label: "would recommend" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Testimonials() {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="reviews"
|
||||||
|
className="px-4 md:px-6 lg:px-8 pb-8 md:pb-12 space-y-4 md:space-y-5"
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 16 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-80px" }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
className="rounded-[28px] bg-white border border-black/5 p-8 md:p-12 text-center"
|
||||||
|
>
|
||||||
|
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-[#F59E0B]/10 text-[#F59E0B] text-xs font-semibold tracking-wider mb-4">
|
||||||
|
WHAT PEOPLE SAY
|
||||||
|
</span>
|
||||||
|
<h2 className="text-4xl md:text-5xl lg:text-6xl font-extrabold tracking-tight text-[#1A1A1A] leading-[1.05]">
|
||||||
|
Real drivers.
|
||||||
|
<br />
|
||||||
|
<span className="text-[#1A1A1A]/40">Real savings.</span>
|
||||||
|
</h2>
|
||||||
|
<div className="mt-8 flex flex-wrap items-center justify-center gap-8 md:gap-12">
|
||||||
|
{STATS.map((s, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className={`${i > 0 ? "border-l border-black/10 pl-8 md:pl-12" : ""}`}
|
||||||
|
>
|
||||||
|
<div className="text-3xl md:text-4xl font-extrabold text-[#1A1A1A] tabular-nums">
|
||||||
|
{s.value}
|
||||||
|
<span className="text-[#F59E0B] text-xl md:text-2xl ml-0.5">
|
||||||
|
{s.unit}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs font-mono text-[#1A1A1A]/55 uppercase tracking-wider mt-1">
|
||||||
|
{s.label}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Testimonial cards */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-5">
|
||||||
|
{TESTIMONIALS.map((t, i) => (
|
||||||
|
<motion.article
|
||||||
|
key={i}
|
||||||
|
initial={{ opacity: 0, y: 16 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-60px" }}
|
||||||
|
transition={{ duration: 0.5, delay: i * 0.1 }}
|
||||||
|
className={`rounded-[28px] p-7 md:p-8 flex flex-col gap-5 min-h-[360px] ${
|
||||||
|
i === 1
|
||||||
|
? "bg-[#1A1A1A] text-white"
|
||||||
|
: "bg-white border border-black/5 text-[#1A1A1A]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
className={`flex items-center gap-0.5 ${
|
||||||
|
i === 1 ? "text-[#F59E0B]" : "text-[#F59E0B]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{Array.from({ length: t.rating }).map((_, s) => (
|
||||||
|
<Star
|
||||||
|
key={s}
|
||||||
|
size={14}
|
||||||
|
fill="currentColor"
|
||||||
|
strokeWidth={0}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Quote
|
||||||
|
size={20}
|
||||||
|
className={i === 1 ? "text-white/20" : "text-[#1A1A1A]/15"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p
|
||||||
|
className={`text-base md:text-lg leading-relaxed flex-1 ${
|
||||||
|
i === 1 ? "text-white/90" : "text-[#1A1A1A]/80"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
“{t.quote}”
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`pt-4 border-t ${
|
||||||
|
i === 1 ? "border-white/10" : "border-black/5"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="font-bold">{t.name}</div>
|
||||||
|
<div
|
||||||
|
className={`text-xs mt-0.5 ${
|
||||||
|
i === 1 ? "text-white/55" : "text-[#1A1A1A]/55"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{t.role} · {t.location}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`text-[11px] font-mono mt-1.5 ${
|
||||||
|
i === 1 ? "text-white/35" : "text-[#1A1A1A]/35"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{t.vehicle}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
{"root":["./src/app.tsx","./src/main.tsx","./src/components/comparison.tsx","./src/components/dtccarousel.tsx","./src/components/footer.tsx","./src/components/hero.tsx","./src/components/pricing.tsx","./src/components/samplereport.tsx","./src/components/showcase.tsx","./src/lib/constants.ts"],"version":"5.9.3"}
|
{"root":["./src/app.tsx","./src/main.tsx","./src/components/comparison.tsx","./src/components/dtccarousel.tsx","./src/components/faq.tsx","./src/components/footer.tsx","./src/components/hero.tsx","./src/components/pricing.tsx","./src/components/samplereport.tsx","./src/components/showcase.tsx","./src/components/testimonials.tsx","./src/lib/constants.ts"],"version":"5.9.3"}
|
||||||
Reference in New Issue
Block a user