Commit Graph

142 Commits

Author SHA1 Message Date
Marco b144758b82 Restore a light background on mobile wishlist hearts
Fully transparent made the heart invisible against some product photos — keeps it smaller than the default but with a semi-transparent (60%) background circle instead of none, and stops dimming the icon itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 20:53:15 +00:00
Marco 92c6953724 Make mobile wishlist hearts smaller/subtler instead of full-size everywhere
Full-size, always-visible hearts on touch devices recreated the exact "a heart on every card" visual noise revealOnHover exists to avoid. Touch devices now get a smaller, backgroundless, slightly transparent heart instead — present and tappable everywhere, but visually quiet. Desktop hover-reveal behavior is unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 20:49:25 +00:00
Marco 9bf6e3f4f2 Fix wishlist heart invisible on mobile product grids
revealOnHover relied purely on group-hover/group-focus-within, both mouse/keyboard-only pseudo-classes with no reliable touch equivalent — a tap on a card never reliably triggers group-hover the way a mouse hover does, leaving the heart permanently hidden on touch devices. Adds pointer-coarse:opacity-100 so it's always visible there; desktop hover-reveal behavior is unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 20:43:40 +00:00
Marco 51e4860fe3 Add spotlight wishlist toggle and shop filter/grid polish
Per-product spotlightShowWishlist opt-in (independent of the global
wishlistEnabled toggle), a reveal-on-hover WishlistButton variant for
multi-card grids (avoids a heart on every card reading as visual noise),
and related PriceRangeFilter/ProductGrid/CustomSelect adjustments.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 13:00:55 +00:00
Marco ee39a5d7dc Use CustomSelect for checkout's country pickers too
Promoted CustomSelect from konto/bestellungen/components/ to a shared
app/components/ location. New includeAllOption (checkout doesn't want
a "clear" pseudo-option — a country is always genuinely selected) and
fullWidth (matches the other w-full form fields, no sm: shrink) props.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 23:15:08 +00:00
Marco bc40e22910 Gate search behind CompanySettings.searchEnabled; fix two reported bugs
Search icon now gated behind the new backend toggle, same pattern as
wishlistEnabled — off by default.

Fixed: blog category filter bar was invisible — it was wrapped in
<Reveal>, which sits right at/just past the hero's bottom edge, the
exact "already near the initial viewport" position Reveal.tsx's own
comment documents as a whileInView(margin:"-80px") trap (an element
already visible without scrolling can permanently never register as
"entered view", since `once: true` never gets a second chance). Now a
plain div, no scroll-reveal animation needed for a filter bar anyway.

Fixed: wishlist count showing one behind on the Navbar badge —
useWishlist.ts's toggle() broadcast the "refetch me" event immediately
after the optimistic local update, before the POST request was even
sent. Another instance's resulting refetch could race the actual
server-side write, get the pre-toggle list, and then never get told to
refetch again. Broadcast now only fires after the request settles.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 22:51:37 +00:00
Marco 2eda211a29 Add instant-search overlay (products + blog posts)
Separate commit on purpose so this can be reverted independently if
needed. Search icon in the Navbar (hidden below sm:, same reasoning
as WishlistLink — Account+Cart are the only always-visible icons on
true mobile) opens a debounced (250ms) overlay searching both
collections at once via a new /api/search route.

Plain Payload `where[...][contains]` queries (Postgres ILIKE), not a
real search index (Meilisearch/Algolia) — matches the catalog's
current small size, see [[project-ecommerce-sota-gaps]]'s own "search
becomes necessary past ~20 products" note. Worth upgrading later
without touching the overlay component itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 22:39:38 +00:00
Marco 11aa9689c1 Add wishlist feature (frontend), gated by CompanySettings.wishlistEnabled
New: useWishlist.ts (fetch+optimistic-toggle hook, server-backed since
a wishlist needs a logged-in customer, unlike the guest-friendly cart),
WishlistButton.tsx (heart toggle, login-redirects on 401), Navbar's
wishlist icon+badge (hidden below sm: — Account+Cart are the only
always-visible icons on true mobile, a 3rd icon there risks the same
computed nav-overflow class of bug documented in the figma-to-nextjs
skill), and /konto/merkliste (list page, 404s if the feature gets
disabled after a customer already has rows).

Product gained numericId (the raw Payload id) alongside its existing
slug id — WishlistItems.product is a real numeric relationship field,
unlike cart/checkout's slug-keyed "commerce id".

Backend counterpart (WishlistItems collection, CompanySettings toggle,
migration) already deployed separately.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 22:28:30 +00:00
Marco 475ee3fa16 Replace order-filter chip wall with 3 compact selects; subgrid-align trust badges
OrderFilters.tsx: filter chips (7 status + 5 payment-status + N year
options as pills) read as cluttered and ate a lot of vertical space.
Replaced with 3 native <select>s in a row (a small Client Component
just for the onChange→router.push navigation) — same URL-search-param
filtering underneath, just a much more compact control.

TrustRow.tsx: replaced the hardcoded min-h-[3.2rem] title reservation
(a guess, and it visibly over-reserved space for single-line titles)
with a real CSS Grid + `grid-template-rows: subgrid` — every badge's
icon+title box shares the same row-track height (auto-sized to
whichever title actually needs 2 lines), so descriptions align
without any hardcoded value. The two structurally different layouts
(icon-above-title below lg vs. icon-beside-a-title/description-stack
at lg) now render as two separate blocks instead of fighting one
shared shape.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 22:11:12 +00:00
Marco c8cf6ae10d Fix trust-badge title/description misalignment, cap order-confirmation card width at tablet
TrustRow.tsx: reserve 2 lines of height for the title below lg: so the
description starts at the same y-position regardless of whether that
badge's own title happened to wrap to 1 or 2 lines in its narrow
stacked column.

BestellbestaetigungContent.tsx: same fix category as NewsletterModal's
dialog width cap — max-w-[56rem] doesn't constrain anything below
896px, so the order-details card stretched full width through the
640-1023px tablet range. Added max-w-[36rem] there, widening to the
real cap only once lg:'s sidebar split needs the room.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 22:05:40 +00:00
Marco 11c8d0b7b6 TrustRow: side-by-side row below lg with icon above text, no wrap
Cart summary trust badges: side by side between sm and lg

TrustRow.tsx: rebuilt as a single continuous below-lg tier instead of
mobile-nebeneinander/tablet-stacked — icon above text (shrinking each
badge to its text column's width) plus dropping whitespace-nowrap on
title/description below lg (wrapping within their own narrow column
instead of forcing overflow) means a full row of 3 badges now fits
without needing to wrap or stack, avoiding the previously-reverted
"odd item alone on its own line" issue a flex-wrap attempt hit.

CartContent.tsx: the sidebar's trust-badge list (title only) now goes
side by side between sm (640px) and lg (1024px) instead of always
stacked — that sidebar is full page width through that whole range,
plenty of room for 3 short titles in a row.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 21:44:30 +00:00
Marco ea7f4a4b3b Blog secondary post cards: image above text through tablet width
Was sm:grid-cols-5 — with the 2-up sm:grid-cols-2 outer grid, each
card's own width through 640-1023px was too narrow for image+text
side by side. Now stacks through lg (1024px), row layout only once
each card has real width. Featured post untouched (already fine).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 21:32:54 +00:00
Marco 6262a8ab01 Tools cards: icon above text below lg, left-aligned above mobile
Newsletter: left-align copy above mobile, fix missing vertical padding

Tools.tsx: icon+text now stacks below lg (1024px) instead of always
being a row — a 3-up grid from sm (640px) left each card too narrow
for side-by-side icon+text through 640-1023px. Centered on true
mobile, left-aligned from sm up.

Newsletter.tsx: same left-alignment treatment (centered only on true
mobile, left-aligned from sm up). Also removed the outer card's
sm:py-0 — it relied entirely on items-center centering against the
copy column's height for top/bottom breathing room, which broke down
whenever the form column (input/checkbox/privacy note) was as tall or
taller, leaving the input and "Keine Werbung" note flush against the
card edges. py-8 now applies at every breakpoint.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 21:31:15 +00:00
Marco 7baf8f9e24 Keep the newsletter icon above the text through the whole tablet range
Icon+text switched to row layout at sm (640px), but the outer card
already puts this copy column next to the form from that same
breakpoint — squeezed the text through 640-1023px. Row layout for
icon+text now only kicks in at lg, where there's actually room.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 21:27:26 +00:00
Marco a036c89291 Fix Product Spotlight looking too wide on tablet
sm:flex-row (640px) put the 380px image side-by-side with text well
before there was comfortable room for it — tablet widths (768-1023px)
read as cramped. Now stays stacked like mobile through lg (1024px),
with a max-w-[32rem] cap between sm and lg so the stacked card reads
as centered/narrower instead of stretching to fill the tablet
viewport (true mobile stays unconstrained, the viewport is already
narrow there).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 21:25:46 +00:00
Marco 32f4068272 Slow down the mobile nav drawer's close animation
The shared ease-out curve (fast start, slow finish) worked well for
the open reveal but made the close shrink almost instantly then
linger on a barely-visible sliver — read as abrupt. Gave exit its own
longer, easeInOut transition instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 19:59:36 +00:00
Marco 275d5abd95 Close the mobile nav drawer when clicking the navbar itself
Added an onClick on <header> that closes the drawer whenever it's
open — the panel is a sibling, not a descendant, so this never fires
for clicks inside the open drawer, only the bar itself. The
hamburger's own click now stops propagation so toggling the drawer
open doesn't get immediately undone by this same handler.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 19:57:14 +00:00
Marco e3352d7e32 Blog categories (hasMany), shipping-address contact fields, product SKU on invoices
- Posts.categories is now hasMany — blog list/detail/live-preview render
  a comma-joined list instead of a single category.
- Checkout's "Abweichende Lieferadresse" gains optional Firma + Kontakt-
  E-Mail/Telefon fields (handed to the shipping carrier, not used for
  customer communication).
- Customer profile can now store its own shipping address (mirroring
  Customers.ts's new "Lieferadresse" tab), prefilling the checkout
  override instead of always starting blank.
- Product-level optional SKU (previously only on variants) snapshots onto
  each order item and shows up on invoices (visual + EN16931 XML),
  the confirmation email, and the account order detail page.
2026-07-30 08:41:39 +00:00
Marco c852752006 Cap Newsletter card at 1280px, show an explicit "Keine Versandkosten" hint, generalize the /versand exemption note
- Newsletter.tsx: max-w-[1280px] mx-auto, matching /lebensuhr's own
  newsletter-style section and Footer.tsx's existing 1280px convention —
  previously unbounded and stretched edge-to-edge on wide viewports.
- Product pages: noShippingCost now shows "Keine Versandkosten" instead
  of just omitting "zzgl. Versand" silently.
- /versand's exemption note no longer implies only digital products can
  be exempt — noShippingCost is a general per-product flag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 23:01:17 +00:00
Marco a3f843ad15 Honor Products.noShippingCost across cart, checkout, and product pages
- 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>
2026-07-29 22:48:33 +00:00
Marco fb1bedcacd Fix invisible Stripe pay button, add brand favicon/OG image, navbar 3x3-System CTA, blog hero crop
- PaymentStep: bg-brand-primary was never a real Tailwind class, leaving
  the "Jetzt bezahlen" button unstyled/invisible; switched to bg-brand
  with dark text, matching every other CTA on the site.
- New app/icon.svg + app/apple-icon.png + app/favicon.ico: brand-yellow
  rounded square with a bold italic "e", replacing the Next.js default.
- New public/og-image.png (logo on the site's cream background) wired in
  as the SEO fallback default OG image/description/title in payload.ts.
- Navbar CTA: "Klarheitskompass" -> "Mein 3x3-System", now links to
  /3x3-system (page not built yet).
- Blog overview hero image anchored to the top instead of center-cropped.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 21:48:22 +00:00
Marco 0a467aed59 Tighten newsletter modal's input-to-submit-button gap
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 20:52:42 +00:00
Marco 14094ab1d4 Update newsletter/brand copy, hide VAT section without a vatId, relabel Lebensuhr breadcrumb
- Newsletter panel + modal: new title/description copy, weekly cadence wording
- Brand mentions ("einfach-produktiv") switched to "einfach produktiv."
- Impressum: Umsatzsteuer section (heading + TOC entry) only renders when vatId is set
- /lebensuhr breadcrumb eyebrow now reads "Lebensuhr" instead of "7-Tage-Challenge"

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 20:49:46 +00:00
Marco 96fddf4cd9 ueberarbeitung mit bjoern 2026-07-29 20:11:55 +00:00
Marco 5f219c23f9 Revert TrustRow from flex-wrap back to single-column stacking
The flex-wrap experiment (2 badges per row + 1 wrapped centered below)
looked disorganized with exactly 3 badges — the wrapped single item
doesn't align under either item in the row above it, reported as
"durcheinander". Reverts to strict single-column stacking below lg:
(the inner-shrink-to-fit-group + outer center/left-align pattern),
which stays visually clean regardless of how many badges exist.
2026-07-29 12:38:44 +00:00
Marco d389790c57 TrustRow: flex-wrap instead of a hard lg: breakpoint; sticky modal close button
TrustRow now uses flex-wrap + justify-center so badges flow as many
per row as actually fit at the current width, wrapping (and
auto-centering, a native flexbox behavior for the last wrapped line)
instead of needing a breakpoint or risking overflow. Replaces the
earlier lg:-only structural exception entirely.

NewsletterModal's close button was absolutely positioned inside the
dialog's own scrolling container, so it scrolled away with the
content. Switched to sticky (top-6, ml-auto for horizzontal position,
-mb-6 to cancel its own height so it doesn't push content down) so it
stays pinned to the top-right corner while scrolling.
2026-07-29 12:35:12 +00:00
Marco 3aa8720daf Fix TrustRow badges misaligning with each other when centered
items-center directly on the badge container centered each badge
independently within the container's width — badges with different
title/description lengths ended up with different left edges instead
of lining up (confirmed via our own screenshot: icons at different x
positions below 640px). Wraps all badges in one inner shrink-to-fit
group (always items-start internally, so every badge shares the same
left edge) and centers/left-aligns that single group as a unit from
the outer wrapper instead.
2026-07-29 12:25:49 +00:00
Marco 17679cc81e Only center TrustRow badges below 640px, left-align through Tablet
Centering the whole non-lg: range (previous fix) overcorrected — only
true Mobile should center (matches other centered content there); the
640-1023px Tablet band left-aligns instead, each badge's left edge
lining up via items-start (no per-badge centering, so nothing reads
crooked). Same tiered-alignment pattern as Hero's social-proof row.
2026-07-29 12:13:20 +00:00
Marco 56fc8d970d Revert TrustRow's breakpoint from sm: to lg:, center stacked badges
Same fixed-content-doesn't-fit bug as Footer's legal-links row,
confirmed via live-site horizontal-overflow measurement: ~100px
overflow at 666px viewport, ~54px at 768px. Multiple whitespace-nowrap
title+description badges don't fit in one row below ~1024px regardless
of fluid scaling. Also centers stacked badges (was items-start below
sm:, now items-center through the whole non-lg: range) per feedback.
2026-07-29 12:09:44 +00:00
Marco 61afa0dcae Revert Footer's row breakpoint from sm: back to lg:
Confirmed via Playwright against the live site (666px viewport): this
row was causing a real horizontal page overflow (scrollWidth 746px vs
666px viewport) in the 640-1023px band, not just visual cramping —
logo + handle + 5 nowrap legal links (all shrink-0) don't fit in one
row below ~1024px regardless of fluid scaling. Today's earlier sm:
rename wrongly treated this as a simple structural-breakpoint case;
it's actually the same fixed-content-doesn't-fit category as
Cart/Checkout/SectionTOC, which correctly stayed at lg:.
2026-07-29 12:04:07 +00:00
Marco 724530b073 Cap NewsletterModal's width through Tablet instead of just stacking it
Stacking single-column at lg: (previous attempt) let the dialog stretch
to near-full-viewport-width at real Tablet widths, since max-w-[75rem]
barely constrains it there — the photo blew up huge and the text below
read as lost/disconnected. Caps the dialog at max-w-[36rem] through the
640-1023px band (only widening to 75rem once the lg: 2-column split
kicks in), so it reads as a compact modal at every width, not a
near-full-bleed stack.
2026-07-29 11:35:31 +00:00
Marco 5c43a49ba9 Revert "Break NewsletterModal at lg: instead of sm:"
This reverts commit e0299713f5.
2026-07-29 11:33:40 +00:00
Marco e0299713f5 Break NewsletterModal at lg: instead of sm:
The dialog is capped at max-w-[75rem] (1200px), so at real Tablet
viewports (640-1023px) it's essentially full-viewport-width — too
little room per column at sm: for the heading/form or the 3 feature
cards to read well. Stacked through the whole Tablet range now,
side by side again only from lg: up.
2026-07-29 11:32:09 +00:00
Marco a9c8344472 Add a soft edge fade to About's photo at Tablet too
The left gradient was gated to lg: (matching the -ml-48 overlap), but
without any overlap at Tablet the photo sits flush against the dark
text column with a hard vertical seam. Narrower fade (w-16) from sm:
up softens that seam; widens to w-72 at lg: to also cover the deeper
overlap once that kicks in.
2026-07-29 11:24:38 +00:00
Marco cbb423f8ca Center Hero heading/subheading below 640px too
CTA and social-proof were already centered on true Mobile, but the
heading/subheading above them stayed left-aligned — read inconsistent.
Centers the whole text block below sm:, left-aligned again from sm: up.
2026-07-29 11:13:48 +00:00
Marco dfb6eb5e23 Re-center Hero social proof below 640px, keep it left-aligned at Tablet
Centering it site-wide below lg: overcorrected — true Mobile (<640px)
should stay centered (matches the CTA there), only the 640-1023px
Tablet band needed the left-align fix from the previous commit.
2026-07-29 11:08:40 +00:00
Marco 5e1d88d13e Left-align Hero's social proof row below lg:
Centered avatars+text below lg: read as floating/disconnected from the
left-aligned heading/subheading/CTA above it. Left-aligned now to match
the rest of the column; still switches to a single centered row at lg:.
2026-07-29 11:05:59 +00:00
Marco c3a6c84d8a Give About's photo more room at Tablet, not the text column
The wider text share at sm: didn't actually help the inner quote/bio
row go inline (it stays stacked until lg: regardless) — it just took
space away from the photo, which read as too narrow/cramped on Tablet.
1:1.4 text:image ratio now applies from sm: up; only the -ml-48 overlap
itself stays gated to lg:, since that trick needs more absolute room.
2026-07-29 11:02:29 +00:00
Marco 932cf60c5c Fix About Tablet layout, center Hero CTA on Mobile
The sm:/lg: ratio collapse in About.tsx from the breakpoint migration
was wrong: the Tablet-specific wider text share wasn't just compensating
for the grid arriving too early, it's what the inner quote/bio row and
the photo's -ml-48 overlap actually need room for. Restores the
two-tier ratio (wider text, no overlap at sm:; real ratio + overlap
only at lg:), just anchored to sm: instead of the old md:.

Also centers the Hero CTA button below sm: (Mobile) per feedback.
2026-07-29 10:58:36 +00:00
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 1306dce6e4 Text updates for customer 2026-07-28 21:39:30 +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 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 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