- RichText.tsx: Lexical's auto-detected "autolink" nodes (a typed-out
email/URL, as opposed to an editor-inserted link) fell through to
Payload's unstyled default converter — only "link" was overridden.
AGB's Vertragspartner email rendered as plain black text because of
this. Both node types now get the same text-brand/hover:underline
treatment.
- Breadcrumb color revert: the breadcrumb Startseite links across the
4 legal pages/shop should stay their original hover:text-brand
treatment — only the actual content/contact links needed the
always-brand-colored style, not page-level breadcrumbs.
- /blog was the one page missing both a breadcrumb and the
text-h-feature heading size every other section page (/shop, legal
pages) already uses — added to match.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018unaXmuzVA8ct1b6WoyP1U
- Cart badge pulsed on every page load/reload, not just real cart
changes — useCartCount's SSR snapshot is always 0, so hydration alone
satisfied the "count increased" check. Skip the very first effect run.
- WishlistButton: touch-device smaller/subtler sizing now applies
regardless of revealOnHover (e.g. the homepage spotlight heart), not
just the shop grid's hover-reveal mode.
- /blog: the big featured-style hero card was applied to whatever post
sorted first post-filter, even when that post isn't actually the
`featured` one (a category filter can exclude the real featured post
entirely). Now gated on the post's own `featured` flag.
- Legal pages' "Startseite" breadcrumb link now matches the same
text-brand/hover:underline treatment already used elsewhere on these
pages (e.g. Impressum's Anbieter email link), instead of staying muted
until hover.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018unaXmuzVA8ct1b6WoyP1U
- CustomSelect.tsx: mousedown on an option blurred the trigger button
before the click landed, unmounting the list before anything could be
selected — add preventDefault on the list's mousedown to stop that.
- KontoShell no longer renders "Eingeloggt als ..." above each page's
content; each page renders its own title then AccountIdentity right
below it, and ProfileForm's now-duplicate email/Kundennummer line is
removed.
- Blog category filter: drop the separate "Zurücksetzen" link — clicking
an active category badge again already deactivates it.
- Werkzeuge cards: more vertical gap between stacked cards below sm:.
- Legal pages' "Stand: ..." line is now derived from the LegalPages doc's
own updatedAt instead of a hand-typed string.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018unaXmuzVA8ct1b6WoyP1U
- api/checkout/route.ts: authoritative shipping charge is 0 whenever
every cart line opts out via noShippingCost, regardless of the
free-shipping threshold.
- Cart/checkout order summaries: the whole "Versand" line (cost, free-
shipping note, delivery time) is hidden entirely rather than showing
"Kostenlos" — that's a different state from hitting the threshold.
- ProductSpotlight/Pricing/TodoKartenHero: "zzgl. Versand" and delivery-
time hints drop for an exempted product's own page.
- /versand + its shared modal: one clarifying sentence that digital
products are exempt.
- Widerrufsformular link: opens inline in a new tab (no forced download),
arrow icon changed from a download glyph to a plain right arrow to
match.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The "An:" address used to be baked into a hand-crafted PDF and silently
went stale whenever an admin updated the Impressum's Anbieterdaten
without also re-exporting/re-uploading the file by hand — exactly what
happened 2026-07-29. New /api/muster-widerrufsformular route renders it
on-the-fly via @react-pdf/renderer using the same getCompanySettings()
data as AnbieterAngaben.tsx's Impressum block, so the two can never drift
apart again. Disables react-pdf's default hyphenation, which otherwise
split the seller's email address mid-word to fit the line.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- PopIn (Home Hero's brand dot) switched from whileInView to animate — its
translate-based entrance could push the element off-screen on a narrow
phone before the IntersectionObserver ever saw it as visible, leaving it
stuck invisible permanently.
- Hero image: no longer wrapped in Reveal below lg: — whileInView's margin
meant it stayed at opacity:0 (a white gap above the fold) on short mobile
viewports until scrolled. Reveal's fade-in kept from lg: up.
- "→ Label" CTA links (Tools.tsx, Blog.tsx) now use a flex row with the
arrow as its own span instead of a literal inline "→" character, which
doesn't reliably align to the surrounding text's cap-height.
- Replaced icon-arrow-connector.svg with a new shared StepArrow component
(inline SVG) across all three step sections — the old asset's color
couldn't be overridden from outside the SVG file, so it could never
actually become brand-orange. Bigger and better-shaped below the
structural breakpoint per feedback.
- Added MobileSectionTOC (SectionTOC.tsx) — a <details> accordion shown
below lg: on Impressum/Datenschutz/AGB/Widerruf/Versand, which previously
had no on-page navigation aid at all below lg: (the sidebar TOC is
`hidden` entirely there).
- Updated the figma-to-nextjs skill with 8 new dated Gotchas from this
mobile-responsive pass, and expanded Step 6's verification checklist.
- README: new "Mobile responsive pass" section summarizing the above.
payload.ts's mapping functions/types are also imported by "use client"
components (LiveTestimonialsGrid, LivePostContent) — importing
next/headers anywhere in that module made it unbundlable for the client,
breaking the production build. draftMode() is now only ever called in the
Server Component pages themselves; they pass the resulting boolean into
getPostBySlug/getLegalPage/getTestimonials as a plain `draft` option.
Testimonials on /todo-cards, /newsletter, /challenge now come from the new
Payload testimonials collection via a shared TestimonialsGrid component,
instead of 3 separately hardcoded arrays.
Adds Next.js Draft Mode (/api/preview) plus Live-Preview-aware client
wrappers (LiveRichText, LiveTestimonialsGrid, LivePostContent) for posts,
legal pages, and testimonials — mounted only while Draft Mode is enabled,
so ordinary visitors keep getting the plain static components.
Clears every remaining @next/next/no-img-element warning — automatic
responsive srcset, lazy-loading, and format optimization instead of
always loading the original file at full size. Fixed-size icons got
explicit width/height; dynamic-aspect photos got fill inside a
relative wrapper.
- 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>