diff --git a/CLAUDE.md b/CLAUDE.md
index ec92da4..1578a79 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -76,8 +76,9 @@ App lives in `apps/web`. Social media videos live in `apps/video` (Remotion, sta
or person, with pins), `Track` (straight runs, 45 degree bends), `Pad` (solder point), `Bit` (what travels).
New drawings are built from these, not from pills, curves and round dots.
- Two audiences, two pages (owner, 2026-10-05). The homepage is for people who commission a result and have
- no software of their own: a website or process automation (plus web presentations). It shows no prices
- and no hourly terms, only "ask for an offer". Everything for companies that book by the hour is on the
+ no software of their own: a website or process automation (plus web presentations). It shows no project prices
+ and no hourly terms, only "ask for an offer"; the one price there is the care offer for websites (89 EUR
+ per month, see the concept, section 5). Everything for companies that book by the hour is on the
freelance page only: the developer case, making an existing app reliable, how working together goes,
project fit, tools, safeguards, rates and booking. Do not put any of that back on the homepage.
- `DecodeText` is for monospaced text only; in proportional type the changing glyph widths make text jump.
diff --git a/apps/web/plans/freelance-relaunch.md b/apps/web/plans/freelance-relaunch.md
index 4392ce2..c566d36 100644
--- a/apps/web/plans/freelance-relaunch.md
+++ b/apps/web/plans/freelance-relaunch.md
@@ -88,7 +88,20 @@ Audit of an AI-built codebase, test foundation, mutation baseline, prioritized r
- Sprint: time-boxed package (example 40 h, 3,800 EUR) with a clear scope list. Extra work is a follow-up block, not open scope. 50% at start, 50% at launch.
- Site: static Next.js, no CMS, no server, no database.
-- Hosting: managed platform (Cloudflare Pages or Vercel) in my account, flat monthly subscription (example 49-99 EUR) including hosting, SSL, domain renewal at cost, 1 h of changes per month. Deployment: git push builds automatically, client approves via a preview URL by email.
+- Care after the launch (owner decision 2026-10-05, replaces the managed-platform idea): one offer,
+ "Betreuung", 89 EUR per month net, cancel monthly. Hosting on the owner's own servers in Germany (EU
+ hosting matters to German clients; no Vercel or Cloudflare), domain, security and updates, and small
+ changes by email (a text, a picture, opening hours; internally about 30 minutes a month). No CMS and no
+ login for the client. The first three months are included in the project price. Anything bigger (a new
+ page, a new feature) gets a price first. Reply within two working days, no on-call. The client can leave
+ and take everything along.
+- Larger clients: the same care with all non-editorial changes included, about 250 EUR per month (one
+ existing client pays 3,000 EUR a year). Offered in the quote, not listed on the website.
+- CMS only as an exception and at extra cost (file-based first; Payload only when the site lives on
+ maintained data such as a product catalogue).
+- Operations: serve client sites as static files from one shared web server, not one container per client.
+- Not on the website yet: "green hosting". The owner wants it as an argument; state it only once the
+ provider's proof (renewable energy) is at hand.
- Changes: by email or message, no CMS training.
- Domain: client is the registrant; transfer-out and source handover on request.
- **Email and DNS are out of scope.** Never switch nameservers. Only the two records `A/CNAME` for apex and `www` are changed, after exporting the existing records, and mail delivery is checked afterwards. Mailboxes stay with the client's provider.
diff --git a/apps/web/src/components/home/PathPicker.tsx b/apps/web/src/components/home/PathPicker.tsx
index 82ac89c..ba1c7f4 100644
--- a/apps/web/src/components/home/PathPicker.tsx
+++ b/apps/web/src/components/home/PathPicker.tsx
@@ -153,7 +153,7 @@ export const PathPicker: React.FC<{
pricing: "offer" | "estimate";
}> = ({ ids, pricing }) => {
const { services } = useContent();
- const { estimate } = services;
+ const { estimate, care } = services;
const paths = ids.flatMap((id) =>
services.paths.filter((path) => path.id === id),
);
@@ -251,6 +251,53 @@ export const PathPicker: React.FC<{
+ {pricing === "offer" && path.id === "website" && (
+
+
{care.label}
+
+
+
+ {care.title}
+
+
+ {care.text}
+
+
+
+
+ {care.price.label}
+
+
+ {care.price.amount}
+
+
{care.price.note}
+
+
+
+ {[
+ { title: care.includedLabel, items: care.included },
+ { title: care.termsLabel, items: care.terms },
+ ].map((group) => (
+
+
+ {group.title}
+
+
+ {group.items.map((item) => (
+ -
+ {item}
+
+ ))}
+
+
+ ))}
+
+
+ )}
+
{pricing === "offer" ? (
diff --git a/apps/web/src/content/de.ts b/apps/web/src/content/de.ts
index 32ed4ce..8c680d8 100644
--- a/apps/web/src/content/de.ts
+++ b/apps/web/src/content/de.ts
@@ -78,6 +78,30 @@ export const de: Content = {
tablistLabel: "Was brauchen Sie?",
youGet: "Das bekommen Sie",
howItRuns: "So läuft es ab",
+ care: {
+ label: "Nach dem Start",
+ title: "Ich kümmere mich weiter um Ihre Website, wenn Sie das möchten.",
+ text: "Sie müssen kein System bedienen und nichts selbst pflegen. Wenn etwas zu ändern ist, schreiben Sie mir eine E-Mail.",
+ price: {
+ label: "Betreuung",
+ amount: "89 EUR",
+ note: "im Monat, netto, monatlich kündbar",
+ },
+ includedLabel: "Das ist enthalten",
+ included: [
+ "Die Website läuft auf Servern in Deutschland",
+ "Adresse, Sicherheit und Technik sind erledigt",
+ "Kleine Änderungen: ein Text, ein Bild, neue Öffnungszeiten",
+ "Kein Redaktionssystem, kein Login",
+ ],
+ termsLabel: "Gut zu wissen",
+ terms: [
+ "Die ersten drei Monate sind im Projektpreis enthalten.",
+ "Größeres, etwa eine neue Seite, bekommt vorher einen Preis.",
+ "Ich antworte innerhalb von zwei Werktagen. Eine Rufbereitschaft gibt es nicht.",
+ "Wenn Sie gehen möchten, bekommen Sie alles mit. Die Website gehört Ihnen.",
+ ],
+ },
offer: {
title: "Sie bekommen ein Angebot, bevor etwas kostet.",
text: "Schreiben Sie mir kurz, was Sie brauchen. Wir sprechen etwa 20 Minuten, danach bekommen Sie ein schriftliches Angebot. Ich fange erst an, wenn Sie zugestimmt haben.",
@@ -252,7 +276,7 @@ export const de: Content = {
],
orientation: "Ab 3.800 EUR, einmalig",
orientationNote:
- "Das gilt für eine typische Unternehmenswebsite. Hosting und kleine Änderungen danach kosten einen monatlichen Betrag, den wir vor dem Start vereinbaren.",
+ "Das gilt für eine typische Unternehmenswebsite. Die Betreuung danach kostet 89 EUR im Monat.",
},
],
scenes: {
@@ -769,7 +793,7 @@ export const de: Content = {
{
question: "Wer kümmert sich danach um die Website?",
answer:
- "Ich, wenn Sie das möchten. Hosting und kleine Änderungen danach kosten einen monatlichen Betrag, den wir vor dem Start vereinbaren. E-Mail-Postfächer bleiben bei Ihrem Anbieter.",
+ "Ich, wenn Sie das möchten. Für 89 EUR im Monat läuft die Website auf Servern in Deutschland, und kleine Änderungen sind enthalten: Sie schreiben mir eine E-Mail. Ein Redaktionssystem brauchen Sie nicht. E-Mail-Postfächer bleiben bei Ihrem Anbieter.",
},
{
question: "Wie erreiche ich Sie?",
diff --git a/apps/web/src/content/en.ts b/apps/web/src/content/en.ts
index fce618d..139d590 100644
--- a/apps/web/src/content/en.ts
+++ b/apps/web/src/content/en.ts
@@ -77,6 +77,30 @@ export const en: Content = {
tablistLabel: "What do you need?",
youGet: "What you get",
howItRuns: "How it runs",
+ care: {
+ label: "After the launch",
+ title: "I keep looking after your website, if you want that.",
+ text: "You do not have to operate a system or maintain anything yourself. When something needs to change, you write me an email.",
+ price: {
+ label: "Care",
+ amount: "89 EUR",
+ note: "per month, net, cancel monthly",
+ },
+ includedLabel: "What is included",
+ included: [
+ "The website runs on servers in Germany",
+ "Address, security and technology are taken care of",
+ "Small changes: a text, a picture, new opening hours",
+ "No editing system, no login",
+ ],
+ termsLabel: "Good to know",
+ terms: [
+ "The first three months are included in the project price.",
+ "Anything bigger, such as a new page, gets a price first.",
+ "I reply within two working days. There is no on-call service.",
+ "If you want to leave, you take everything with you. The website is yours.",
+ ],
+ },
offer: {
title: "You get an offer before anything costs money.",
text: "Write me briefly what you need. We talk for about 20 minutes, then you get a written offer. I only start once you have agreed.",
@@ -248,7 +272,7 @@ export const en: Content = {
],
orientation: "From 3,800 EUR, one-off",
orientationNote:
- "This is for a typical company website. Hosting and small changes afterwards cost a monthly fee that we agree on before we start.",
+ "This is for a typical company website. Care afterwards costs 89 EUR per month.",
},
],
scenes: {
@@ -749,7 +773,7 @@ export const en: Content = {
{
question: "Who looks after the website afterwards?",
answer:
- "I do, if you want that. Hosting and small changes afterwards cost a monthly fee that we agree on before we start. Email inboxes stay with your provider.",
+ "I do, if you want that. For 89 EUR per month the website runs on servers in Germany, and small changes are included: you write me an email. You do not need an editing system. Email inboxes stay with your provider.",
},
{
question: "How do I reach you?",
diff --git a/apps/web/src/content/types.ts b/apps/web/src/content/types.ts
index b836b4d..f8af0e1 100644
--- a/apps/web/src/content/types.ts
+++ b/apps/web/src/content/types.ts
@@ -188,6 +188,18 @@ export type Content = {
readonly tablistLabel: string;
readonly youGet: string;
readonly howItRuns: string;
+ /** What happens to a website after it is live: the care offer, with its price. */
+ readonly care: {
+ readonly label: string;
+ readonly title: string;
+ readonly text: string;
+ readonly price: PathPrice;
+ readonly includedLabel: string;
+ readonly included: readonly string[];
+ readonly termsLabel: string;
+ /** The limits, said plainly. */
+ readonly terms: readonly string[];
+ };
/** The homepage's way to a price: ask for an offer. No figures there. */
readonly offer: TitledText & { readonly cta: string };
/** How a visitor gets to a price: the homepage shows this instead of a price list. */