Commit Graph

252 Commits

Author SHA1 Message Date
Marco cc935420ec Move structural breakpoint to 640px, shorten Hero heading
Tablet layout (768-1023px) hit the md: grid switch exactly where the
fluid clamp() tokens were already at their floor, leaving no room to
shrink. Moves the fluid floor and structural breakpoint down together
to sm: (640px) so real tablets always get the fluid, desktop-like
structure; consolidates the ad-hoc md:+lg: patchwork in Hero/About/
Newsletter/Footer/Tools back onto one line, leaving documented lg:
exceptions where content genuinely doesn't fit yet. Also shortens the
Hero heading to a single sentence with no trailing period (the brand's
orange dot already renders one, animated).
2026-07-29 10:49:56 +00:00
Marco 94cba756c8 Remove trailing period from Werkzeuge section heading
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 09:58:32 +00:00
Marco b835e8622f Align newsletter modal copy with the homepage newsletter block
NewsletterModal.tsx advertised a different offer (the 7-Tage-Challenge)
than Newsletter.tsx's own description (7 Impulse) for the same signup
flow. Also rewrote both descriptions to drop the vague "und gewinne
Klarheit" buzzword formula and the word "Klarheit" repeated from the
heading directly above it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 09:58:27 +00:00
Marco 7286c76787 fixed hero title 2026-07-29 08:54:35 +00:00
Marco e175d2b4c3 Bump @einfach-produktiv/invoicing to 0.2.6 (embedded-font fix)
Picks up the Liberation Sans font-embedding fix for PDF/A-3 compliance
— fixes invoice PDF downloads/emails generated by this app.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 23:53:51 +00:00
Marco 1306dce6e4 Text updates for customer 2026-07-28 21:39:30 +00:00
Marco 8fa4a20e63 Document the active/inactive toggle and fix stale "6 rows" references
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 23:04:44 +00:00
Marco 1d875a65c0 Honor email-templates.active for order-confirmation
Skips the send entirely when the admin has deliberately deactivated
the order-confirmation template, matching the backend's new toggle for
the 7 order-status emails. Distinct from a missing row, which still
sends with the hardcoded default wording.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:58:41 +00:00
Marco 0436e87147 Document the 3 new email types and the cross-origin Live Preview limitation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:43:51 +00:00
Marco 7feda76b3c Use 🎉 for order-delivered instead of 🥳
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:14:22 +00:00
Marco c4fb6586e7 Match order-delivered's Live Preview icon to the backend's 🥳
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:13:36 +00:00
Marco 3dccc229af Add order-delivered to Live Preview support
Matches the backend's new opt-in review/follow-up email type.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:58:09 +00:00
Marco 6c43171b11 Fix Live Preview 404 for the two new tracking email templates
order-tracking-added/order-tracking-corrected were missing from
VALID_TYPES (app/email-preview/[type]/page.tsx), EmailTemplateType
(app/lib/payload.ts), and ORDER_STATUS_EMAIL_ICON (emailTemplates.ts)
— Live Preview 404'd for both since they were added to the Payload
collection without a matching frontend update.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 20:35:07 +00:00
Marco 8d4ee75cfb Document newsletter-modal fixes in the README
Error-clears-on-interaction behavior and the modal photo no longer
resizing when the already-subscribed/format-error message appears.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 20:19:44 +00:00
Marco 8a910f7ff8 Bump @einfach-produktiv/invoicing to 0.2.5
Moves the §19/§4-Nr.-1b-UStG notice out of the invoice summary card
into its own full-width row, matching the Vorkasse-notice fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 19:49:02 +00:00
Marco a7fa0ec027 Reserve space for newsletter-modal error text so the photo doesn't resize
The modal's left photo stretches (items-stretch, md:aspect-auto) to
match the right column's height. The "already subscribed"/invalid-email
messages were conditionally mounted, so their appearance grew the right
column and dragged the photo's height along with it. Both are now
always rendered with a reserved min-height instead, so toggling them no
longer changes the modal's size.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 17:52:13 +00:00
Marco 0ac2e45077 Clear "already subscribed" newsletter error on next interaction
Matches standard form-validation behavior: any further edit to the
email or consent checkbox after the already-subscribed message
appears now dismisses it, instead of leaving it stuck until submit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 17:34:20 +00:00
Marco fd98f68ba6 Route already-subscribed through the error state, not success
Per explicit feedback: swapping the whole form out for a bare success
message felt wrong for "you're already signed up, nothing to do" — the
form stays visible with a small red note below it instead, same as
every other inline validation error. No per-form UI changes needed,
they already render the error state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 17:27:50 +00:00
Marco bccfc28012 Log the real newsletter-subscribe failure reason server-side
The customer-facing message stays generic on purpose (never leak
Brevo's internal error text), but the real reason was discarded
entirely before this — every failure looked identical from the
outside. Cost real debugging time today tracking down a misconfigured
BREVO_LIST_ID in Coolify (was "2", should have been "5") that made
every single signup attempt fail with the same unhelpful message.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 17:25:01 +00:00
Marco 55df2e104c Give the Vorkasse bank details their own line in the confirmation email
Was one run-on sentence; split into three paragraphs: the instruction,
the bank details on their own bold line, then the processing-time note
with a line break after the bank line.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 17:20:15 +00:00
Marco 1706da8598 Add schema.org structured data, Vorkasse email notice, newsletter duplicate detection
- Organization (site-wide), Product (/todo-cards), BlogPosting (every
  /blog/[slug]) JSON-LD via new app/lib/structuredData.ts — no new
  Payload fields needed, derived from existing data. Verified locally
  by curling each page and checking the rendered script tag.
- Order confirmation email gains the same "please transfer to this
  account, processed after payment received" notice the invoice PDF
  already had for Vorkasse orders — OrderConfirmationData's new
  isManualPayment flag is set explicitly by each caller (never derived
  from paymentMethodTitle, which already broke once this session after
  a payment-methods rename). CompanySettings gains bankName (existed on
  the backend, was missing from the frontend's type/usage).
- Newsletter signup now detects an already-subscribed email
  (verified empirically: Brevo's doubleOptinConfirmation endpoint gives
  identical 201 responses for new vs. already-confirmed contacts) via a
  GET /v3/contacts/{email} pre-check, and shows a distinct message
  instead of silently resending the confirmation mail. Success message
  text centralized in useNewsletterSignup.ts instead of duplicated
  across 4 forms.
- Bumped @einfach-produktiv/invoicing to the version with the
  unpaid-notice layout fix (full width, more top spacing — was
  squeezed into the narrow paid-badge column).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 17:11:48 +00:00
Marco 1dbc0c31ff Drop "neu" from the checkout account-password copy
"Bitte ein Passwort für dein neues Konto vergeben" / "Passwort (für
dein neues Konto)" read oddly — just "dein Konto".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 16:41:02 +00:00
Marco 06a00d67e4 Fix groupPaymentMethodsForCheckout ignoring sortOrder
Hardcoded manual rows first, then the combined stripe option — so
"Online-Zahlung" (sortOrder 0) showed after "Überweisung (Vorkasse)"
(sortOrder 1) in checkout, contradicting the admin's own ordering.
Now preserves the fetch's sortOrder-sorted order, splicing the combined
entry in at the position of the first stripe row encountered.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 16:39:56 +00:00
Marco 952b902702 Document a concrete Stripe activation checklist
Everything code-side is already live — this is purely the remaining
provisioning steps (test keys -> Coolify -> backend .env -> redeploy ->
end-to-end test -> live keys), so the next person doesn't have to
reconstruct the sequence from scattered comments.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 16:17:32 +00:00
Marco f959ebb998 Bump @einfach-produktiv/invoicing for the Vorkasse invoice fix
Fixes isPaidImmediately() incorrectly showing "Bereits beglichen" on
unpaid Überweisung (Vorkasse) invoices after the payment-methods rename
earlier today, plus adds the missing "please transfer to this account,
processed after payment received" instruction text.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 16:12:27 +00:00
Marco bae23775f2 Hide failed-payment order attempts from the customer's own order history
A cancelled order with no invoiceNumber is a Stripe payment that never
succeeded (failed or timed out before ever reaching received/invoiced),
not a real cancellation of something that actually happened — from the
customer's point of view it was never really an order. Filtered out of
getCustomerOrders/getCustomerOrderDetail by default; the row stays in
Payload for admin/audit purposes (shown there as "Zahlung
fehlgeschlagen", see backend).

getCustomerOrderDetail's filter is opt-in via a new optional parameter,
not the default — /api/checkout/status/route.ts's post-payment polling
needs to keep seeing exactly this order to show the "Zahlung
fehlgeschlagen, bitte erneut versuchen" retry state. The GDPR export
route also opts out for the same reason a legal completeness export
can't silently drop rows.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 16:05:26 +00:00
Marco 0e12ab1f1e Merge Stripe payment integration + Brevo double opt-in newsletter
- Real payment capture for Kreditkarte/PayPal via Stripe's Payment
  Element, webhook-gated order confirmation, PAYMENT_TEST_MODE for
  local testing without a real Stripe account.
- Newsletter signup switched from single to double opt-in
  (POST /contacts/doubleOptinConfirmation), plus /newsletter-confirmed
  as the post-confirmation landing page.

Backend counterpart already deployed and verified (confirm-payment
endpoint live, payment-methods provider field set on Kreditkarte/PayPal).
STRIPE_SECRET_KEY/STRIPE_WEBHOOK_SECRET/NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
still unset in Coolify — PAYMENT_TEST_MODE auto-engages until then, so
checkout is safe to test without a real Stripe account.
BREVO_DOUBLE_OPTIN_TEMPLATE_ID is set.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 15:25:52 +00:00
Marco cb4c9d77f2 Fix icon circle collapsing narrow in strict HTML-attribute-stripping renderers
The width="56" height="56" HTML attributes on the icon badge <td> weren't
mirrored in its inline style — renderers that ignore/strip HTML
width/height (Brevo's own editor among them, per a real report) shrink
the cell to fit the glyph instead of staying a 56px circle. Add explicit
width:56px;height:56px to the style too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 14:48:45 +00:00
Marco ff6118a778 Fix icon circle collapsing narrow in strict HTML-attribute-stripping renderers
The width="56" height="56" HTML attributes on the icon badge <td> weren't
mirrored in its inline style — renderers that ignore/strip HTML
width/height (Brevo's own editor among them, per a real report) shrink
the cell to fit the glyph instead of staying a 56px circle. Add explicit
width:56px;height:56px to the style too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 14:31:08 +00:00
Marco 3328f30a06 Add /newsletter-confirmed double-opt-in confirmation page
Brevo's redirectionUrl now points here instead of the homepage — a
static page matching /bestellbestaetigung's visual language (brand-
tinted checkmark circle, serif display heading, thin brand divider).
No query params to read; Brevo's confirmation redirect carries nothing
this page needs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 14:08:52 +00:00
Marco df4bd700e6 Switch newsletter signup to Brevo double opt-in
Was a plain POST /v3/contacts upsert (single opt-in — straight onto the
list, no confirmation required). Now calls doubleOptinConfirmation
instead, so a signup only requests subscription; Brevo sends its own
confirmation email and adds the contact to the real list only once they
click through. Needs BREVO_DOUBLE_OPTIN_TEMPLATE_ID set in Coolify
before this works — not yet configured, signups will fail closed with a
logged reason until it is.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 13:40:27 +00:00
Marco bab2c916be Consolidate Kreditkarte/PayPal into one "Online-Zahlung" checkout option
Both already route through the same Stripe PaymentIntent
(automatic_payment_methods: enabled — Stripe's own recommended Payment
Element pattern, letting Stripe itself decide which eligible method to
show). Pre-selecting one of two identical-behind-the-scenes rows before
the payment step was redundant friction, not a real choice. Collapses
them into one option with a hint text explaining the actual instrument
is picked on the next screen; Überweisung is unaffected.

Also refines paymentMethodTitle from a neutral "Online-Zahlung"
placeholder (snapshotted at order-creation time, before the customer has
picked an instrument) to the real one Stripe reports, once payment
confirms — carried through to both the stored order and the
sessionStorage snapshot shown on /bestellbestaetigung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 12:17:38 +00:00
Marco 4e22942031 Send the customer confirmation email from the payment webhook
The webhook route previously assumed the backend's confirm-payment
endpoint sent the customer confirmation email; the backend assumed the
opposite. Net effect: a successful Stripe payment never triggered any
confirmation email. Consume the order snapshot confirm-payment now
returns and send it from here, matching what the checkout route already
does for a manual/Überweisung order.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 12:07:26 +00:00
Marco 740b791e5e Add Stripe payment processing (cards + PayPal) with a webhook-gated checkout flow
Checkout now branches on payment-methods.provider: Überweisung stays
immediate/unchanged, Kreditkarte/PayPal creates a pending_payment order,
mounts Stripe's Payment Element, and defers invoice/email to a webhook-
verified confirm-payment call once the backend actually confirms payment.
Includes a PAYMENT_TEST_MODE mock provider so the whole gated pipeline is
exercisable locally without a real Stripe account.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 12:03:04 +00:00
Marco bb3f94d39e Revert checkout step-number circle borders to the original color
Only the connector line between steps stays the darker #c4b8a0 —
the number circles themselves go back to border-border per feedback.
2026-07-24 21:35:41 +00:00
Marco d48a00973d Fix low-contrast checkout borders, and a Tablet-sizing regression in Hero/About
- Checkout: the 4 step cards' border-border and CheckoutSteps' connector
  lines/upcoming-circle borders were nearly the same luminance as the
  page's own bg-bg-base background, barely visible. Darker (#c4b8a0),
  scoped to just these spots rather than the shared border-border token.
- Hero.tsx: fixes a mistake from the last Tablet pass — moving the CTA/
  subtitle/icon/social-proof size overrides from lg: to md: (to match the
  grid breakpoint move) actually removed their smaller sizing from the
  whole Tablet range, recreating the exact 3-line-wrap problem the lg:
  exception used to prevent. Reverted those specific overrides back to
  lg: (grid structure stays at md:), and added a smaller heading size
  (text-h1) below lg: too — text-display's 44px floor doesn't fit the
  ~283-320px Tablet column any better than the CTA did.
- About.tsx: the quote/divider/bio row and its divider orientation also
  pushed from md: to lg: — still too tight for the Tablet column even
  after the text/photo ratio swap from the previous pass.
2026-07-24 21:32:28 +00:00
Marco 7b4b54a9ac Fix homepage Tablet layout: Hero grid, Tools icon, About columns, Newsletter/Footer stacking
- Hero.tsx: structural breakpoint reverted from lg: back to md: — the
  smaller CTA/subtitle/icon sizes added during the Mobile pass fit
  comfortably in the ~283px Tablet column, so the original 3-line-wrap
  problem that justified lg: doesn't recur. Tablet gets the real 5/7
  grid (image beside text) again instead of a stacked mobile layout.
- Tools.tsx: full-size (56px) card icon pushed from md: to lg: — at
  Tablet it dwarfed the still-close-to-floor title/description text.
- About.tsx: text/photo flex ratio swapped at Tablet (text gets the
  bigger share, no overlap) vs. the original ratio + overlap trick from
  lg: up, where it was designed for — Tablet's text column was too
  narrow for its fixed-width statement + quote/bio row otherwise.
- Newsletter.tsx/Footer.tsx: the input+button row and the logo/handle/
  legal-links row both went side-by-side at md:, but their surrounding
  columns didn't leave enough width at 768px — pushed to lg:flex-row.
2026-07-24 21:20:47 +00:00
Marco 797d9d42fe Custom post content blocks (images/gallery/video/quote) + backend-driven SEO settings
RichText.tsx switched to Payload's official React renderer + custom
JSXConverters (same call signature, LiveRichText/LivePostContent
untouched) — needed to render the new Lexical Blocks the Payload repo's
Posts.content just gained. Converters follow the existing CMS-image
convention (relative + aspect-[...] + fill + object-cover); the video
block resolves YouTube/Vimeo links to an iframe embed.

New getSeoSettings() fetcher (same pattern as getKleinunternehmer()),
app/layout.tsx now generateMetadata() reading it with the same fallback
values it used to hardcode. Per-post SEO overrides (seoTitle/
seoDescription/seoImage) wired into the blog detail page's metadata,
falling back to title/excerpt/thumbnail when empty.

Also fixed while auditing every page's metadata: missing descriptions on
3 konto pages, a static title on the dynamic order-detail route, and
missing OG images on /shop and /blog.
2026-07-24 21:10:33 +00:00
Marco b1b1aa2037 Stack Impulse & Tipps hero's email CTA below sm: for consistency
Input and button were a fixed row at every width, squeezing together on a
narrow phone — now flex-col sm:flex-row, full width when stacked, same
pattern as Challenge's EmailCapture and the other mail CTAs already fixed.
2026-07-24 20:07:50 +00:00
Marco 4f95a347dc Change StepArrow back to light gray
Matches the original icon-arrow-connector.svg's own default color, just
bolder (strokeWidth 2.5 vs. 1.5) and better-shaped than the original.
2026-07-24 20:05:04 +00:00
Marco 268f2e841d Nudge checkmark/login icon vertical alignment
- Checklist checkmarks (Challenge, todo-cards, newsletter): mt-0.5 -> mt-1,
  centering against the first line's glyphs instead of sitting flush at
  the very top edge.
- Navbar login icon: -translate-y-0.5 — its round head vs. wide shoulders
  read as optically bottom-heavy next to the cart icon despite both
  having a mathematically centered bounding box.
2026-07-24 20:02:44 +00:00
Marco 8d4f167374 Deactivated product shows as sold out, StepArrow to black, newsletter checkmarks fixed
- /todo-cards's detail page (the only page resolving a product regardless
  of active status) now renders both CTAs as "Ausverkauft" and disabled
  when the product is deactivated, instead of fully buyable — variants are
  dropped too, since AddToCartButton's outOfStock prop is otherwise ignored
  whenever variants is non-empty.
- StepArrow: brand orange didn't fit here after all, switched to
  near-black (#222221) per feedback.
- Newsletter/"Impulse & Tipps" checklist checkmarks (WeeklyImpulsesHero.tsx,
  WeeklyBenefits.tsx) were still the old un-recolorable icon-check.svg —
  same inline-SVG orange-checkmark fix as todo-cards/Challenge, plus
  items-start instead of items-center on WeeklyImpulsesHero's list for
  top-alignment consistency.
2026-07-24 19:58:24 +00:00
Marco 6a6d50abdb Fix orange dot/hero image visibility, arrow alignment, and add a mobile legal-page TOC
- 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.
2026-07-24 19:17:56 +00:00
Marco bca29ab7a3 Fix more mobile responsive issues: Hero, arrows, cart button, checkmarks, modal
- Newsletter card icon: fixed an aspect-ratio distortion bug (w-16 maps
  to this project's fluid --spacing-16, which floors to 40px below
  768px, paired with a fixed 55px height — squished the icon on
  mobile). Same root cause existed in NewsletterModal's envelope icon;
  that one's now just hidden below md: instead per feedback.
- Hero: subtitle sized down and CTA checkmark icon scaled to match
  below lg:, social proof text always wraps below the avatars there
  instead of only when it doesn't fit.
- Werkzeuge connector arrows (todo-cards/newsletter/challenge
  HowItWorks): object-contain added — the SVG has
  preserveAspectRatio="none" and was stretching to fill the square
  mobile box instead of keeping its thin-arrow shape.
- Challenge bottom CTA: icon now stacks above the copy, centered, below
  lg: to match the Home Newsletter card's pattern.
- Homepage Werkzeuge icons: smaller below md: to match the (fluid-floor)
  text size next to them.
- Blog detail "Passend dazu" card: the fixed w-[19rem] title column plus
  "Entdecken" sharing its row overflowed on mobile; stacked below sm:
  instead, with a little top margin on "Entdecken".
- Todo-Karten checklist checkmarks: recolored brand-orange (icon-check
  .svg's fill lives in an internal CSS var that can't be overridden from
  outside an <img>-loaded SVG, so switched to an inline SVG) and
  top-aligned instead of vertically centered.
- AddToCartButton: added whitespace-nowrap to the stacked-label grid
  (used to reserve button width across all possible label texts) — one
  of those labels wrapping to two lines on a narrow w-full button was
  inflating the row height for whichever label is actually showing,
  leaving a tall empty gap under "Ausverkauft".
2026-07-24 19:01:18 +00:00
Marco 3da8b75395 Fix several mobile responsive issues across Hero, Newsletter, cart, and Challenge
- Hero CTA: back to a single line below lg: (wrapping put the icon
  beside two lines and looked broken), sized down instead so the full
  phrase fits.
- Hero heading: dropped the forced <br> after "darf" at true mobile
  widths, kept it only for the sm-lg tablet range it was added for.
- Hero social proof: avatars+text now wrap and center instead of
  cramming onto one row (flex-wrap + justify-center, no fixed
  breakpoint needed).
- Newsletter card icon: stacked above the copy and centered below md:
  instead of squeezed into a row beside it.
- TrustRow: left-aligned below md: instead of centered (shop, cart, and
  every other page using this component).
- Cart line item image: full width below sm: instead of a fixed 150px
  square.
- Challenge EmailCapture (top + bottom CTA, same shared component):
  input and button stack full-width below sm: instead of squeezing
  into one row.
- Challenge steps: icon above text and centered at every breakpoint
  (previously only from lg: up), connector arrows centered to match.
2026-07-24 18:48:18 +00:00
Marco f20a02dfa2 Match the profile icon's size to the cart icon in the navbar
Profile was h-6 w-6 (24px) next to cart's h-7 w-7 (28px), a noticeable
size mismatch between the two always-visible nav icons.
2026-07-24 18:38:33 +00:00
Marco 55de9b3e29 Fix three mobile layout issues on the homepage
- Hero CTA: whitespace-nowrap forced the button as wide as the full
  32-char phrase, overflowing the stacked mobile column. Now wraps to
  two lines below lg:, single line from lg: up where there's room.
- Navbar: the account/cart icons are 44px touch targets with the glyph
  centered inside, so the outer gap-2 read as too much space on top of
  that padding. Grouped them with no gap between just the two.
- Divider: "Klarheit -> Fokus -> Entlastung" plus its connector icons
  needs ~550px to fit one row even at the site's 768px fluid floor, far
  more than a phone's ~310px content width. Added a component-scoped
  --divider-word-size (independent from --text-h2) plus a <640px
  override that shrinks the words/icons/gaps together.
2026-07-24 18:32:35 +00:00
Marco a3fb864f7d Focus the email field after clearing it via "andere E-Mail-Adresse"
FormField is now forwardRef so the email input can be targeted
imperatively — clicking the button clears the field (previous commit)
and now also focuses it, so the shopper can start typing immediately
instead of having to click in first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 18:04:56 +00:00
Marco 9f92f7324a Clear Card 1's email field when switching away from the login prompt
"Andere E-Mail-Adresse verwenden" only hid the inline login prompt
before, leaving the already-registered address still sitting in the
field — the shopper had to manually select/delete it before typing a
new one. Now clears email + loginPassword + the email field's error
alongside dismissing the prompt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 17:56:42 +00:00
Marco 9bfd0affd0 Tighten Impressum text blocks and drop Reveal's y-translate jump
AnbieterAngaben.tsx's address/VAT/register blocks each got the same
gap-4 as the section headings, so related lines (e.g. name/street/zip+
city) read as visually disconnected paragraphs instead of one block —
wrapped each in its own gap-1 container, keeping gap-4 only between
sections.

Reveal.tsx's shared fadeUp variant animated opacity and a 28px y-
translate together, which read as the whole section hopping into place
on top of the fade. Renamed to fadeIn, opacity only — applies site-wide
via Reveal/RevealGroup/RevealItem.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 17:47:06 +00:00