- Posts collection: new "featured" checkbox (Payload) — /blog now prefers
a manually-featured post over just the most recent one. Query sorts by
"-featured,-publishedAt" so multiple accidentally-featured posts
resolve deterministically (most recent among them wins) instead of
erroring or being ambiguous.
- challenge/page.tsx: step-connector arrow now uses the same
/icon-arrow-connector.svg asset as todo-cards/newsletter's HowItWorks,
replacing its own hand-drawn inline SVG.
- todo-cards & newsletter HowItWorks: connector arrows now vertically
centered on their icon (md:mt-[1.625rem]), matching Challenge's
margin-based centering technique instead of sitting flush at the row's
top edge.
- Blog overview: featured card overlaps the header slightly (-mt-8) per
Figma-inspired refinement, and now also shows the publish date in its
meta row (previously only the list items did).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- app/blog/page.tsx: header (title/subheading + bleeding photo with a
left-edge fade, per Figma node 4577:330), featured-post card (most
recent), remaining posts as a divided list with category/readTime/date,
and the reusable Newsletter signup panel. Uses all real posts from
Payload — the Figma mockup padded its list out to 4 items with two
posts that were never actually seeded, so this only renders what
exists (currently 1 featured + 2 listed).
- lib/payload.ts: BlogPost now carries publishedAt (needed for the list's
per-post date), removed the now-redundant duplicate field on PostDetail.
- Navbar: "Blog" now links to /blog instead of scrolling to the
homepage's #blog anchor — same real-route pattern as "Shop".
- blog/[slug]/page.tsx: earlier title-size tuning (fluid clamp between
text-h-feature and text-display) from this session's follow-up
feedback, not yet pushed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- app/blog/[slug]/page.tsx: article header (category/readTime, Playfair
display title, excerpt, byline), full-bleed hero image, RichText body,
"Passend dazu: ToDo-Karten" cross-promo, author bio card, "Weiterlesen"
related-post card. Widths, fonts, and the Passend-dazu card's
border/padding/spacing were corrected against the actual built Figma
frame (page-blog-detail, node 4667:344, jCCZyh1DGwdjpv1wGge9To) via
get_design_context after a few visually-wrong guesses.
- RichText.tsx: new "quote" case renders Lexical's blockquote feature as
the "Merke dir:" pull-quote — label+underline+divider+Caveat lines,
using the real exported sparkle/underline assets, matching Figma's
actual (background-less) structure instead of a guessed bordered card.
- lib/payload.ts: getPostBySlug() for single-post fetches.
- lib/format.ts: formatDate() — "03. Juli 2025"-style German dates.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace both placeholder images with the actual exports pulled from
the built Figma page-404 (node 4692:341, file jCCZyh1DGwdjpv1wGge9To):
testimonial-photo (4699:372) at full 810x306 resolution, and the
sticky-note-404 (4693:382) — a real photographed/rendered note, not the
hand-coded CSS+Caveat approximation this had before.
- Help-link icon hover: subtle scale-110 zoom (matching Testimonials.tsx's
avatar hover) instead of a color inversion.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Swap the testimonial band's placeholder photo for one cropped directly
from the actual mockup pixels (mockups/einfach-produktiv_mockup_404.png)
instead of reusing an unrelated existing site asset.
- Remove the search bar — no search backend exists to wire it to, so it
was a dead decorative element.
- Add micro-interactions: main CTA arrow slides right on hover, sticky
note un-rotates on hover, help-link cards lift + icon circle inverts to
brand fill + arrow slides right on hover.
- Help-link CTAs ("Zur Startseite" etc.) now text-text-primary (black)
instead of text-brand.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
app/not-found.tsx — root not-found handles all unmatched routes
automatically (Next 16, no global-not-found flag needed for a single
root layout). Hero (Ups. / subheading / CTA) with a natively-drawn
sticky-note illustration (Lora "404" + Caveat handwritten line, no
image asset needed), 3 help links (Startseite/Blog/Werkzeuge), a
decorative search bar (no search backend exists yet to wire it to),
photo+quote testimonial band, TrustRow, Footer. Sets robots: noindex.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
backdrop-filter (backdrop-blur-md, applied to the sticky header once
scrolled) creates a new containing block for position:fixed descendants,
same as transform does. NewsletterModal was rendered inside that header,
so its `fixed inset-0` backdrop silently stopped being fixed to the
viewport once scrolled and became fixed to the 100px header instead,
clipping the modal to the top of the page. Moved the modal to be a
sibling of <header> instead of a child.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- New /widerruf page: CMS-driven content via getLegalPage("widerruf"),
sidebar TOC + "Nachhaltig handeln" callout, TrustRow, and a download
card for the Muster-Widerrufsformular PDF attachment.
- New /agb page, same legal-page shell pattern as Impressum/Datenschutz.
- lib/payload.ts: getLegalPage now also resolves the optional `attachment`
media relation (depth=1) for legal pages that have a downloadable file.
- NewsletterModal: replaced the body overflow/position scroll-lock hacks
(which fought with the sticky Navbar and the global scroll-smooth CSS)
with a wheel/touch event interceptor that never touches scroll position
at all, plus `preventScroll: true` on all modal/drawer focus() calls to
stop the browser's implicit scrollIntoView from nudging the page for
elements near the sticky navbar's reserved scroll-padding-top zone.
Same preventScroll fix applied to VersandModal and the Navbar mobile
drawer for consistency.
- globals.css: scrollbar-gutter: stable, so a modal's overflow:hidden
lock never causes a scrollbar-width layout shift.
- Divider: stagger its reveal animation slightly (delay 0.3s) behind the
section above it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- lib/payload.ts: getLegalPage(type) alongside the existing
getBlogPosts/getProducts fetchers
- New RichText component: small dependency-free Lexical JSON → JSX
renderer for Payload's richText fields (headings get stable
"section-N" ids for anchor/TOC linking)
- New SectionTOC: generalized from VersandTOC into a reusable
scroll-spy sidebar driven by any {id, title}[] — Datenschutz needs one
built from CMS-authored headings, not a hardcoded array. VersandTOC is
now a thin wrapper around it. Sticky positioning moved from the nav
itself to each page's sidebar wrapper, so a TOC and an extra card
(Impressum/Datenschutz both have one) scroll together as one unit
instead of the card drifting away independently
- TOC clicks set the active item immediately and hold it for ~1s over
the scroll-spy observer, covering both "target already fully visible,
nothing to scroll" and "an unrelated section flickers through the
intersection band mid-scroll"
- Both pages follow the same breadcrumb+H1+TOC-sidebar+content layout
established for /versand
Products now come from Payload's new "products" collection instead of a
hardcoded catalog, same pattern already used for blog posts:
- lib/payload.ts: getProducts()/getProductBySlug() (server-side fetch,
60s ISR)
- New /api/products route so client components (CartContent,
RelatedProducts) can reach the same data without a server-only import
- lib/products.ts: useProducts() hook replacing the old PRODUCTS record
- ProductGrid (/shop) fetches server-side directly; now shows all
catalog products except notizbuch-klarheit (matches Figma's 4-card
page-shop-overview — still cross-sold via RelatedProducts)
- ProductSpotlight and /todo-cards' Pricing now pull price/photo from
the same CMS product instead of a separately hardcoded "12,90 €", so
the two can't silently drift apart
- formatPrice moved to a new lib/format.ts (plain, no "use client") —
Server Components can't call functions exported from a "use client"
module directly, which lib/products.ts now is because of the hook
Also fixes two unrelated bugs surfaced along the way: the add-to-cart
button visibly resizing when its "Hinzugefügt ✓" success state showed
(fixed with a CSS-grid text stack sized to the wider of the two
strings), and removes the now-unused local product images from public/.
Shows "Noch X € bis zum kostenlosen Versand" with a progress bar while
below the threshold; briefly confirms "freigeschaltet ✓" on crossing it,
then auto-hides. Re-appears if the subtotal drops back below the
threshold (e.g. after removing an item).
- New /shop overview, /cart (real cart state via useSyncExternalStore),
/versand (shipping policy page with TOC) and /newsletter detail page
- Cart: quantity/removal, order summary, related-products cross-sell
with randomized picks, VersandModal quick-reference instead of
navigating away, MwSt. disclosure next to unit prices
- Add-to-cart UX: inline success feedback (green state) plus a
fly-to-navbar-cart-icon animation (CartFlyProvider) with a delayed
badge count-up; AddToCartButton no longer navigates straight to /cart
- Shared lib/products.ts catalog and lib/shipping.ts constants (cost,
free-shipping threshold, handling/transit days) so cart, trust badges
and the versand page can never drift apart
- Fix Navbar smooth-scroll easing (ease-out instead of ease-in-out, no
more perceived start delay); compress newsletter modal photo
2.4MB -> 85KB to fix first-open jank
New /todo-cards page (Hero, How-it-works, Focus, Testimonials, Pricing)
built with the fluid clamp() token system (app/lib/fluid.ts) and
scroll-reveal animations (app/components/Reveal.tsx), matching styling
consistency with /challenge's testimonial section.
Navbar: page-aware active state and anchor-link navigation from any
route (not just "/"), fixed logo click to actually navigate instead of
silently rewriting the URL, fluid nav text size, custom hash-scroll
handling for cross-page anchor links.
Hero: responsive breakpoint fix for the text/image split at Tablet
widths, entrance animation for the brand's orange dot, removed a red
dot artifact from hero.png.
Also includes prior uncommitted work on About/Blog/Newsletter/Footer
and the cart lib (app/lib/cart.ts).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Blog.tsx now fetches the einfach-produktiv tenant's posts from the
shared Payload instance at build/render time (ISR, 60s revalidate),
via a small typed fetch helper in app/lib/payload.ts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Strategy: one layout breakpoint at lg (1024px), clamp() for fluid type.
Navbar: hamburger menu (animated ✕) with max-h dropdown, resize-close,
h-20 mobile / h-[6.25rem] desktop, blur triggers on scroll or menu-open.
Hero: flex-col→lg:flex-row, clamp(2rem,5vw,4rem) heading, background-image
scales responsively, gradient mask via .hero-mask only at lg+ in CSS.
Divider: flex-wrap + gap-y for smaller screens.
Tools: grid-cols-1→md:2→lg:3, removed fixed height and per-card paddingRight.
Blog: featured flex-col→lg:flex-row, secondary flex-col→md:flex-row,
excerpt hidden on mobile secondary cards to save space.
About: flex-col→lg:flex-row, clamp on quote size, min-h-[18rem] for photo.
Newsletter: flex-col→lg:flex-row, input+button stack on xs / row on sm+.
Footer: flex-col→lg:flex-row, flex-wrap on legal links.
globals.css: scroll-padding-top 5rem mobile / 6.25rem desktop.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Featured had 8px (only content px-2, no card gap).
Secondary had 16px (gap-2 + content p-2 left).
Both now use gap-3 (12px) at card level with no left padding on content.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces browser scroll-behavior:smooth (no duration control) with a
requestAnimationFrame loop using cubic ease-in-out over 800ms. Offset
accounts for navbar height (100px) via getBoundingClientRect + scrollY.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Next.js Link appends hash instead of replacing it (#a#b#b...). Anchor
links now use native <a> with e.preventDefault(), manual scrollIntoView,
and history.replaceState so only the current hash appears in the URL.
Page routes (/shop etc.) still use Link as before.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
flex-1 (shrink:1) let the text column grow past 50% by shrinking the
image. flex-[1_0_0] (shrink:0) matches Figma's flex:1 0 0 so neither
column can shrink — both are exactly half the section width.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Navbar is sticky top-0 z-50. On scroll >8px: bg opacity drops to 80%
and backdrop-blur-md activates with a subtle shadow. Transitions on
background-color and backdrop-filter (300ms). Smooth scrolling via
html { scroll-behavior: smooth } in globals.css.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Werkzeuge→#werkzeuge, Blog→#blog, Über Björn→#ueber-bjoern.
Shop remains /shop (no matching section). Added matching id attributes
to Tools, Blog and About section root elements.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PNG has hard alpha cutoff edges — adds left (0%→14%) and top (0%→10%)
linear-gradient masks via mask-composite:intersect so both edges fade
simultaneously into the cream background, matching Figma's seamless look.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Figma exports the hero image as a PNG with alpha channel — the background
is already transparent. Switched from <img mix-blend-multiply> to a
background-image div (background-size: contain, right center) so the
transparent PNG blends seamlessly into the cream section background with
no visible edge. Background-image also scales better for responsive.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
White/light areas of the photo dissolve into #f5f0e8 without needing
a PNG with alpha transparency.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dark bg (#111). Top divider is a 3px div in #30302c (not a CSS border).
Three justify-between columns: Lora SemiBold logo with gold period (#fdb705),
Lora Regular @handle centered (added weight 400 to Lora config), Inter 14px
legal links with gap-6. Footer sits outside <main> so mt-auto pushes it down.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cream card (bg-[#f8f3ec], rounded-xl) inside section padding of 80px.
Left copy column has fixed w-[38.25rem] (612px) with icon (-rotate-4)
and Lora heading; right form column is flex-1 with email input +
orange submit button side by side, privacy note below. Input and button
share items-stretch so they align to equal height.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two-column layout: left column stacks serif statement above a row of
Caveat quote (flex-1) + 2px golden divider + author bio (shrink-0).
Signature image is absolute-positioned just below the three Caveat lines
(top: 6.44rem = 3 × 32px line-height). Right column is a full-height
overflow-hidden container with object-cover author photo.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fine 1px #d9d9d9 border with rounded-xl on all cards. Featured card
uses overflow-hidden to clip thumbnail flush left; secondary cards give
each thumbnail its own rounded-xl so it sits neatly inside the py-2
padded wrapper. Arrow uses standard → instead of unsupported U+1F816.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>