ui: Polish details

This commit is contained in:
Dries Augustyns
2026-04-19 09:03:50 +02:00
parent 6fdc29fc0f
commit 19ea8b0122
35 changed files with 478 additions and 462 deletions
@@ -39,9 +39,9 @@ export function ComparisonTable({competitorName, rows}: ComparisonTableProps) {
className={'grid grid-cols-3 gap-px bg-neutral-200'} className={'grid grid-cols-3 gap-px bg-neutral-200'}
> >
<div className={'bg-white p-6'}> <div className={'bg-white p-6'}>
<span className={'text-sm text-neutral-600'}>{row.feature}</span> <span className={'text-sm text-neutral-700'}>{row.feature}</span>
</div> </div>
<div className={'bg-white p-6'}> <div className={'bg-neutral-50/70 p-6'}>
<div className={'flex justify-center'}> <div className={'flex justify-center'}>
{typeof row.plunk === 'boolean' ? ( {typeof row.plunk === 'boolean' ? (
row.plunk ? ( row.plunk ? (
+2 -2
View File
@@ -35,13 +35,13 @@ export function FAQSection({faqs, schemaId = 'faq-schema'}: FAQSectionProps) {
/> />
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:px-10 sm:py-20'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-16'} className={'mb-12'}
> >
<h2 <h2
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -148,7 +148,10 @@ export function GuideLayout({
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-8 sm:mb-12 w-full'} className={'mb-8 sm:mb-12 w-full'}
> >
<h1 className={'text-2xl sm:text-4xl font-bold tracking-tight text-neutral-900 break-words max-w-full'}> <h1
style={{fontFamily: 'var(--font-display)'}}
className={'text-3xl sm:text-4xl font-bold tracking-[-0.02em] text-neutral-900 break-words max-w-full'}
>
{title} {title}
</h1> </h1>
<p <p
@@ -199,16 +202,16 @@ export function GuideLayout({
<div className={'rounded-xl border border-neutral-200 bg-white p-6 shadow-sm'}> <div className={'rounded-xl border border-neutral-200 bg-white p-6 shadow-sm'}>
<h2 className={'text-sm font-semibold text-neutral-900 mb-4 uppercase tracking-wide'}>On this page</h2> <h2 className={'text-sm font-semibold text-neutral-900 mb-4 uppercase tracking-wide'}>On this page</h2>
<nav> <nav>
<ul className={'space-y-1'}> <ul className={'space-y-0.5'}>
{headings.map(heading => ( {headings.map(heading => (
<li key={heading.id} className={heading.level === 3 ? 'ml-4 mt-0.5' : 'mt-2 first:mt-0'}> <li key={heading.id} className={heading.level === 3 ? 'ml-3' : ''}>
<a <a
href={`#${heading.id}`} href={`#${heading.id}`}
onClick={e => { onClick={e => {
e.preventDefault(); e.preventDefault();
const element = document.getElementById(heading.id); const element = document.getElementById(heading.id);
if (element) { if (element) {
const offset = 100; // Account for fixed header const offset = 100;
const elementPosition = element.getBoundingClientRect().top + window.scrollY; const elementPosition = element.getBoundingClientRect().top + window.scrollY;
window.scrollTo({ window.scrollTo({
top: elementPosition - offset, top: elementPosition - offset,
@@ -216,14 +219,14 @@ export function GuideLayout({
}); });
} }
}} }}
className={`block py-1 border-l-2 -ml-px pl-3 transition-all duration-200 ${ className={`block rounded px-2 py-1.5 transition-all duration-200 ${
heading.level === 2 heading.level === 2
? activeId === heading.id ? activeId === heading.id
? 'border-neutral-900 text-neutral-900 font-semibold text-sm' ? 'bg-neutral-100 text-sm font-semibold text-neutral-900'
: 'border-transparent text-neutral-600 hover:text-neutral-900 hover:border-neutral-300 font-medium text-sm' : 'text-sm font-medium text-neutral-600 hover:bg-neutral-50 hover:text-neutral-900'
: activeId === heading.id : activeId === heading.id
? 'border-neutral-700 text-neutral-800 font-medium text-xs' ? 'bg-neutral-50 text-xs font-medium text-neutral-800'
: 'border-transparent text-neutral-500 hover:text-neutral-700 hover:border-neutral-200 text-xs' : 'text-xs text-neutral-500 hover:bg-neutral-50 hover:text-neutral-700'
}`} }`}
> >
{heading.text} {heading.text}
@@ -101,9 +101,11 @@ export default function EmailEditorFeature() {
> >
<div <div
style={{fontFamily: 'var(--font-mono)'}} style={{fontFamily: 'var(--font-mono)'}}
className={'mb-6 text-[11px] uppercase tracking-[0.18em] text-neutral-500'} className={'mb-10 border-t border-neutral-900/90 pt-4 text-[11px] uppercase tracking-[0.18em] text-neutral-700'}
> >
Email Editor & Templates <span className={'text-neutral-400'}>Features</span>
<span className={'mx-3 text-neutral-300'}></span>
<span className={'font-medium text-neutral-900'}>Email Editor & Templates</span>
</div> </div>
<h1 <h1
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -148,7 +150,7 @@ export default function EmailEditorFeature() {
{/* Features grid */} {/* Features grid */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -165,7 +167,7 @@ export default function EmailEditorFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>Visual editing for speed, code editing for control</p> <p className={'mt-4 text-lg text-neutral-600'}>Visual editing for speed, code editing for control</p>
</motion.div> </motion.div>
<div className={'grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-5 sm:grid-cols-2 lg:grid-cols-3'}>
{features.map((feature, index) => { {features.map((feature, index) => {
const highlighted = feature.featured; const highlighted = feature.featured;
return ( return (
@@ -210,13 +212,13 @@ export default function EmailEditorFeature() {
{/* How it works */} {/* How it works */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-16 text-center'} className={'mb-16'}
> >
<h2 <h2
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -271,7 +273,7 @@ export default function EmailEditorFeature() {
{/* Use cases */} {/* Use cases */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -285,41 +287,43 @@ export default function EmailEditorFeature() {
> >
Built for every team Built for every team
</h2> </h2>
<p className={'mt-4 text-lg text-neutral-600'}>Whether you're a developer, marketer, or founder</p> <p className={'mt-4 text-lg text-neutral-600'}>Whether you&apos;re a developer, marketer, or founder</p>
</motion.div> </motion.div>
<div className={'space-y-4'}> <ul className={'divide-y divide-neutral-200 border-y border-neutral-200'}>
{useCases.map((useCase, index) => ( {useCases.map((useCase, index) => (
<motion.div <motion.li
key={useCase.title} key={useCase.title}
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 12}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.1, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: index * 0.08, ease: [0.22, 1, 0.36, 1]}}
className={'rounded-[24px] border border-neutral-200 bg-white p-8'} className={'grid grid-cols-12 gap-6 py-10 sm:py-12'}
> >
<div className={'flex items-start gap-6'}> <span
<div className={'flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-full border border-neutral-200 text-neutral-900'}> style={{fontFamily: 'var(--font-mono)'}}
{useCase.icon} className={'col-span-12 text-[11px] uppercase tracking-[0.18em] text-neutral-400 sm:col-span-1 sm:pt-1.5'}
</div> >
<div className={'flex-1'}> {String(index + 1).padStart(2, '0')}
<h3 </span>
style={{fontFamily: 'var(--font-display)'}} <h3
className={'text-xl font-bold tracking-[-0.02em] text-neutral-900'} style={{fontFamily: 'var(--font-display)'}}
> className={'col-span-12 text-xl font-bold tracking-[-0.02em] text-neutral-900 sm:col-span-3'}
{useCase.title} >
</h3> {useCase.title}
<p className={'mt-2 text-neutral-600'}>{useCase.description}</p> </h3>
<div className={'mt-4 rounded-xl border border-neutral-100 bg-neutral-50 p-4'}> <div className={'col-span-12 sm:col-span-8'}>
<p style={{fontFamily: 'var(--font-mono)'}} className={'text-sm text-neutral-600'}> <p className={'leading-relaxed text-neutral-600'}>{useCase.description}</p>
{useCase.example} <p
</p> style={{fontFamily: 'var(--font-mono)'}}
</div> className={'mt-5 text-[11px] uppercase tracking-[0.16em] text-neutral-400'}
</div> >
{useCase.example}
</p>
</div> </div>
</motion.div> </motion.li>
))} ))}
</div> </ul>
</div> </div>
</section> </section>
@@ -100,9 +100,11 @@ export default function InboundEmailFeature() {
> >
<div <div
style={{fontFamily: 'var(--font-mono)'}} style={{fontFamily: 'var(--font-mono)'}}
className={'mb-6 text-[11px] uppercase tracking-[0.18em] text-neutral-500'} className={'mb-10 border-t border-neutral-900/90 pt-4 text-[11px] uppercase tracking-[0.18em] text-neutral-700'}
> >
Inbound Email <span className={'text-neutral-400'}>Features</span>
<span className={'mx-3 text-neutral-300'}></span>
<span className={'font-medium text-neutral-900'}>Inbound Email</span>
</div> </div>
<h1 <h1
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -147,7 +149,7 @@ export default function InboundEmailFeature() {
{/* Features grid */} {/* Features grid */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -164,7 +166,7 @@ export default function InboundEmailFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>Everything you need to receive and process incoming emails</p> <p className={'mt-4 text-lg text-neutral-600'}>Everything you need to receive and process incoming emails</p>
</motion.div> </motion.div>
<div className={'grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-5 sm:grid-cols-2 lg:grid-cols-3'}>
{features.map((feature, index) => { {features.map((feature, index) => {
const highlighted = feature.featured; const highlighted = feature.featured;
return ( return (
@@ -209,13 +211,13 @@ export default function InboundEmailFeature() {
{/* How it works */} {/* How it works */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-16 text-center'} className={'mb-16'}
> >
<h2 <h2
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -270,7 +272,7 @@ export default function InboundEmailFeature() {
{/* Use cases */} {/* Use cases */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -287,38 +289,45 @@ export default function InboundEmailFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>From support to sales, inbound email unlocks new automation possibilities</p> <p className={'mt-4 text-lg text-neutral-600'}>From support to sales, inbound email unlocks new automation possibilities</p>
</motion.div> </motion.div>
<div className={'space-y-4'}> <ul className={'divide-y divide-neutral-200 border-y border-neutral-200'}>
{useCases.map((useCase, index) => ( {useCases.map((useCase, index) => (
<motion.div <motion.li
key={useCase.title} key={useCase.title}
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 12}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.1, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: index * 0.08, ease: [0.22, 1, 0.36, 1]}}
className={'rounded-[24px] border border-neutral-200 bg-white p-8'} className={'grid grid-cols-12 gap-6 py-10 sm:py-12'}
> >
<div className={'flex items-start gap-6'}> <span
<div className={'flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-full border border-neutral-200 text-neutral-900'}> style={{fontFamily: 'var(--font-mono)'}}
{useCase.icon} className={'col-span-12 text-[11px] uppercase tracking-[0.18em] text-neutral-400 sm:col-span-1 sm:pt-1.5'}
</div> >
<div className={'flex-1'}> {String(index + 1).padStart(2, '0')}
<h3 </span>
style={{fontFamily: 'var(--font-display)'}} <h3
className={'text-xl font-bold tracking-[-0.02em] text-neutral-900'} style={{fontFamily: 'var(--font-display)'}}
> className={'col-span-12 text-xl font-bold tracking-[-0.02em] text-neutral-900 sm:col-span-3'}
{useCase.title} >
</h3> {useCase.title}
<p className={'mt-2 text-neutral-600'}>{useCase.description}</p> </h3>
<div className={'mt-4 rounded-xl border border-neutral-100 bg-neutral-50 p-4'}> <div className={'col-span-12 sm:col-span-8'}>
<p style={{fontFamily: 'var(--font-mono)'}} className={'text-sm text-neutral-600'}> <p className={'leading-relaxed text-neutral-600'}>{useCase.description}</p>
{useCase.benefits.join(' → ')} <div className={'mt-5 flex flex-wrap gap-x-6 gap-y-1'}>
</p> {useCase.benefits.map(b => (
</div> <span
key={b}
style={{fontFamily: 'var(--font-mono)'}}
className={'text-[11px] uppercase tracking-[0.16em] text-neutral-400'}
>
{b}
</span>
))}
</div> </div>
</div> </div>
</motion.div> </motion.li>
))} ))}
</div> </ul>
</div> </div>
</section> </section>
+33 -30
View File
@@ -115,9 +115,11 @@ export default function SegmentsFeature() {
> >
<div <div
style={{fontFamily: 'var(--font-mono)'}} style={{fontFamily: 'var(--font-mono)'}}
className={'mb-6 text-[11px] uppercase tracking-[0.18em] text-neutral-500'} className={'mb-10 border-t border-neutral-900/90 pt-4 text-[11px] uppercase tracking-[0.18em] text-neutral-700'}
> >
Audience Segmentation <span className={'text-neutral-400'}>Features</span>
<span className={'mx-3 text-neutral-300'}></span>
<span className={'font-medium text-neutral-900'}>Audience Segmentation</span>
</div> </div>
<h1 <h1
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -162,7 +164,7 @@ export default function SegmentsFeature() {
{/* Features grid */} {/* Features grid */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -179,7 +181,7 @@ export default function SegmentsFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>Build precise audiences and send campaigns that land</p> <p className={'mt-4 text-lg text-neutral-600'}>Build precise audiences and send campaigns that land</p>
</motion.div> </motion.div>
<div className={'grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-5 sm:grid-cols-2 lg:grid-cols-3'}>
{features.map((feature, index) => { {features.map((feature, index) => {
const highlighted = feature.featured; const highlighted = feature.featured;
return ( return (
@@ -224,7 +226,7 @@ export default function SegmentsFeature() {
{/* Filter examples */} {/* Filter examples */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -241,7 +243,7 @@ export default function SegmentsFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>Build complex segments with nested AND/OR logic</p> <p className={'mt-4 text-lg text-neutral-600'}>Build complex segments with nested AND/OR logic</p>
</motion.div> </motion.div>
<div className={'space-y-4'}> <div className={'space-y-5'}>
{filterExamples.map((example, index) => ( {filterExamples.map((example, index) => (
<motion.div <motion.div
key={example.title} key={example.title}
@@ -276,7 +278,7 @@ export default function SegmentsFeature() {
{/* Segment types */} {/* Segment types */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -293,7 +295,7 @@ export default function SegmentsFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>Choose between dynamic filtering or manual curation</p> <p className={'mt-4 text-lg text-neutral-600'}>Choose between dynamic filtering or manual curation</p>
</motion.div> </motion.div>
<div className={'grid gap-4 sm:grid-cols-2'}> <div className={'grid gap-5 sm:grid-cols-2'}>
{[ {[
{ {
icon: <TrendingUp className="h-6 w-6" strokeWidth={1.5} />, icon: <TrendingUp className="h-6 w-6" strokeWidth={1.5} />,
@@ -340,7 +342,7 @@ export default function SegmentsFeature() {
{/* Use cases */} {/* Use cases */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -357,33 +359,34 @@ export default function SegmentsFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>From targeted campaigns to automated workflows</p> <p className={'mt-4 text-lg text-neutral-600'}>From targeted campaigns to automated workflows</p>
</motion.div> </motion.div>
<div className={'space-y-4'}> <ul className={'divide-y divide-neutral-200 border-y border-neutral-200'}>
{useCases.map((useCase, index) => ( {useCases.map((useCase, index) => (
<motion.div <motion.li
key={useCase.title} key={useCase.title}
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 12}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.1, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: index * 0.08, ease: [0.22, 1, 0.36, 1]}}
className={'rounded-[24px] border border-neutral-200 bg-white p-8'} className={'grid grid-cols-12 gap-6 py-10 sm:py-12'}
> >
<div className={'flex items-start gap-6'}> <span
<div className={'flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-full border border-neutral-200 text-neutral-900'}> style={{fontFamily: 'var(--font-mono)'}}
{useCase.icon} className={'col-span-12 text-[11px] uppercase tracking-[0.18em] text-neutral-400 sm:col-span-1 sm:pt-1.5'}
</div> >
<div className={'flex-1'}> {String(index + 1).padStart(2, '0')}
<h3 </span>
style={{fontFamily: 'var(--font-display)'}} <h3
className={'text-xl font-bold tracking-[-0.02em] text-neutral-900'} style={{fontFamily: 'var(--font-display)'}}
> className={'col-span-12 text-xl font-bold tracking-[-0.02em] text-neutral-900 sm:col-span-3'}
{useCase.title} >
</h3> {useCase.title}
<p className={'mt-2 text-neutral-600'}>{useCase.description}</p> </h3>
</div> <p className={'col-span-12 leading-relaxed text-neutral-600 sm:col-span-8'}>
</div> {useCase.description}
</motion.div> </p>
</motion.li>
))} ))}
</div> </ul>
</div> </div>
</section> </section>
+35 -33
View File
@@ -111,9 +111,11 @@ export default function SMTPFeature() {
> >
<div <div
style={{fontFamily: 'var(--font-mono)'}} style={{fontFamily: 'var(--font-mono)'}}
className={'mb-6 text-[11px] uppercase tracking-[0.18em] text-neutral-500'} className={'mb-10 border-t border-neutral-900/90 pt-4 text-[11px] uppercase tracking-[0.18em] text-neutral-700'}
> >
SMTP <span className={'text-neutral-400'}>Features</span>
<span className={'mx-3 text-neutral-300'}></span>
<span className={'font-medium text-neutral-900'}>SMTP</span>
</div> </div>
<h1 <h1
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -158,7 +160,7 @@ export default function SMTPFeature() {
{/* Features grid */} {/* Features grid */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -177,7 +179,7 @@ export default function SMTPFeature() {
</p> </p>
</motion.div> </motion.div>
<div className={'grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-5 sm:grid-cols-2 lg:grid-cols-3'}>
{features.map((feature, index) => { {features.map((feature, index) => {
const highlighted = feature.featured; const highlighted = feature.featured;
return ( return (
@@ -222,7 +224,7 @@ export default function SMTPFeature() {
{/* Comparison table */} {/* Comparison table */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -270,7 +272,7 @@ export default function SMTPFeature() {
{/* Use cases */} {/* Use cases */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -287,40 +289,40 @@ export default function SMTPFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>Perfect for these scenarios</p> <p className={'mt-4 text-lg text-neutral-600'}>Perfect for these scenarios</p>
</motion.div> </motion.div>
<div className={'space-y-4'}> <ul className={'divide-y divide-neutral-200 border-y border-neutral-200'}>
{useCases.map((useCase, index) => ( {useCases.map((useCase, index) => (
<motion.div <motion.li
key={useCase.title} key={useCase.title}
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 12}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.1, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: index * 0.08, ease: [0.22, 1, 0.36, 1]}}
className={'rounded-[24px] border border-neutral-200 bg-white p-8'} className={'grid grid-cols-12 gap-6 py-10 sm:py-12'}
> >
<div className={'flex items-start gap-6'}> <span
<div className={'flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-full border border-neutral-200 text-neutral-900'}> style={{fontFamily: 'var(--font-mono)'}}
{useCase.icon} className={'col-span-12 text-[11px] uppercase tracking-[0.18em] text-neutral-400 sm:col-span-1 sm:pt-1.5'}
</div> >
<div className={'flex-1'}> {String(index + 1).padStart(2, '0')}
<h3 </span>
style={{fontFamily: 'var(--font-display)'}} <h3
className={'text-xl font-bold tracking-[-0.02em] text-neutral-900'} style={{fontFamily: 'var(--font-display)'}}
> className={'col-span-12 text-xl font-bold tracking-[-0.02em] text-neutral-900 sm:col-span-3'}
{useCase.title} >
</h3> {useCase.title}
<p className={'mt-2 text-neutral-600'}>{useCase.description}</p> </h3>
<div <div className={'col-span-12 sm:col-span-8'}>
style={{fontFamily: 'var(--font-mono)'}} <p className={'leading-relaxed text-neutral-600'}>{useCase.description}</p>
className={'mt-4 inline-flex items-center gap-2 text-[11px] uppercase tracking-[0.18em] text-neutral-500'} <span
> style={{fontFamily: 'var(--font-mono)'}}
<div className={'h-1.5 w-1.5 rounded-full bg-neutral-900'} /> className={'mt-5 inline-block text-[11px] uppercase tracking-[0.16em] text-neutral-400'}
{useCase.benefit} >
</div> {useCase.benefit}
</div> </span>
</div> </div>
</motion.div> </motion.li>
))} ))}
</div> </ul>
</div> </div>
</section> </section>
+36 -35
View File
@@ -100,9 +100,11 @@ export default function WorkflowsFeature() {
> >
<div <div
style={{fontFamily: 'var(--font-mono)'}} style={{fontFamily: 'var(--font-mono)'}}
className={'mb-6 text-[11px] uppercase tracking-[0.18em] text-neutral-500'} className={'mb-10 border-t border-neutral-900/90 pt-4 text-[11px] uppercase tracking-[0.18em] text-neutral-700'}
> >
Workflow Automation <span className={'text-neutral-400'}>Features</span>
<span className={'mx-3 text-neutral-300'}></span>
<span className={'font-medium text-neutral-900'}>Workflow Automation</span>
</div> </div>
<h1 <h1
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -147,7 +149,7 @@ export default function WorkflowsFeature() {
{/* Features grid */} {/* Features grid */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -166,7 +168,7 @@ export default function WorkflowsFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>Powerful features that make complex automations simple</p> <p className={'mt-4 text-lg text-neutral-600'}>Powerful features that make complex automations simple</p>
</motion.div> </motion.div>
<div className={'grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-5 sm:grid-cols-2 lg:grid-cols-3'}>
{features.map((feature, index) => { {features.map((feature, index) => {
const highlighted = feature.featured; const highlighted = feature.featured;
return ( return (
@@ -211,13 +213,13 @@ export default function WorkflowsFeature() {
{/* How it works */} {/* How it works */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-16 text-center'} className={'mb-16'}
> >
<h2 <h2
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -274,7 +276,7 @@ export default function WorkflowsFeature() {
{/* Use cases */} {/* Use cases */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
@@ -291,41 +293,40 @@ export default function WorkflowsFeature() {
<p className={'mt-4 text-lg text-neutral-600'}>From onboarding to re-engagement, workflows handle it all</p> <p className={'mt-4 text-lg text-neutral-600'}>From onboarding to re-engagement, workflows handle it all</p>
</motion.div> </motion.div>
<div className={'space-y-4'}> <ul className={'divide-y divide-neutral-200 border-y border-neutral-200'}>
{useCases.map((useCase, index) => ( {useCases.map((useCase, index) => (
<motion.div <motion.li
key={useCase.title} key={useCase.title}
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 12}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.1, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: index * 0.08, ease: [0.22, 1, 0.36, 1]}}
className={'rounded-[24px] border border-neutral-200 bg-white p-8'} className={'grid grid-cols-12 gap-6 py-10 sm:py-12'}
> >
<div className={'flex items-start gap-6'}> <span
<div className={'flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-full border border-neutral-200 bg-white text-neutral-900'}> style={{fontFamily: 'var(--font-mono)'}}
{useCase.icon} className={'col-span-12 text-[11px] uppercase tracking-[0.18em] text-neutral-400 sm:col-span-1 sm:pt-1.5'}
</div> >
<div className={'flex-1'}> {String(index + 1).padStart(2, '0')}
<h3 </span>
style={{fontFamily: 'var(--font-display)'}} <h3
className={'text-xl font-bold tracking-[-0.02em] text-neutral-900'} style={{fontFamily: 'var(--font-display)'}}
> className={'col-span-12 text-xl font-bold tracking-[-0.02em] text-neutral-900 sm:col-span-3'}
{useCase.title} >
</h3> {useCase.title}
<p className={'mt-2 text-neutral-600'}>{useCase.description}</p> </h3>
<div className={'mt-4 rounded-xl border border-neutral-100 bg-neutral-50 p-4'}> <div className={'col-span-12 sm:col-span-8'}>
<p <p className={'leading-relaxed text-neutral-600'}>{useCase.description}</p>
style={{fontFamily: 'var(--font-mono)'}} <p
className={'text-sm text-neutral-600'} style={{fontFamily: 'var(--font-mono)'}}
> className={'mt-5 text-[11px] uppercase tracking-[0.16em] text-neutral-400'}
{useCase.example} >
</p> {useCase.example}
</div> </p>
</div>
</div> </div>
</motion.div> </motion.li>
))} ))}
</div> </ul>
</div> </div>
</section> </section>
@@ -78,7 +78,7 @@ export default function EmailAPIGuide() {
<h2 className="text-3xl font-bold text-neutral-900 mb-6">How Email APIs Work</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">How Email APIs Work</h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Authentication</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Authentication</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
You authenticate requests using an API key (usually passed in headers). This identifies your account and You authenticate requests using an API key (usually passed in headers). This identifies your account and
@@ -86,14 +86,14 @@ export default function EmailAPIGuide() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Make HTTP Request</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Make HTTP Request</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Send a POST request to the API endpoint with email details (recipient, subject, body, etc.) as JSON. Send a POST request to the API endpoint with email details (recipient, subject, body, etc.) as JSON.
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. API Validates & Queues</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. API Validates & Queues</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
The API validates your request, queues the email for delivery, and returns a response with the email ID The API validates your request, queues the email for delivery, and returns a response with the email ID
@@ -101,14 +101,14 @@ export default function EmailAPIGuide() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Email Delivery</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Email Delivery</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
The service handles SMTP connections, retry logic, and delivery to the recipient's mail server. The service handles SMTP connections, retry logic, and delivery to the recipient's mail server.
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Webhooks & Tracking</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Webhooks & Tracking</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
You receive webhook notifications for delivery events (delivered, bounced, opened, clicked) and can query You receive webhook notifications for delivery events (delivered, bounced, opened, clicked) and can query
@@ -535,7 +535,7 @@ func main() {
</p> </p>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">Deliverability Reputation</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">Deliverability Reputation</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Choose providers with strong deliverability rates and sender reputation. Poor deliverability means your Choose providers with strong deliverability rates and sender reputation. Poor deliverability means your
@@ -543,7 +543,7 @@ func main() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">Feature Set</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">Feature Set</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Ensure the API supports your needs: templates, webhooks, analytics, scheduling, attachments, etc. Some Ensure the API supports your needs: templates, webhooks, analytics, scheduling, attachments, etc. Some
@@ -551,7 +551,7 @@ func main() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">Pricing Model</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">Pricing Model</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Understand pricing: per-email charges, monthly tiers, overage fees. Calculate costs for your expected Understand pricing: per-email charges, monthly tiers, overage fees. Calculate costs for your expected
@@ -559,7 +559,7 @@ func main() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">Developer Experience</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">Developer Experience</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Good documentation, SDKs in your language, clear error messages, and responsive support make Good documentation, SDKs in your language, clear error messages, and responsive support make
@@ -567,7 +567,7 @@ func main() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">Scalability & Reliability</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">Scalability & Reliability</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Can the provider handle your peak volumes? What's their uptime guarantee (SLA)? Do they have redundancy Can the provider handle your peak volumes? What's their uptime guarantee (SLA)? Do they have redundancy
@@ -575,7 +575,7 @@ func main() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">Compliance & Security</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">Compliance & Security</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Ensure the provider complies with GDPR, CAN-SPAM, and other relevant regulations. Check their security Ensure the provider complies with GDPR, CAN-SPAM, and other relevant regulations. Check their security
@@ -141,7 +141,7 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
<h2 className="text-3xl font-bold text-neutral-900 mb-6">What Affects Click-Through Rates?</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">What Affects Click-Through Rates?</h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Call-to-Action (CTA) Design</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Call-to-Action (CTA) Design</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Your CTA's design, placement, and copy directly impact clicks. Clear, prominent, action-oriented CTAs Your CTA's design, placement, and copy directly impact clicks. Clear, prominent, action-oriented CTAs
@@ -149,7 +149,7 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Email Relevance</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Email Relevance</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Targeted, personalized content generates 2-3x higher CTR than generic blasts. Segmentation and Targeted, personalized content generates 2-3x higher CTR than generic blasts. Segmentation and
@@ -157,7 +157,7 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Value Proposition</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Value Proposition</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Recipients need a clear reason to click. Compelling value propositions—exclusive content, limited offers, Recipients need a clear reason to click. Compelling value propositions—exclusive content, limited offers,
@@ -165,7 +165,7 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Mobile Optimization</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Mobile Optimization</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
60%+ of emails are read on mobile. Unoptimized emails with small links or poorly formatted content see 50% 60%+ of emails are read on mobile. Unoptimized emails with small links or poorly formatted content see 50%
@@ -173,7 +173,7 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Content Scannability</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Content Scannability</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Most people skim emails. Clear structure with headers, bullet points, and whitespace helps readers find Most people skim emails. Clear structure with headers, bullet points, and whitespace helps readers find
@@ -181,7 +181,7 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">6. Number of CTAs</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">6. Number of CTAs</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
More CTAs = divided attention. Emails with one primary CTA convert 371% better than those with multiple More CTAs = divided attention. Emails with one primary CTA convert 371% better than those with multiple
@@ -402,14 +402,14 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
<h2 className="text-3xl font-bold text-neutral-900 mb-6">Common CTR Mistakes to Avoid</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">Common CTR Mistakes to Avoid</h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Too Many CTAs</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Too Many CTAs</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Multiple competing CTAs confuse readers and reduce overall clicks. Focus on one primary action per email. Multiple competing CTAs confuse readers and reduce overall clicks. Focus on one primary action per email.
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Vague CTA Copy</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Vague CTA Copy</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
"Click here" and "Learn more" don't communicate value. Be specific: "Download free guide" or "Start 14-day "Click here" and "Learn more" don't communicate value. Be specific: "Download free guide" or "Start 14-day
@@ -417,7 +417,7 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Image-Only CTAs</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Image-Only CTAs</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Many email clients block images by default. If your CTA is an image, users won't see it. Use HTML buttons Many email clients block images by default. If your CTA is an image, users won't see it. Use HTML buttons
@@ -425,14 +425,14 @@ CTOR = (294 ÷ 2,450) × 100 = 12.0%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2">✗ Small, Hard-to-Tap Links</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2">✗ Small, Hard-to-Tap Links</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Tiny text links are difficult to tap on mobile. Use large buttons (minimum 44x44px) for easy tapping. Tiny text links are difficult to tap on mobile. Use large buttons (minimum 44x44px) for easy tapping.
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2">✗ No Clear Value Proposition</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2">✗ No Clear Value Proposition</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Readers won't click if they don't know why they should. Clearly communicate the benefit of clicking before Readers won't click if they don't know why they should. Clearly communicate the benefit of clicking before
@@ -71,7 +71,7 @@ export default function EmailDeliverability() {
</p> </p>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Sender Reputation</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Sender Reputation</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Email providers track your sending behavior over time. High engagement rates, low spam complaints, and few Email providers track your sending behavior over time. High engagement rates, low spam complaints, and few
@@ -79,7 +79,7 @@ export default function EmailDeliverability() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Email Authentication</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Email Authentication</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
SPF, DKIM, and DMARC authenticate your emails and prove they're legitimate. Without proper authentication, SPF, DKIM, and DMARC authenticate your emails and prove they're legitimate. Without proper authentication,
@@ -87,7 +87,7 @@ export default function EmailDeliverability() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Email Content</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Email Content</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Spam filters analyze your subject lines, body content, links, and images. Spammy language, excessive Spam filters analyze your subject lines, body content, links, and images. Spammy language, excessive
@@ -95,7 +95,7 @@ export default function EmailDeliverability() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. List Quality & Engagement</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. List Quality & Engagement</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Sending to engaged subscribers who want your emails is crucial. High open rates and clicks signal quality. Sending to engaged subscribers who want your emails is crucial. High open rates and clicks signal quality.
@@ -103,7 +103,7 @@ export default function EmailDeliverability() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Technical Infrastructure</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Technical Infrastructure</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Your sending IP address, domain reputation, and email infrastructure affect how providers perceive your Your sending IP address, domain reputation, and email infrastructure affect how providers perceive your
@@ -107,7 +107,7 @@ export default function EmailMarketingBestPractices() {
<h2 className="text-3xl font-bold text-neutral-900 mb-6">Email Content Best Practices</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">Email Content Best Practices</h2>
<div className="space-y-6 mb-8"> <div className="space-y-6 mb-8">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Craft Compelling Subject Lines</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Craft Compelling Subject Lines</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
Your subject line determines whether emails get opened. Keep them under 50 characters, create curiosity, Your subject line determines whether emails get opened. Keep them under 50 characters, create curiosity,
@@ -125,7 +125,7 @@ export default function EmailMarketingBestPractices() {
</div> </div>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Personalize Beyond First Names</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Personalize Beyond First Names</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Use behavioral data, purchase history, browsing activity, or preferences. Personalized emails deliver 6x Use behavioral data, purchase history, browsing activity, or preferences. Personalized emails deliver 6x
@@ -133,7 +133,7 @@ export default function EmailMarketingBestPractices() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Focus on One Primary Goal</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Focus on One Primary Goal</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Each email should have one clear call-to-action (CTA). Multiple CTAs confuse readers and reduce conversion Each email should have one clear call-to-action (CTA). Multiple CTAs confuse readers and reduce conversion
@@ -141,7 +141,7 @@ export default function EmailMarketingBestPractices() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Write Scannable Content</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Write Scannable Content</h3>
<p className="text-neutral-700 mb-3">Most people skim emails. Structure content for easy scanning:</p> <p className="text-neutral-700 mb-3">Most people skim emails. Structure content for easy scanning:</p>
<ul className="list-disc list-inside space-y-1 text-neutral-700"> <ul className="list-disc list-inside space-y-1 text-neutral-700">
@@ -153,7 +153,7 @@ export default function EmailMarketingBestPractices() {
</ul> </ul>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Create Compelling CTAs</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Create Compelling CTAs</h3>
<p className="text-neutral-700 mb-3">Effective CTAs are:</p> <p className="text-neutral-700 mb-3">Effective CTAs are:</p>
<ul className="list-disc list-inside space-y-1 text-neutral-700"> <ul className="list-disc list-inside space-y-1 text-neutral-700">
@@ -172,7 +172,7 @@ export default function EmailMarketingBestPractices() {
</ul> </ul>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">6. Provide Real Value</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">6. Provide Real Value</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Every email should benefit the reader. Share insights, solve problems, offer exclusive content, or provide Every email should benefit the reader. Share insights, solve problems, offer exclusive content, or provide
@@ -361,7 +361,7 @@ export default function EmailMarketingBestPractices() {
</p> </p>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">What to A/B Test</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">What to A/B Test</h3>
<ul className="space-y-2 text-neutral-700"> <ul className="space-y-2 text-neutral-700">
<li> <li>
@@ -385,7 +385,7 @@ export default function EmailMarketingBestPractices() {
</ul> </ul>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">A/B Testing Best Practices</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">A/B Testing Best Practices</h3>
<ul className="space-y-2 text-neutral-700"> <ul className="space-y-2 text-neutral-700">
<li> Test one variable at a time for clear results</li> <li> Test one variable at a time for clear results</li>
@@ -131,7 +131,7 @@ Open Rate = (285 ÷ 950) × 100 = 30%`}
<h2 className="text-3xl font-bold text-neutral-900 mb-6">What Affects Email Open Rates?</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">What Affects Email Open Rates?</h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Subject Line</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Subject Line</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
Your subject line is the #1 factor. It must be compelling, relevant, and create curiosity without being Your subject line is the #1 factor. It must be compelling, relevant, and create curiosity without being
@@ -161,7 +161,7 @@ Open Rate = (285 ÷ 950) × 100 = 30%`}
</div> </div>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Sender Name</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Sender Name</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Recipients decide whether to open based on who it's from. Use a recognizable name—either your brand or a Recipients decide whether to open based on who it's from. Use a recognizable name—either your brand or a
@@ -169,7 +169,7 @@ Open Rate = (285 ÷ 950) × 100 = 30%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Send Time & Day</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Send Time & Day</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Timing impacts visibility. B2B emails typically perform best Tuesday-Thursday, 10am-2pm. B2C varies more Timing impacts visibility. B2B emails typically perform best Tuesday-Thursday, 10am-2pm. B2C varies more
@@ -177,7 +177,7 @@ Open Rate = (285 ÷ 950) × 100 = 30%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. List Quality & Segmentation</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. List Quality & Segmentation</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Engaged subscribers open more. Segmenting by behavior, interests, or demographics ensures relevance. Engaged subscribers open more. Segmenting by behavior, interests, or demographics ensures relevance.
@@ -185,7 +185,7 @@ Open Rate = (285 ÷ 950) × 100 = 30%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Deliverability & Sender Reputation</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Deliverability & Sender Reputation</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
If emails land in spam, they won't be opened. Maintain good sender reputation through proper If emails land in spam, they won't be opened. Maintain good sender reputation through proper
@@ -193,7 +193,7 @@ Open Rate = (285 ÷ 950) × 100 = 30%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">6. Email Frequency</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">6. Email Frequency</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Too frequent leads to fatigue and unsubscribes. Too infrequent and subscribers forget you. Find the sweet Too frequent leads to fatigue and unsubscribes. Too infrequent and subscribers forget you. Find the sweet
@@ -201,7 +201,7 @@ Open Rate = (285 ÷ 950) × 100 = 30%`}
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">7. Mobile Optimization</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">7. Mobile Optimization</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
60%+ of emails are opened on mobile. Use short subject lines (40-50 characters), clear preview text, and 60%+ of emails are opened on mobile. Use short subject lines (40-50 characters), clear preview text, and
@@ -70,7 +70,7 @@ export default function EmailSenderReputation() {
<h2 className="text-3xl font-bold text-neutral-900 mb-6">What Affects Sender Reputation?</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">What Affects Sender Reputation?</h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Spam Complaint Rate</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Spam Complaint Rate</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: Critical.</strong> When recipients mark your emails as spam, it severely damages <strong>Impact: Critical.</strong> When recipients mark your emails as spam, it severely damages
@@ -81,7 +81,7 @@ export default function EmailSenderReputation() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Engagement Metrics</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Engagement Metrics</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: Very High.</strong> Email providers track opens, clicks, replies, forwards, and deletes. <strong>Impact: Very High.</strong> Email providers track opens, clicks, replies, forwards, and deletes.
@@ -92,7 +92,7 @@ export default function EmailSenderReputation() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Bounce Rate</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Bounce Rate</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: High.</strong> High bounce rates (especially hard bounces) indicate poor list hygiene, <strong>Impact: High.</strong> High bounce rates (especially hard bounces) indicate poor list hygiene,
@@ -103,7 +103,7 @@ export default function EmailSenderReputation() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Email Authentication</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Email Authentication</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: High.</strong> Proper SPF, DKIM, and DMARC authentication proves your emails are <strong>Impact: High.</strong> Proper SPF, DKIM, and DMARC authentication proves your emails are
@@ -114,7 +114,7 @@ export default function EmailSenderReputation() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Spam Trap Hits</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">5. Spam Trap Hits</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: Critical.</strong> Spam traps are email addresses used to catch senders with poor <strong>Impact: Critical.</strong> Spam traps are email addresses used to catch senders with poor
@@ -125,7 +125,7 @@ export default function EmailSenderReputation() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">6. Sending Volume & Consistency</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">6. Sending Volume & Consistency</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: Moderate.</strong> Sudden spikes in volume look suspicious. Inconsistent sending (long <strong>Impact: Moderate.</strong> Sudden spikes in volume look suspicious. Inconsistent sending (long
@@ -136,7 +136,7 @@ export default function EmailSenderReputation() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">7. Content Quality</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">7. Content Quality</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: Moderate.</strong> Spammy content (excessive links, misleading subject lines, all caps) <strong>Impact: Moderate.</strong> Spammy content (excessive links, misleading subject lines, all caps)
@@ -147,7 +147,7 @@ export default function EmailSenderReputation() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">8. Blacklist Status</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">8. Blacklist Status</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: Critical.</strong> Being listed on major blacklists (Spamhaus, Barracuda, SURBL) can block <strong>Impact: Critical.</strong> Being listed on major blacklists (Spamhaus, Barracuda, SURBL) can block
@@ -158,7 +158,7 @@ export default function EmailSenderReputation() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">9. Sending History</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">9. Sending History</h3>
<p className="text-neutral-700 mb-3"> <p className="text-neutral-700 mb-3">
<strong>Impact: Cumulative.</strong> Reputation is built over time. New domains/IPs have no history (zero <strong>Impact: Cumulative.</strong> Reputation is built over time. New domains/IPs have no history (zero
+59 -58
View File
@@ -94,7 +94,13 @@ const guides: Guide[] = [
}, },
]; ];
const badgeOrder = ['Authentication', 'Deliverability', 'Analytics', 'Technical', 'Best Practices', 'Fundamentals'];
export default function GuidesIndex() { export default function GuidesIndex() {
const categories = badgeOrder
.map(name => ({name, guides: guides.filter(g => g.badge === name)}))
.filter(c => c.guides.length > 0);
return ( return (
<> <>
<NextSeo <NextSeo
@@ -165,68 +171,63 @@ export default function GuidesIndex() {
</div> </div>
</section> </section>
{/* Guides grid */} {/* Guides - Categorized */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}>
<motion.div <div className={'space-y-16'}>
initial={{opacity: 0, y: 20}} {categories.map((category, catIndex) => (
whileInView={{opacity: 1, y: 0}} <motion.div
viewport={{once: true}} key={category.name}
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} initial={{opacity: 0, y: 16}}
className={'mb-16'} whileInView={{opacity: 1, y: 0}}
> viewport={{once: true}}
<h2 transition={{duration: 0.6, delay: catIndex * 0.06, ease: [0.22, 1, 0.36, 1]}}
style={{fontFamily: 'var(--font-display)'}} >
className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'} <div className={'mb-6 flex items-center gap-4'}>
> <span
Browse all guides style={{fontFamily: 'var(--font-mono)'}}
</h2> className={'shrink-0 text-[11px] uppercase tracking-[0.18em] text-neutral-400'}
<p className={'mt-4 text-lg text-neutral-600'}>Everything you need to master email</p>
</motion.div>
<div className={'grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}>
{guides.map((guide, index) => {
const Icon = guide.icon;
return (
<motion.div
key={guide.href}
initial={{opacity: 0, y: 16}}
whileInView={{opacity: 1, y: 0}}
viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.04, ease: [0.22, 1, 0.36, 1]}}
>
<Link
href={guide.href}
className={
'group flex min-h-[16rem] flex-col justify-between rounded-[28px] border border-neutral-200 bg-white p-8 transition hover:border-neutral-900'
}
> >
<div className={'flex items-start justify-between'}> {category.name}
<div className={'text-neutral-900'}> </span>
<Icon className="h-6 w-6" strokeWidth={1.5} /> <div className={'h-px flex-1 bg-neutral-200'} />
</div> </div>
{guide.badge && (
<span <div className={'divide-y divide-neutral-100'}>
style={{fontFamily: 'var(--font-mono)'}} {category.guides.map(guide => {
className={'text-[11px] uppercase tracking-[0.18em] text-neutral-400'} const Icon = guide.icon;
> return (
{guide.badge} <Link
</span> key={guide.href}
)} href={guide.href}
</div> className={
<div> 'group -mx-4 flex items-center gap-5 rounded-lg px-4 py-5 transition hover:bg-neutral-50 sm:gap-6'
<h3 }
style={{fontFamily: 'var(--font-display)'}}
className={'mt-8 text-xl font-bold tracking-[-0.02em] text-neutral-900'}
> >
{guide.title} <Icon
</h3> className={'h-5 w-5 shrink-0 text-neutral-400 transition group-hover:text-neutral-600'}
<p className={'mt-2 text-sm leading-relaxed text-neutral-600'}>{guide.description}</p> strokeWidth={1.5}
</div> />
</Link> <div className={'min-w-0 flex-1'}>
</motion.div> <h3
); style={{fontFamily: 'var(--font-display)'}}
})} className={'font-bold tracking-[-0.01em] text-neutral-900'}
>
{guide.title}
</h3>
<p className={'mt-0.5 truncate text-sm text-neutral-500'}>{guide.description}</p>
</div>
<ArrowRight
className={
'h-4 w-4 shrink-0 text-neutral-300 transition-transform group-hover:translate-x-0.5 group-hover:text-neutral-600'
}
/>
</Link>
);
})}
</div>
</motion.div>
))}
</div> </div>
</div> </div>
</section> </section>
+10 -10
View File
@@ -33,7 +33,7 @@ export default function WhatIsDKIM() {
</p> </p>
<div className="space-y-6 mb-8"> <div className="space-y-6 mb-8">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. The Sending Server Signs the Email</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. The Sending Server Signs the Email</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
When you send an email, your email server adds a DKIM signature to the email header. This signature is When you send an email, your email server adds a DKIM signature to the email header. This signature is
@@ -41,7 +41,7 @@ export default function WhatIsDKIM() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. The Signature is Added to Headers</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. The Signature is Added to Headers</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
The DKIM signature includes a hash of specific email components (like the subject, body, and sender) and The DKIM signature includes a hash of specific email components (like the subject, body, and sender) and
@@ -49,7 +49,7 @@ export default function WhatIsDKIM() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. The Receiving Server Verifies</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. The Receiving Server Verifies</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
When the email arrives, the receiving server looks up your domain's public DKIM key in DNS, then uses it When the email arrives, the receiving server looks up your domain's public DKIM key in DNS, then uses it
@@ -57,7 +57,7 @@ export default function WhatIsDKIM() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Delivery Decision</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Delivery Decision</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Passing DKIM verification improves your sender reputation and deliverability. Failing or missing DKIM may Passing DKIM verification improves your sender reputation and deliverability. Failing or missing DKIM may
@@ -252,7 +252,7 @@ export default function WhatIsDKIM() {
<h2 className="text-3xl font-bold text-neutral-900 mb-6">DKIM Best Practices</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">DKIM Best Practices</h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-green-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Use 2048-bit Keys</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Use 2048-bit Keys</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
While 1024-bit keys still work, 2048-bit keys provide better security and are recommended by Gmail and While 1024-bit keys still work, 2048-bit keys provide better security and are recommended by Gmail and
@@ -260,7 +260,7 @@ export default function WhatIsDKIM() {
</p> </p>
</div> </div>
<div className="border-l-4 border-green-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Implement SPF and DMARC Too</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Implement SPF and DMARC Too</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
DKIM works best when combined with SPF and DMARC for comprehensive email authentication. Use all three for DKIM works best when combined with SPF and DMARC for comprehensive email authentication. Use all three for
@@ -268,7 +268,7 @@ export default function WhatIsDKIM() {
</p> </p>
</div> </div>
<div className="border-l-4 border-green-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Monitor DKIM Status</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Monitor DKIM Status</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Regularly check that your DKIM signatures are passing. Most email platforms provide authentication Regularly check that your DKIM signatures are passing. Most email platforms provide authentication
@@ -276,7 +276,7 @@ export default function WhatIsDKIM() {
</p> </p>
</div> </div>
<div className="border-l-4 border-green-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Rotate Keys Periodically</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Rotate Keys Periodically</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
For enhanced security, rotate your DKIM keys every 6-12 months. Plan key rotation carefully to avoid For enhanced security, rotate your DKIM keys every 6-12 months. Plan key rotation carefully to avoid
@@ -284,14 +284,14 @@ export default function WhatIsDKIM() {
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Don't Share Private Keys</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Don't Share Private Keys</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Your DKIM private key should never be shared or stored insecurely. Treat it like a password. Your DKIM private key should never be shared or stored insecurely. Treat it like a password.
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2">✗ Don't Use the Same Key Across Domains</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2">✗ Don't Use the Same Key Across Domains</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Each domain should have its own unique DKIM key pair for security and proper authentication. Each domain should have its own unique DKIM key pair for security and proper authentication.
@@ -32,7 +32,7 @@ export default function WhatIsDMARC() {
</p> </p>
<div className="space-y-6 mb-8"> <div className="space-y-6 mb-8">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Email Authentication</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. Email Authentication</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
When an email is received, the server first checks SPF and DKIM authentication. At least one of these must When an email is received, the server first checks SPF and DKIM authentication. At least one of these must
@@ -40,7 +40,7 @@ export default function WhatIsDMARC() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Alignment Check</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. Alignment Check</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
DMARC checks if the domain in the "From" header aligns with the domain that passed SPF or DKIM. This is DMARC checks if the domain in the "From" header aligns with the domain that passed SPF or DKIM. This is
@@ -48,7 +48,7 @@ export default function WhatIsDMARC() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Policy Application</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. Policy Application</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
If authentication and alignment pass, the email is delivered. If they fail, the receiving server follows If authentication and alignment pass, the email is delivered. If they fail, the receiving server follows
@@ -56,7 +56,7 @@ export default function WhatIsDMARC() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Reporting</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Reporting</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Receiving servers send daily reports to your specified email address, showing authentication results for Receiving servers send daily reports to your specified email address, showing authentication results for
@@ -32,7 +32,7 @@ export default function WhatIsSPF() {
</p> </p>
<div className="space-y-6 mb-8"> <div className="space-y-6 mb-8">
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">1. You Publish an SPF Record</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">1. You Publish an SPF Record</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
You add a TXT record to your domain's DNS that lists all IP addresses and services authorized to send You add a TXT record to your domain's DNS that lists all IP addresses and services authorized to send
@@ -40,7 +40,7 @@ export default function WhatIsSPF() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">2. An Email is Sent</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">2. An Email is Sent</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
When someone sends an email claiming to be from your domain, the receiving server notes the IP address of When someone sends an email claiming to be from your domain, the receiving server notes the IP address of
@@ -48,7 +48,7 @@ export default function WhatIsSPF() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">3. The Receiving Server Checks SPF</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">3. The Receiving Server Checks SPF</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
The receiving server looks up your domain's SPF record in DNS and checks if the sending server's IP The receiving server looks up your domain's SPF record in DNS and checks if the sending server's IP
@@ -56,7 +56,7 @@ export default function WhatIsSPF() {
</p> </p>
</div> </div>
<div className="border-l-4 border-neutral-900 pl-6"> <div className="">
<h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Pass or Fail</h3> <h3 className="text-xl font-semibold text-neutral-900 mb-2">4. Pass or Fail</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
If the IP matches, SPF passes. If not, SPF fails and the email may be flagged as spam or rejected, If the IP matches, SPF passes. If not, SPF fails and the email may be flagged as spam or rejected,
@@ -268,7 +268,7 @@ export default function WhatIsSPF() {
<h2 className="text-3xl font-bold text-neutral-900 mb-6">Common SPF Mistakes to Avoid</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">Common SPF Mistakes to Avoid</h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Multiple SPF Records</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Multiple SPF Records</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Never create multiple SPF TXT records. You can only have ONE SPF record per domain. Combine all authorized Never create multiple SPF TXT records. You can only have ONE SPF record per domain. Combine all authorized
@@ -276,7 +276,7 @@ export default function WhatIsSPF() {
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Exceeding 10 DNS Lookups</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Exceeding 10 DNS Lookups</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Each <code>include:</code> mechanism counts toward the 10 lookup limit. Too many includes will cause SPF Each <code>include:</code> mechanism counts toward the 10 lookup limit. Too many includes will cause SPF
@@ -284,7 +284,7 @@ export default function WhatIsSPF() {
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Forgetting to Update SPF</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Forgetting to Update SPF</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
When you add new email services, remember to update your SPF record. Outdated SPF records cause legitimate When you add new email services, remember to update your SPF record. Outdated SPF records cause legitimate
@@ -292,7 +292,7 @@ export default function WhatIsSPF() {
</p> </p>
</div> </div>
<div className="border-l-4 border-red-500 pl-6 py-2"> <div className="py-2">
<h3 className="text-lg font-semibold text-neutral-900 mb-2"> Using +all</h3> <h3 className="text-lg font-semibold text-neutral-900 mb-2"> Using +all</h3>
<p className="text-neutral-700"> <p className="text-neutral-700">
Never use <code>+all</code> (pass all). This completely defeats the purpose of SPF by allowing anyone to Never use <code>+all</code> (pass all). This completely defeats the purpose of SPF by allowing anyone to
+17 -17
View File
@@ -284,7 +284,7 @@ export default function Index() {
<h1 <h1
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
className={ className={
'text-[clamp(3rem,9vw,8rem)] font-extrabold leading-[0.92] tracking-[-0.04em] text-neutral-900' 'text-[clamp(3rem,9vw,8rem)] font-extrabold leading-none tracking-[-0.04em] text-neutral-900'
} }
> >
The open-source The open-source
@@ -328,7 +328,7 @@ export default function Index() {
viewport={{once: true, margin: '-10%'}} viewport={{once: true, margin: '-10%'}}
transition={{duration: 0.9, delay: 0.25, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.9, delay: 0.25, ease: [0.22, 1, 0.36, 1]}}
className={ className={
'mt-20 grid grid-cols-2 gap-x-8 gap-y-10 border-t border-neutral-200 pt-10 sm:mt-28 sm:grid-cols-4' 'mt-20 grid grid-cols-2 gap-x-12 gap-y-10 border-t border-neutral-200 pt-10 sm:mt-28 sm:grid-cols-4 sm:gap-x-20'
} }
> >
{[ {[
@@ -391,7 +391,7 @@ export default function Index() {
</section> </section>
{/* ========== COMPETITORS — EDITORIAL LIST ========== */} {/* ========== COMPETITORS — EDITORIAL LIST ========== */}
<section className={'mx-auto max-w-[88rem] px-6 py-28 sm:px-10 sm:py-36'}> <section className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10 sm:py-28'}>
<SectionHeader <SectionHeader
number={'02'} number={'02'}
label={'The Alternatives'} label={'The Alternatives'}
@@ -399,7 +399,7 @@ export default function Index() {
subtitle={'One tool in place of Resend, SendGrid, Mailchimp, Customer.io, and Mailgun.'} subtitle={'One tool in place of Resend, SendGrid, Mailchimp, Customer.io, and Mailgun.'}
/> />
<ul className={'mt-20 divide-y divide-neutral-200 border-y border-neutral-200'}> <ul className={'mt-12 divide-y divide-neutral-200 border-y border-neutral-200'}>
{competitors.map((c, i) => ( {competitors.map((c, i) => (
<motion.li <motion.li
key={c.slug} key={c.slug}
@@ -463,7 +463,7 @@ export default function Index() {
subtitle={'Three things Plunk gets right, out of the box.'} subtitle={'Three things Plunk gets right, out of the box.'}
/> />
<div className={'mt-20 grid gap-10 sm:grid-cols-3 sm:gap-16'}> <div className={'mt-20 grid gap-10 sm:grid-cols-3 sm:gap-20 lg:gap-28'}>
{[ {[
{ {
tag: 'Setup', tag: 'Setup',
@@ -523,7 +523,7 @@ export default function Index() {
subtitle={'Every Plunk install ships with the full platform — no upsell pages, no locked modules.'} subtitle={'Every Plunk install ships with the full platform — no upsell pages, no locked modules.'}
/> />
<div className={'mt-20 grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'mt-16 grid gap-5 sm:grid-cols-2 lg:grid-cols-3'}>
{features.map((feature, index) => { {features.map((feature, index) => {
const highlighted = feature.feature; const highlighted = feature.feature;
return ( return (
@@ -535,8 +535,8 @@ export default function Index() {
transition={{duration: 0.5, delay: index * 0.06, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: index * 0.06, ease: [0.22, 1, 0.36, 1]}}
className={ className={
highlighted highlighted
? 'group relative flex min-h-[18rem] flex-col justify-between overflow-hidden rounded-[28px] border border-neutral-900 bg-neutral-900 p-8 text-white' ? 'flex min-h-72 flex-col justify-between overflow-hidden rounded-[28px] border border-neutral-900 bg-neutral-900 p-8 text-white'
: 'group relative flex min-h-[18rem] flex-col justify-between overflow-hidden rounded-[28px] border border-neutral-200 bg-white p-8 transition hover:border-neutral-900' : 'flex min-h-72 flex-col justify-between overflow-hidden rounded-[28px] border border-neutral-200 bg-white p-8 transition hover:border-neutral-900'
} }
> >
<div className={'flex items-start justify-between'}> <div className={'flex items-start justify-between'}>
@@ -622,8 +622,8 @@ export default function Index() {
))} ))}
</div> </div>
<div className={'relative my-12'}> <div className={'relative my-12 hidden lg:block'}>
<svg className={'mx-auto h-28 w-full'} viewBox="0 0 600 120" preserveAspectRatio="xMidYMid meet"> <svg className={'mx-auto h-28 w-full'} viewBox="0 0 600 120" preserveAspectRatio="none">
<defs> <defs>
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"> <marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
<polygon points="0 0, 10 3, 0 6" fill="#a3a3a3" /> <polygon points="0 0, 10 3, 0 6" fill="#a3a3a3" />
@@ -734,7 +734,7 @@ export default function Index() {
subtitle={'AGPL-3.0 licensed, EU-hosted, GDPR compliant. Inspect the code, self-host, or use our cloud.'} subtitle={'AGPL-3.0 licensed, EU-hosted, GDPR compliant. Inspect the code, self-host, or use our cloud.'}
/> />
<div className={'mt-20 grid gap-6 sm:grid-cols-3'}> <div className={'mt-14 grid gap-5 sm:grid-cols-3'}>
{[ {[
{ {
icon: <PackageOpen className="h-8 w-8" strokeWidth={1.25} />, icon: <PackageOpen className="h-8 w-8" strokeWidth={1.25} />,
@@ -801,7 +801,7 @@ export default function Index() {
{/* ========== PRICING — BIG MOMENT ========== */} {/* ========== PRICING — BIG MOMENT ========== */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-28 sm:px-10 sm:py-36'}> <div className={'mx-auto max-w-[88rem] px-6 py-40 sm:px-10 sm:py-56'}>
<SectionHeader <SectionHeader
number={'07'} number={'07'}
label={'Pricing'} label={'Pricing'}
@@ -815,7 +815,7 @@ export default function Index() {
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}}
className={'mt-20 text-center'} className={'mt-24 text-center'}
> >
<div className={'flex items-baseline justify-center gap-3 text-neutral-900'}> <div className={'flex items-baseline justify-center gap-3 text-neutral-900'}>
<span <span
@@ -899,7 +899,7 @@ export default function Index() {
subtitle={'No hyperbole. Just the people building products on Plunk.'} subtitle={'No hyperbole. Just the people building products on Plunk.'}
/> />
<div className={'mt-20 grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'mt-16 grid gap-5 sm:grid-cols-2 lg:grid-cols-3'}>
{testimonials.map((t, i) => { {testimonials.map((t, i) => {
const highlighted = t.featured; const highlighted = t.featured;
return ( return (
@@ -911,8 +911,8 @@ export default function Index() {
transition={{duration: 0.5, delay: i * 0.06, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: i * 0.06, ease: [0.22, 1, 0.36, 1]}}
className={ className={
highlighted highlighted
? 'flex min-h-[18rem] flex-col justify-between rounded-[28px] border border-neutral-900 bg-neutral-900 p-8 text-white' ? 'flex min-h-72 flex-col justify-between rounded-[28px] border border-neutral-900 bg-neutral-900 p-8 text-white'
: 'flex min-h-[18rem] flex-col justify-between rounded-[28px] border border-neutral-200 bg-white p-8' : 'flex min-h-72 flex-col justify-between rounded-[28px] border border-neutral-200 bg-white p-8'
} }
> >
<blockquote <blockquote
@@ -1000,7 +1000,7 @@ export default function Index() {
'inline-flex items-center gap-2 rounded-full border border-neutral-700 px-7 py-3.5 text-sm font-semibold text-white transition hover:border-white' 'inline-flex items-center gap-2 rounded-full border border-neutral-700 px-7 py-3.5 text-sm font-semibold text-white transition hover:border-white'
} }
> >
Read documentation Read the docs
</Link> </Link>
</div> </div>
</motion.div> </motion.div>
+21 -30
View File
@@ -1,6 +1,6 @@
import {NextSeo} from 'next-seo'; import {NextSeo} from 'next-seo';
import React from 'react'; import React from 'react';
import {Footer, Navbar} from '../components'; import {Footer, Navbar, SectionHeader} from '../components';
import {motion} from 'framer-motion'; import {motion} from 'framer-motion';
import {DASHBOARD_URI} from '../lib/constants'; import {DASHBOARD_URI} from '../lib/constants';
import { import {
@@ -228,42 +228,33 @@ export default function Pricing() {
{/* Every feature included */} {/* Every feature included */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}>
<motion.div <SectionHeader
initial={{opacity: 0, y: 20}} number={'01'}
whileInView={{opacity: 1, y: 0}} label={'Included'}
viewport={{once: true}} title={'Every feature, every plan.'}
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} subtitle={'No feature tiers, no add-ons, no surprises.'}
className={'mb-16 text-center'} />
>
<h2
style={{fontFamily: 'var(--font-display)'}}
className={
'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'
}
>
Every feature on every plan
</h2>
<p className={'mt-4 text-lg text-neutral-600'}>No feature tiers, no add-ons, no surprises</p>
</motion.div>
<div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}> <ul className={'mt-16 divide-y divide-neutral-200 border-y border-neutral-200'}>
{includedFeatures.map((feature, index) => ( {includedFeatures.map((feature, index) => (
<motion.div <motion.li
key={feature.title} key={feature.title}
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 12}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.05, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: index * 0.04, ease: [0.22, 1, 0.36, 1]}}
className={'group bg-white p-10 transition hover:bg-neutral-50'} className={'grid gap-3 py-7 sm:grid-cols-[1fr_2fr] sm:items-baseline sm:gap-12 sm:py-8'}
> >
<div className={'flex h-12 w-12 items-center justify-center rounded-xl bg-neutral-900 text-white'}> <h3
{feature.icon} style={{fontFamily: 'var(--font-display)'}}
</div> className={'text-base font-semibold text-neutral-900'}
<h3 className={'mt-6 text-lg font-semibold text-neutral-900'}>{feature.title}</h3> >
<p className={'mt-2 text-sm leading-relaxed text-neutral-600'}>{feature.description}</p> {feature.title}
</motion.div> </h3>
<p className={'text-sm leading-relaxed text-neutral-600'}>{feature.description}</p>
</motion.li>
))} ))}
</div> </ul>
</div> </div>
</section> </section>
@@ -205,7 +205,7 @@ export default function VerifyEmailPage() {
subtitle={'Invalid addresses hurt deliverability. Verification keeps your list clean before you send.'} subtitle={'Invalid addresses hurt deliverability. Verification keeps your list clean before you send.'}
/> />
<div className={'mt-20 grid gap-4 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'mt-20 grid gap-6 sm:grid-cols-2 lg:grid-cols-3'}>
{EMAIL_VERIFICATION_FEATURES.map((feature, index) => { {EMAIL_VERIFICATION_FEATURES.map((feature, index) => {
const Icon = feature.icon; const Icon = feature.icon;
return ( return (
@@ -216,7 +216,7 @@ export default function VerifyEmailPage() {
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.5, delay: index * 0.05, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.5, delay: index * 0.05, ease: [0.22, 1, 0.36, 1]}}
className={ className={
'flex min-h-[14rem] flex-col justify-between rounded-[28px] border border-neutral-200 bg-white p-8 transition hover:border-neutral-900' 'flex flex-col gap-8 rounded-[20px] border border-neutral-200 bg-white p-8 transition hover:border-neutral-900'
} }
> >
<div className={'text-neutral-900'}> <div className={'text-neutral-900'}>
@@ -225,7 +225,7 @@ export default function VerifyEmailPage() {
<div> <div>
<h3 <h3
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
className={'mt-10 text-xl font-bold tracking-[-0.02em] text-neutral-900'} className={'text-xl font-bold tracking-[-0.02em] text-neutral-900'}
> >
{feature.title} {feature.title}
</h3> </h3>
+7 -7
View File
@@ -97,8 +97,8 @@ export default function ActiveCampaignComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
Enterprise Features Without Enterprise Prices Enterprise Features Without Enterprise Prices
</h2> </h2>
@@ -133,8 +133,8 @@ export default function ActiveCampaignComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Automation Without Complexity</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Automation Without Complexity</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Powerful email workflows without the enterprise overhead</p> <p className={'mt-4 text-lg text-neutral-600'}>Powerful email workflows without the enterprise overhead</p>
</motion.div> </motion.div>
@@ -159,8 +159,8 @@ export default function ActiveCampaignComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="ActiveCampaign" rows={comparisonData} /> <ComparisonTable competitorName="ActiveCampaign" rows={comparisonData} />
@@ -172,7 +172,7 @@ export default function ActiveCampaignComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Email automation, not enterprise complexity. Email automation, not enterprise complexity.
+7 -7
View File
@@ -97,8 +97,8 @@ export default function BentoComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
Focused Email vs All-in-One Complexity Focused Email vs All-in-One Complexity
</h2> </h2>
@@ -133,8 +133,8 @@ export default function BentoComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Developer-First Email Platform</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Developer-First Email Platform</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Everything you need for email, nothing you don't</p> <p className={'mt-4 text-lg text-neutral-600'}>Everything you need for email, nothing you don't</p>
</motion.div> </motion.div>
@@ -158,8 +158,8 @@ export default function BentoComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Bento" rows={comparisonData} /> <ComparisonTable competitorName="Bento" rows={comparisonData} />
@@ -171,7 +171,7 @@ export default function BentoComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Focused email. No bloat. Focused email. No bloat.
+7 -7
View File
@@ -99,8 +99,8 @@ export default function BrevoComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
Pricing That Scales With You Pricing That Scales With You
</h2> </h2>
@@ -135,8 +135,8 @@ export default function BrevoComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Choose Plunk Over Brevo</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Choose Plunk Over Brevo</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Focus on email, not feature overload</p> <p className={'mt-4 text-lg text-neutral-600'}>Focus on email, not feature overload</p>
</motion.div> </motion.div>
@@ -182,8 +182,8 @@ export default function BrevoComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Brevo" rows={comparisonData} /> <ComparisonTable competitorName="Brevo" rows={comparisonData} />
@@ -195,7 +195,7 @@ export default function BrevoComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Make the switch to simplicity Make the switch to simplicity
+7 -7
View File
@@ -100,8 +100,8 @@ export default function ConvertkitComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
Pay for Emails, Not Subscribers Pay for Emails, Not Subscribers
</h2> </h2>
@@ -136,8 +136,8 @@ export default function ConvertkitComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Built for Developers, Not Creators</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Built for Developers, Not Creators</h2>
</motion.div> </motion.div>
<div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}>
@@ -182,8 +182,8 @@ export default function ConvertkitComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="ConvertKit" rows={comparisonData} /> <ComparisonTable competitorName="ConvertKit" rows={comparisonData} />
@@ -195,7 +195,7 @@ export default function ConvertkitComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Ready for a developer-first email platform? Ready for a developer-first email platform?
+7 -7
View File
@@ -95,8 +95,8 @@ export default function CustomerioComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
Simple Pricing That Scales Simple Pricing That Scales
</h2> </h2>
@@ -131,8 +131,8 @@ export default function CustomerioComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Key Advantages</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Key Advantages</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Why developers choose Plunk</p> <p className={'mt-4 text-lg text-neutral-600'}>Why developers choose Plunk</p>
</motion.div> </motion.div>
@@ -178,8 +178,8 @@ export default function CustomerioComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Customer.io" rows={comparisonData} /> <ComparisonTable competitorName="Customer.io" rows={comparisonData} />
@@ -191,7 +191,7 @@ export default function CustomerioComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Try Plunk free Try Plunk free
+17 -15
View File
@@ -157,13 +157,13 @@ export default function CompetitorsIndex() {
{/* Competitors grid */} {/* Competitors grid */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:px-10 sm:py-24'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-16'} className={'mb-10'}
> >
<h2 <h2
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -185,7 +185,7 @@ export default function CompetitorsIndex() {
> >
<Link <Link
href={`/vs/${competitor.slug}`} href={`/vs/${competitor.slug}`}
className={'group flex min-h-[14rem] flex-col justify-between rounded-[28px] border border-neutral-200 bg-white p-8 transition hover:border-neutral-900'} className={'group flex flex-col justify-between rounded-[28px] border border-neutral-200 bg-white p-6 sm:p-8 transition hover:border-neutral-900'}
> >
<div className={'flex items-start justify-between'}> <div className={'flex items-start justify-between'}>
<h3 <h3
@@ -198,15 +198,17 @@ export default function CompetitorsIndex() {
</div> </div>
<div> <div>
<p className={'text-sm text-neutral-600'}>{competitor.description}</p> <p className={'text-sm text-neutral-600'}>{competitor.description}</p>
<div className={'mt-4 flex flex-wrap gap-1.5'}> <div className={'mt-4 flex flex-wrap items-center gap-x-2 gap-y-1'}>
{competitor.features.map(feature => ( {competitor.features.map((feature, i) => (
<span <React.Fragment key={feature}>
key={feature} {i > 0 && <span className={'text-neutral-300'} aria-hidden>·</span>}
style={{fontFamily: 'var(--font-mono)'}} <span
className={'text-[10px] uppercase tracking-[0.12em] text-neutral-400'} style={{fontFamily: 'var(--font-mono)'}}
> className={'text-[10px] uppercase tracking-[0.12em] text-neutral-400'}
{feature} >
</span> {feature}
</span>
</React.Fragment>
))} ))}
</div> </div>
</div> </div>
@@ -219,13 +221,13 @@ export default function CompetitorsIndex() {
{/* Why Plunk */} {/* Why Plunk */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-14 sm:px-10 sm:py-20'}>
<motion.div <motion.div
initial={{opacity: 0, y: 20}} initial={{opacity: 0, y: 20}}
whileInView={{opacity: 1, y: 0}} whileInView={{opacity: 1, y: 0}}
viewport={{once: true}} viewport={{once: true}}
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-16'} className={'mb-10'}
> >
<h2 <h2
style={{fontFamily: 'var(--font-display)'}} style={{fontFamily: 'var(--font-display)'}}
@@ -280,7 +282,7 @@ export default function CompetitorsIndex() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 <motion.h2
initial={{opacity: 0, y: 16}} initial={{opacity: 0, y: 16}}
+7 -7
View File
@@ -97,8 +97,8 @@ export default function KlaviyoComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
E-commerce Email Without the Premium Price E-commerce Email Without the Premium Price
</h2> </h2>
@@ -133,8 +133,8 @@ export default function KlaviyoComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>E-commerce Email, Developer-Friendly</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>E-commerce Email, Developer-Friendly</h2>
<p className={'mt-4 text-lg text-neutral-600'}>All the automation power, at a fraction of the cost</p> <p className={'mt-4 text-lg text-neutral-600'}>All the automation power, at a fraction of the cost</p>
</motion.div> </motion.div>
@@ -159,8 +159,8 @@ export default function KlaviyoComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Klaviyo" rows={comparisonData} /> <ComparisonTable competitorName="Klaviyo" rows={comparisonData} />
@@ -172,7 +172,7 @@ export default function KlaviyoComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
E-commerce email at a fraction of the cost. E-commerce email at a fraction of the cost.
+7 -7
View File
@@ -99,8 +99,8 @@ export default function LoopsComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
Transparent Pricing vs Vendor Lock-In Transparent Pricing vs Vendor Lock-In
</h2> </h2>
@@ -135,8 +135,8 @@ export default function LoopsComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Choose Plunk Over Loops</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Choose Plunk Over Loops</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Open-source transparency meets modern SaaS features</p> <p className={'mt-4 text-lg text-neutral-600'}>Open-source transparency meets modern SaaS features</p>
</motion.div> </motion.div>
@@ -182,8 +182,8 @@ export default function LoopsComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Loops" rows={comparisonData} /> <ComparisonTable competitorName="Loops" rows={comparisonData} />
@@ -195,7 +195,7 @@ export default function LoopsComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Switch to open source Switch to open source
+7 -7
View File
@@ -100,8 +100,8 @@ export default function MailchimpComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
The Pricing Model That Makes Sense The Pricing Model That Makes Sense
</h2> </h2>
@@ -138,8 +138,8 @@ export default function MailchimpComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Developers Choose Plunk</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Developers Choose Plunk</h2>
</motion.div> </motion.div>
<div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}>
@@ -184,8 +184,8 @@ export default function MailchimpComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Mailchimp" rows={comparisonData} /> <ComparisonTable competitorName="Mailchimp" rows={comparisonData} />
@@ -197,7 +197,7 @@ export default function MailchimpComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Ready for a better developer experience? Ready for a better developer experience?
+7 -7
View File
@@ -97,8 +97,8 @@ export default function MailerliteComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
Open Source Meets Developer Experience Open Source Meets Developer Experience
</h2> </h2>
@@ -133,8 +133,8 @@ export default function MailerliteComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>The Truly Developer-First Alternative</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>The Truly Developer-First Alternative</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Full control, transparent code, pay only for what you send</p> <p className={'mt-4 text-lg text-neutral-600'}>Full control, transparent code, pay only for what you send</p>
</motion.div> </motion.div>
@@ -159,8 +159,8 @@ export default function MailerliteComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="MailerLite" rows={comparisonData} /> <ComparisonTable competitorName="MailerLite" rows={comparisonData} />
@@ -172,7 +172,7 @@ export default function MailerliteComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Experience true developer-first email. Experience true developer-first email.
+7 -7
View File
@@ -95,8 +95,8 @@ export default function MailgunComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
The Pricing Model That Makes Sense The Pricing Model That Makes Sense
</h2> </h2>
@@ -131,8 +131,8 @@ export default function MailgunComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>What Plunk Adds</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>What Plunk Adds</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Beyond transactional emails</p> <p className={'mt-4 text-lg text-neutral-600'}>Beyond transactional emails</p>
</motion.div> </motion.div>
@@ -178,8 +178,8 @@ export default function MailgunComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Mailgun" rows={comparisonData} /> <ComparisonTable competitorName="Mailgun" rows={comparisonData} />
@@ -191,7 +191,7 @@ export default function MailgunComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Try Plunk free Try Plunk free
+7 -7
View File
@@ -96,8 +96,8 @@ export default function PostmarkComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
One Platform for All Your Emails One Platform for All Your Emails
</h2> </h2>
@@ -132,8 +132,8 @@ export default function PostmarkComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Choose Plunk Over Postmark</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Choose Plunk Over Postmark</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Do more with one platform instead of two</p> <p className={'mt-4 text-lg text-neutral-600'}>Do more with one platform instead of two</p>
</motion.div> </motion.div>
@@ -179,8 +179,8 @@ export default function PostmarkComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Postmark" rows={comparisonData} /> <ComparisonTable competitorName="Postmark" rows={comparisonData} />
@@ -192,7 +192,7 @@ export default function PostmarkComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Get more from your email platform Get more from your email platform
+7 -7
View File
@@ -95,8 +95,8 @@ export default function ResendComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
The Pricing Model That Makes Sense The Pricing Model That Makes Sense
</h2> </h2>
@@ -131,8 +131,8 @@ export default function ResendComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>What Plunk Adds</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>What Plunk Adds</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Beyond transactional emails</p> <p className={'mt-4 text-lg text-neutral-600'}>Beyond transactional emails</p>
</motion.div> </motion.div>
@@ -178,8 +178,8 @@ export default function ResendComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="Resend" rows={comparisonData} /> <ComparisonTable competitorName="Resend" rows={comparisonData} />
@@ -191,7 +191,7 @@ export default function ResendComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Try Plunk free Try Plunk free
+7 -7
View File
@@ -99,8 +99,8 @@ export default function SendGridComparison() {
{/* Pricing comparison */} {/* Pricing comparison */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>
The Pricing Model That Makes Sense The Pricing Model That Makes Sense
</h2> </h2>
@@ -135,8 +135,8 @@ export default function SendGridComparison() {
{/* Key advantages */} {/* Key advantages */}
<section className={'border-t border-neutral-200 bg-neutral-50/60'}> <section className={'border-t border-neutral-200 bg-neutral-50/60'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Choose Plunk Over SendGrid</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Why Choose Plunk Over SendGrid</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Built for modern developers, not enterprise sales teams</p> <p className={'mt-4 text-lg text-neutral-600'}>Built for modern developers, not enterprise sales teams</p>
</motion.div> </motion.div>
@@ -182,8 +182,8 @@ export default function SendGridComparison() {
{/* Feature comparison table */} {/* Feature comparison table */}
<section className={'border-t border-neutral-200'}> <section className={'border-t border-neutral-200'}>
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}> <div className={'mx-auto max-w-[88rem] px-6 py-16 sm:py-20 sm:px-10'}>
<motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-16'}> <motion.div initial={{opacity: 0, y: 20}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} className={'mb-10'}>
<h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2> <h2 style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}>Feature comparison</h2>
</motion.div> </motion.div>
<ComparisonTable competitorName="SendGrid" rows={comparisonData} /> <ComparisonTable competitorName="SendGrid" rows={comparisonData} />
@@ -195,7 +195,7 @@ export default function SendGridComparison() {
{/* CTA */} {/* CTA */}
<section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}> <section className={'relative overflow-hidden border-t border-neutral-900 bg-neutral-900 text-white'}>
<div className={'mx-auto max-w-[88rem] px-6 py-32 sm:px-10 sm:py-40'}> <div className={'mx-auto max-w-[88rem] px-6 py-24 sm:px-10 sm:py-32'}>
<div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}> <div className={'flex flex-col items-start gap-12 lg:flex-row lg:items-end lg:justify-between'}>
<motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}> <motion.h2 initial={{opacity: 0, y: 16}} whileInView={{opacity: 1, y: 0}} viewport={{once: true}} transition={{duration: 0.9, ease: [0.22, 1, 0.36, 1]}} style={{fontFamily: 'var(--font-display)'}} className={'text-[clamp(2.5rem,7vw,6rem)] font-extrabold leading-[0.95] tracking-[-0.035em]'}>
Make the switch today Make the switch today