Moves the Next.js app's contents from new-site/ to the repository root and deletes the previous Hugo site (assets/, content/, themes/, hugo.toml, etc.). Also retires the AWS Amplify config and old Netlify _redirects file — the new site deploys to Vercel. Updates STRATEGY.md path references to drop the new-site/ prefix. LICENSE preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
121 lines
3.6 KiB
TypeScript
121 lines
3.6 KiB
TypeScript
import { Container } from "./container";
|
|
import { Eyebrow, SectionHeading } from "./section-heading";
|
|
import { cn } from "@/lib/cn";
|
|
|
|
export const guarantees = [
|
|
{
|
|
title: "30-day money back",
|
|
body:
|
|
"If your first month on a retainer or block doesn't fit, you get it back. No questions, no exit interview. Risk is on me.",
|
|
},
|
|
{
|
|
title: "30-day bug-fix window",
|
|
body:
|
|
"Bugs in code I ship are fixed at no charge for 30 days after handoff. If it broke under my watch, I own it.",
|
|
},
|
|
{
|
|
title: "One business day response",
|
|
body:
|
|
"Every retainer and block client gets a real reply inside one business day. Not a ticket number, not an out-of-office.",
|
|
},
|
|
{
|
|
title: "You own everything",
|
|
body:
|
|
"Code, docs, infra, accounts. Full IP transfer in writing. No subcontracting, no vendor lock-in, no surprises.",
|
|
},
|
|
];
|
|
|
|
type Props = {
|
|
className?: string;
|
|
/** Use 'compact' for narrower, in-context placement (e.g. inside another section). */
|
|
variant?: "default" | "compact";
|
|
/** Hide the section heading; useful when wrapped in a custom heading. */
|
|
hideHeading?: boolean;
|
|
};
|
|
|
|
export function Guarantees({
|
|
className,
|
|
variant = "default",
|
|
hideHeading = false,
|
|
}: Props) {
|
|
const isCompact = variant === "compact";
|
|
const heading = (
|
|
<SectionHeading
|
|
eyebrow="Promises in writing"
|
|
title="Four guarantees on every engagement."
|
|
subtitle="The senior-freelance market is full of vague promises. Here are mine, written down so we both have them."
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<section
|
|
className={cn(
|
|
isCompact ? "py-16" : "border-y border-line/70 bg-cream-soft py-24 sm:py-32",
|
|
className,
|
|
)}
|
|
>
|
|
<Container>
|
|
{!hideHeading ? heading : null}
|
|
<ul
|
|
className={cn(
|
|
"grid gap-6",
|
|
isCompact
|
|
? "mt-10 sm:grid-cols-2"
|
|
: "mt-14 sm:grid-cols-2 lg:grid-cols-4",
|
|
)}
|
|
>
|
|
{guarantees.map((g, i) => (
|
|
<li
|
|
key={g.title}
|
|
className={cn(
|
|
"rounded-2xl border border-line/80 p-6",
|
|
isCompact ? "bg-cream" : "bg-cream",
|
|
)}
|
|
>
|
|
<div className="flex items-baseline gap-3">
|
|
<span className="font-mono text-sm text-accent">0{i + 1}</span>
|
|
<h3 className="font-serif text-lg font-semibold text-ink">
|
|
{g.title}
|
|
</h3>
|
|
</div>
|
|
<p className="mt-3 text-sm leading-relaxed text-ink-soft">
|
|
{g.body}
|
|
</p>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</Container>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Inline mini-list of guarantee titles only — for tight spots
|
|
* (e.g. inside the Services pricing area) where the full Guarantees
|
|
* section would be too heavy.
|
|
*/
|
|
export function GuaranteesMini() {
|
|
return (
|
|
<div className="rounded-2xl border border-line/80 bg-cream p-6">
|
|
<div className="flex flex-wrap items-baseline gap-3">
|
|
<Eyebrow>Every engagement includes</Eyebrow>
|
|
</div>
|
|
<ul className="mt-4 grid gap-x-8 gap-y-2 text-sm text-ink sm:grid-cols-2">
|
|
{guarantees.map((g) => (
|
|
<li key={g.title} className="flex items-start gap-2">
|
|
<span aria-hidden="true" className="mt-1 text-accent">
|
|
✓
|
|
</span>
|
|
<span>
|
|
<span className="font-medium">{g.title}.</span>{" "}
|
|
<span className="text-ink-soft">
|
|
{g.body.split(".")[0]}.
|
|
</span>
|
|
</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
);
|
|
}
|