feat: drawings in circuit style, visible hero digits, hourly booking only on the freelance page

Drawings: "How I work" and the step drawings under "How it runs" now use
the same language as the story thread. Systems and people are chips with
pins, connections are tracks with 45 degree bends and solder points, and
what travels is a bit instead of a round dot (circuit.tsx).

Hero: the digits in the background were close to invisible on white. They
are about twice as strong now, and the ones near the pointer light up indigo.

Homepage vs. freelance page: the homepage is for clients who buy a result,
so it shows three cases. The developer case (100 EUR per hour, booked by the
month) and its steps live on the freelance page only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 11:37:26 +02:00
co-authored by Claude Opus 5.5
parent affd4b7ee7
commit f0c25b802b
11 changed files with 430 additions and 294 deletions
@@ -8,7 +8,7 @@ export const HeroStatement: React.FC<{ hero: Content["hero"] }> = ({
hero,
}) => (
<section className="relative overflow-hidden bg-white">
<div className="absolute inset-0 opacity-70">
<div className="absolute inset-0">
<AbstractCircuit />
</div>
+9 -15
View File
@@ -2,23 +2,26 @@
import * as React from "react";
import { motion } from "framer-motion";
import Link from "next/link";
import { BitAura } from "@/src/components/bits/BitAura";
import { DecodeText } from "@/src/components/bits/DecodeText";
import { PathScene } from "@/src/components/illustrations/PathScenes";
import { useContent, useLocale } from "@/src/components/ContentProvider";
import { pathFor } from "@/src/domain/routes";
import { useContent } from "@/src/components/ContentProvider";
import { TopicButton } from "./TopicButton";
import type { ServicePath } from "@/src/content/types";
const MONO = "font-mono text-[11px] uppercase tracking-[0.2em] text-slate-500";
const STEP_MS = 4800;
/**
* Booked by the hour by a team, not bought as a result: this case is not on the
* homepage. It lives on the freelance page.
*/
const TEAM_PATH = "developer";
/**
* PathStory: the four steps of one path, each with a drawing that explains it.
* The steps advance on their own until the visitor picks one.
*/
const PathStory: React.FC<{ path: ServicePath; active: boolean }> = ({
export const PathStory: React.FC<{ path: ServicePath; active: boolean }> = ({
path,
active,
}) => {
@@ -151,8 +154,7 @@ const PathStory: React.FC<{ path: ServicePath; active: boolean }> = ({
export const PathPicker: React.FC = () => {
const { services } = useContent();
const { estimate } = services;
const locale = useLocale();
const paths = services.paths;
const paths = services.paths.filter((path) => path.id !== TEAM_PATH);
const [activeId, setActiveId] = React.useState(paths[0]?.id ?? "");
return (
@@ -160,7 +162,7 @@ export const PathPicker: React.FC = () => {
<div
role="tablist"
aria-label={services.tablistLabel}
className="grid grid-cols-2 gap-2 md:gap-3 lg:grid-cols-4 lg:gap-4"
className="grid grid-cols-1 gap-2 md:grid-cols-3 md:gap-4"
>
{paths.map((path, index) => {
const selected = path.id === activeId;
@@ -285,14 +287,6 @@ export const PathPicker: React.FC = () => {
</p>
<div className="mt-8 flex flex-col items-start gap-5 md:mt-auto md:pt-8">
<TopicButton topic={path.id}>{estimate.cta}</TopicButton>
{path.id === "developer" && (
<Link
href={pathFor("freelance", locale)}
className="border-b border-slate-900 pb-0.5 font-sans text-base font-bold text-slate-900 no-underline transition-opacity hover:opacity-60"
>
{estimate.freelance} →
</Link>
)}
</div>
</div>
</div>