3x3-system: card layout for categories, matrix image, CTA card; lebensuhr fixes

/3x3-system:
- Categories now a 3-card grid (icon + colored top border) instead of
  a plain bulleted list.
- Embeds the original blog post's Arbeit/Familie/Persönlich matrix
  graphic, framed like the challenge page's image, with a caption
  clarifying it's one example application (the surrounding text only
  ever describes 3 categories, not a 3x3 grid).
- Closing CTA is now the same bordered-card link /lebensuhr uses.
- Tightened remaining prose.

/lebensuhr:
- Fixed missing side padding below 640px (the table card's
  full-bleed negative-margin trick ate the page's own padding).
- Added a small decorative clock-face SVG above the table (8 ages
  plotted at their proportional position) — company piece for the
  table, which stays the actual data source.
This commit is contained in:
Marco
2026-08-26 15:36:47 +00:00
parent 9af970587d
commit cdc779aebe
3 changed files with 139 additions and 20 deletions
+85 -19
View File
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import Link from "next/link";
import Image from "next/image";
import { Reveal } from "../components/Reveal";
import { Footer } from "../components/Footer";
@@ -56,10 +57,37 @@ function Quote({ children }: { children: React.ReactNode }) {
);
}
const categories: { dot: string; label: string; desc: string }[] = [
{ dot: "bg-red-500", label: "Verantwortung", desc: "Etwas, das erledigt werden muss und für das du Verantwortung trägst." },
{ dot: "bg-amber-400", label: "Fortschritt", desc: "Etwas, das dich beruflich oder persönlich ein Stück weiterbringt." },
{ dot: "bg-green-500", label: "Stabilität", desc: "Etwas, das deinen Alltag ordnet, deiner Gesundheit guttut oder Gleichgewicht schafft." },
function IconTarget({ color }: { color: string }) {
return (
<svg width="28" height="28" viewBox="0 0 28 28" fill="none">
<circle cx="14" cy="14" r="11" stroke={color} strokeWidth="2" />
<circle cx="14" cy="14" r="6" stroke={color} strokeWidth="2" />
<circle cx="14" cy="14" r="1.5" fill={color} />
</svg>
);
}
function IconTrendingUp({ color }: { color: string }) {
return (
<svg width="28" height="28" viewBox="0 0 28 28" fill="none">
<path d="M4 20l7-7 4 4 9-9" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M17 8h7v7" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
}
function IconShield({ color }: { color: string }) {
return (
<svg width="28" height="28" viewBox="0 0 28 28" fill="none">
<path d="M14 3l9 3.5v6c0 6-4 10.5-9 12.5-5-2-9-6.5-9-12.5v-6L14 3z" stroke={color} strokeWidth="2" strokeLinejoin="round" />
</svg>
);
}
const categories: { color: string; icon: (color: string) => React.ReactNode; label: string; desc: string }[] = [
{ color: "#ef4444", icon: (c) => <IconTarget color={c} />, label: "Verantwortung", desc: "Etwas, das erledigt werden muss und für das du Verantwortung trägst." },
{ color: "#f59e0b", icon: (c) => <IconTrendingUp color={c} />, label: "Fortschritt", desc: "Etwas, das dich beruflich oder persönlich ein Stück weiterbringt." },
{ color: "#22c55e", icon: (c) => <IconShield color={c} />, label: "Stabilität", desc: "Etwas, das deinen Alltag ordnet, deiner Gesundheit guttut oder Gleichgewicht schafft." },
];
export default function DreiXDreiSystemPage() {
@@ -133,17 +161,38 @@ export default function DreiXDreiSystemPage() {
aber die drei, die zählen sollen, wenn der Tag wieder voller wird als geplant. Damit daraus
nicht einfach drei weitere beliebige Aufgaben werden, verteile ich sie auf drei Bereiche:
</P>
<ul className="flex flex-col gap-4">
<div className="grid sm:grid-cols-3 gap-4">
{categories.map((c) => (
<li key={c.label} className="flex items-start gap-3">
<span className={`size-2.5 rounded-full mt-2 shrink-0 ${c.dot}`} aria-hidden />
<p className="text-body text-text-body">
<span className="font-semibold text-text-primary">{c.label}</span> {c.desc}
</p>
</li>
<div key={c.label} className="bg-bg-muted rounded-lg p-5 flex flex-col gap-2 border-t-4" style={{ borderTopColor: c.color }}>
{c.icon(c.color)}
<p className="font-semibold text-text-primary">{c.label}</p>
<p className="text-body-sm text-text-muted">{c.desc}</p>
</div>
))}
</ul>
</div>
<P>Mehr kommt nicht auf diese Liste.</P>
{/* Same rounded-xl framed-image treatment /7-tage-klarheits-check's
"Das erwartet dich" section uses. Shows one concrete
application of the three categories (across Arbeit/Familie/
Persönlich) — an example, not a required 4th dimension of
the system, hence the caption spelling that out rather than
leaving the image to imply a grid the text above never
mentioned. */}
<div className="relative w-full rounded-xl overflow-hidden bg-bg-muted" style={{ aspectRatio: "1500/1000" }}>
<Image
alt="Beispielraster: Verantwortung, Fortschritt und Stabilität je einmal über Arbeit, Familie und Persönliches verteilt"
src="/3x3-system-matrix.png"
fill
sizes="(min-width: 768px) 48rem, 100vw"
className="object-contain"
/>
</div>
<p className="text-body-sm text-text-muted text-center -mt-2">
Ein Beispiel: An diesem Tag steckt die Verantwortung im Job, der Fortschritt in der Familie
und die Stabilität im Privaten. An einem anderen Tag sieht die Verteilung anders aus.
</p>
<P>
Diese drei Punkte sind keine vollständige Tagesplanung. Sie sollen nicht verhindern, dass das
Leben dazwischenkommt sie sorgen nur dafür, dass der Tag eine Richtung hat, bevor andere
@@ -181,14 +230,31 @@ export default function DreiXDreiSystemPage() {
<H2>Du möchtest das 3×3-System selbst ausprobieren?</H2>
<P>
Falls dir das Gefühl gerade bekannt vorkommt: Im{" "}
<Link href="/7-tage-klarheits-check" className="text-brand hover:underline">
7-Tage-Klarheits-Check
</Link>{" "}
begleite ich dich sieben Tage lang beim Einstieg ins 3×3-System keine langen Lektionen,
sondern kurze Impulse, die du direkt im Alltag ausprobieren kannst. Denn genau dort entscheidet
sich, ob eine Idee funktioniert: nicht auf dem Papier, sondern mitten im echten Leben.
Falls dir das Gefühl bekannt vorkommt: Eine Idee zeigt sich nicht auf dem Papier, sondern
mitten im echten Leben.
</P>
{/* Same bordered CTA-card treatment /lebensuhr/page.tsx uses. */}
<Link
href="/7-tage-klarheits-check"
className="group flex items-center justify-between gap-4 border border-border rounded-md px-6 py-5 mt-2 hover:border-brand transition-colors"
>
<div className="flex flex-col gap-1">
<p className="font-bold text-[0.8125rem] text-brand">Nächster Schritt:</p>
<p className="font-semibold text-body text-text-primary" style={{ fontFamily: "var(--font-lora)" }}>
7-Tage-Klarheits-Check
</p>
<p className="text-body-sm text-text-muted">Sieben Tage, kurze Impulse, direkt im Alltag.</p>
</div>
<svg
viewBox="0 0 20 20"
className="size-4 shrink-0 text-text-primary transition-transform duration-200 group-hover:translate-x-1"
fill="none"
aria-hidden="true"
>
<path d="M4 10h12m0 0-5-5m5 5-5 5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</Link>
</Reveal>
</main>
<Footer />
+54 -1
View File
@@ -185,13 +185,66 @@ export default function LebensuhrPage() {
Stell dir vor, dein ganzes Leben wäre auf einen einzigen Tag mit 24 Stunden komprimiert.
Wirst du 90 Jahre alt, sieht das ungefähr so aus:
</P>
{/* Decorative companion to the table below, not a replacement for
it (a version that tried to carry the actual Alter/Uhrzeit
pairs on its own read ambiguous — see the table's own
comment) — just the 8 ages plotted at their proportional
clock position, so the "24 Stunden" framing above has an
actual clock to look at. Coordinates are hand-computed
(evenly spaced every 40°, since age/90 and time/24 are the
same proportion), not derived from lebensuhrRows — if the
rows above ever change, these need updating too. */}
<div className="flex justify-center py-2">
<svg viewBox="0 0 250 250" className="w-full max-w-[16rem] h-auto" aria-hidden="true">
<circle cx="125" cy="125" r="100" stroke="var(--color-border)" strokeWidth="1.5" fill="none" />
{[0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330].map((deg) => {
const rad = (deg * Math.PI) / 180;
const x1 = 125 + 92 * Math.cos(rad), y1 = 125 + 92 * Math.sin(rad);
const x2 = 125 + 100 * Math.cos(rad), y2 = 125 + 100 * Math.sin(rad);
return <line key={deg} x1={x1} y1={y1} x2={x2} y2={y2} stroke="var(--color-border)" strokeWidth="1.5" />;
})}
{([
[10, 175.1, 65.2, 200.8, 34.6, "start"],
[20, 201.8, 111.5, 241.2, 104.5, "start"],
[30, 192.5, 164.0, 227.2, 184.0, "start"],
[40, 151.7, 198.3, 165.4, 235.9, "start"],
[50, 98.3, 198.3, 84.6, 235.9, "end"],
[60, 57.5, 164.0, 22.8, 184.0, "end"],
[70, 48.2, 111.5, 8.8, 104.5, "end"],
[80, 74.9, 65.2, 49.2, 34.6, "end"],
] as [number, number, number, number, number, "start" | "end"][]).map(([age, dx, dy, lx, ly, anchor]) => (
<g key={age}>
<line x1={dx} y1={dy} x2={lx} y2={ly} stroke="var(--color-border)" strokeWidth="1" />
<circle cx={dx} cy={dy} r="4" fill="var(--color-brand)" />
<text
x={lx}
y={ly}
textAnchor={anchor}
dominantBaseline="middle"
className="fill-text-muted"
style={{ fontSize: 12, fontWeight: 600 }}
>
{age}
</text>
</g>
))}
<text x="125" y="118" textAnchor="middle" className="fill-text-primary" style={{ fontFamily: "var(--font-caveat)", fontSize: 24 }}>
dein
</text>
<text x="125" y="142" textAnchor="middle" className="fill-text-primary" style={{ fontFamily: "var(--font-caveat)", fontSize: 24 }}>
Leben
</text>
</svg>
</div>
{/* Still a real table (explicit "Alter"/"Uhrzeit" headers — a
dot-on-a-line version tried here first read ambiguous
without them, and forced a horizontal scroll on mobile for
no gain). Dressed up with the same bg-bg-muted rounded card
the AGB sidebar and blog author box use, brand-colored
header, and zebra rows instead of a bare bordered table. */}
<div className="bg-bg-muted rounded-xl overflow-hidden -mx-[var(--layout-padding-x)] sm:mx-0">
<div className="bg-bg-muted rounded-xl overflow-hidden">
<table className="w-full text-left border-collapse">
<thead>
<tr className="border-b-2 border-brand">
Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 KiB