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.
This commit is contained in:
Marco
2026-07-24 21:32:28 +00:00
parent 7b4b54a9ac
commit d48a00973d
4 changed files with 76 additions and 51 deletions
+12 -4
View File
@@ -668,7 +668,15 @@ export function CheckoutContent({
{/* Form column */}
<div className="w-full lg:flex-1 flex flex-col gap-6 items-start min-w-0">
{/* 1. Rechnungsadresse */}
<Reveal className="w-full bg-bg-base border border-border rounded-md p-7 flex flex-col gap-5 items-start">
{/* border-[#c4b8a0], not the shared border-border (#e5e0d8) — that
token is nearly the same luminance as this card's own bg-bg-base
background (#f8f5f1), so the card's outline barely read at all
(fixed 2026-07-24, feedback: "die Striche bei den Steps sind zu
hell"). Darker but still on the warm-cream palette, scoped to
just these 4 step cards rather than the shared token, since
border-border reads fine everywhere else it's paired with a
genuinely different background. */}
<Reveal className="w-full bg-bg-base border border-[#c4b8a0] rounded-md p-7 flex flex-col gap-5 items-start">
<p
className="font-semibold text-h-small text-text-primary"
style={{ fontFamily: "var(--font-lora)" }}
@@ -1107,7 +1115,7 @@ export function CheckoutContent({
</Reveal>
{/* 2. Versandart */}
<Reveal delay={0.05} className="w-full bg-bg-base border border-border rounded-md p-7 flex flex-col gap-5 items-start">
<Reveal delay={0.05} className="w-full bg-bg-base border border-[#c4b8a0] rounded-md p-7 flex flex-col gap-5 items-start">
<p
className="font-semibold text-h-small text-text-primary"
style={{ fontFamily: "var(--font-lora)" }}
@@ -1138,7 +1146,7 @@ export function CheckoutContent({
</Reveal>
{/* 3. Zahlungsart */}
<Reveal delay={0.1} className="w-full bg-bg-base border border-border rounded-md p-7 flex flex-col gap-5 items-start">
<Reveal delay={0.1} className="w-full bg-bg-base border border-[#c4b8a0] rounded-md p-7 flex flex-col gap-5 items-start">
<p
className="font-semibold text-h-small text-text-primary"
style={{ fontFamily: "var(--font-lora)" }}
@@ -1198,7 +1206,7 @@ export function CheckoutContent({
{/* Sidebar */}
<Reveal delay={0.15} className="w-full lg:w-[24.375rem] lg:shrink-0 flex flex-col gap-6 items-start">
<div className="bg-bg-base border border-border rounded-md p-7 flex flex-col gap-5 items-start w-full">
<div className="bg-bg-base border border-[#c4b8a0] rounded-md p-7 flex flex-col gap-5 items-start w-full">
<p
className="font-semibold text-h-small text-text-primary"
style={{ fontFamily: "var(--font-lora)" }}
+11 -6
View File
@@ -26,8 +26,13 @@ export function About() {
</p>
{/* Quote row: script quote / divider / author bio — side-by-side
from md+, stacked with a horizontal divider below md */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-6 md:gap-0 w-full">
from lg: (was md:) — even with the text column's wider Tablet
share above, quote + divider + the whitespace-nowrap bio ("Gründer
von einfach-produktiv.") together still needed more room than
Tablet's ~384px column has. Stacked with a horizontal divider
through the whole Tablet range instead, side-by-side (vertical
divider) only once there's real room at lg:. */}
<div className="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6 lg:gap-0 w-full">
{/* Caveat script text with signature positioned below */}
<div className="relative flex-1" style={{ minHeight: "8rem" }}>
@@ -58,12 +63,12 @@ export function About() {
</div>
</div>
{/* Divider — horizontal full-width line below md, vertical
gold line beside the author bio from md+ */}
<div className="bg-brand w-full h-px md:w-[2px] md:h-24 md:mx-6 shrink-0" />
{/* Divider — horizontal full-width line below lg:, vertical
gold line beside the author bio from lg: */}
<div className="bg-brand w-full h-px lg:w-[2px] lg:h-24 lg:mx-6 shrink-0" />
<div
className="text-bg-white font-normal whitespace-nowrap md:shrink-0"
className="text-bg-white font-normal whitespace-nowrap lg:shrink-0"
style={{ fontSize: "1rem", lineHeight: "1.5rem" }}
>
<p>Björn.</p>
+7 -2
View File
@@ -20,7 +20,12 @@ function StepCircle({ state, number }: { state: StepState; number: number }) {
);
}
return (
<div className="flex size-9 items-center justify-center rounded-full border border-border font-bold text-body-sm text-text-muted">
// border-[#c4b8a0], not the shared border-border (#e5e0d8) — nearly the
// same luminance as the page's own bg-bg-base (#f8f5f1), barely visible
// (fixed 2026-07-24, feedback: "die Striche bei den Nummern-Steps sind
// zu hell"). Same color as the connector line below and the checkout
// step cards' own border fix, for consistency.
<div className="flex size-9 items-center justify-center rounded-full border border-[#c4b8a0] font-bold text-body-sm text-text-muted">
{number}
</div>
);
@@ -50,7 +55,7 @@ export function CheckoutSteps({ current }: { current: number }) {
</span>
</div>
</div>
{i < STEP_LABELS.length - 1 && <div className="h-px bg-border flex-1 mx-4 min-w-4" />}
{i < STEP_LABELS.length - 1 && <div className="h-px bg-[#c4b8a0] flex-1 mx-4 min-w-4" />}
</div>
);
})}
+46 -39
View File
@@ -28,17 +28,19 @@ function HeroImage() {
export function Hero() {
return (
<section className="bg-bg-base w-full overflow-hidden">
{/* Structural breakpoint is md: (768px), same as the site-wide
convention — briefly moved to lg: (see the figma-to-nextjs
skill's Gotcha #5) because at md:col-span-5 the text column was
only ~283px at 768px and the full-size CTA/subtitle text made the
heading/CTA/social-proof row wrap to 3 cramped lines. Reverted
2026-07-24: the CTA/subtitle/icon sizing added since then for
true mobile widths (see each one's own comment below) uses fixed
sizes well under half that column width, so the original problem
doesn't recur — moving back to md: means Tablet gets the real
5/7 grid (image beside text) instead of stacking full-width like
a phone. */}
{/* Structural breakpoint is md: (768px) for the GRID only — the text
column stays ~283-320px wide through the whole 768-1023px Tablet
range regardless. Below, every piece of *content* inside the text
column (heading/subtitle/CTA/social-proof) keeps its smaller,
fixed-below-lg: sizing all the way through Tablet too, not just
true Mobile — reusing the full fluid-token sizes at md: (as a
first pass 2026-07-24 briefly did) put the original ~19-44px
fluid floors right back in that narrow column, recreating the
exact 3-line-wrap problem the old `lg:` structural exception
existed to avoid. Splitting "grid at md:" from "full-size content
at lg:" gets both: Tablet shows the real 5/7 grid, but with
content sized for its column's actual width, not the column
width `lg:` was designed for. */}
<div className="flex flex-col md:grid md:grid-cols-12 md:items-center gap-8 md:gap-[var(--layout-grid-gap)] pt-10 md:pt-0">
{/* Text content — first in DOM/visual order at every breakpoint so
@@ -48,18 +50,21 @@ export function Hero() {
viewport — this doubles as the page's entrance animation. */}
<Reveal className="order-1 md:order-none md:col-span-5 flex flex-col gap-7 items-start pl-[var(--layout-padding-x)] pr-10 md:pr-0">
{/* Heading — forced break after "darf" only in the sm-md tablet
range (Hero stacked full-width there, natural wrap landed
awkwardly). Removed at true mobile widths (below sm:) 2026-07-24
— narrower still, natural wrap there reads fine, and the
forced break made "darf" the whole first line, leaving very
little text above the CTA. Natural wrap from md: up too, once
the 5/12 grid gives the column real width again. */}
{/* Heading — smaller fixed-ish size below lg: (text-h1, still a
real paired font-size+line-height token, not an arbitrary
value) — text-display's own 44px floor wraps very heavily in
a ~283-320px Tablet column (even a single word can approach
that width). Forced break after "darf" only in the sm-md
tablet range (natural wrap there landed awkwardly); removed
at true mobile widths (below sm:) 2026-07-24 — narrower
still, natural wrap reads fine there, and the forced break
made "darf" the whole first line. Full text-display only
from lg: up, where the column has real room again. */}
<p
className="font-semibold leading-[0] shrink-0 text-[0px] text-text-primary"
style={{ fontFamily: "var(--font-playfair)" }}
>
<span className="text-display">
<span className="text-h1 lg:text-display">
Produktivität darf<br className="hidden sm:inline md:hidden" /> sich leicht anfühlen
</span>
{/* Brand's signature orange dot (also in the logo/footer) —
@@ -67,16 +72,18 @@ export function Hero() {
land just after the Reveal's own 0.6s fade-up so it reads
as a deliberate flourish, not simultaneous with the text.
One-shot, not a looping pulse — continuous motion next to
the primary CTA would be distracting rather than "cool". */}
<PopIn className="text-display text-brand inline-block" delay={0.5}>
the primary CTA would be distracting rather than "cool".
Same text-h1 lg:text-display as the heading itself, so the
dot scales down to match below lg:. */}
<PopIn className="text-h1 lg:text-display text-brand inline-block" delay={0.5}>
.
</PopIn>
</p>
{/* Subheading — smaller fixed size below md:, text-h-emphasis's
own 20px floor read too large next to the now-smaller mobile
CTA text. leading shrinks to match, not just font-size. */}
<p className="font-semibold leading-[1.75rem] md:leading-[2.375rem] min-w-full shrink-0 text-text-primary text-[1rem] md:text-h-emphasis w-[min-content] [word-break:break-word] not-italic">
{/* Subheading — smaller fixed size below lg:, text-h-emphasis's
own 20px floor read too large next to the now-smaller CTA
text. leading shrinks to match, not just font-size. */}
<p className="font-semibold leading-[1.75rem] lg:leading-[2.375rem] min-w-full shrink-0 text-text-primary text-[1rem] lg:text-h-emphasis w-[min-content] [word-break:break-word] not-italic">
Für Menschen mit Familie, Verantwortung und zu wenig Zeit
</p>
@@ -85,28 +92,28 @@ export function Hero() {
href="/challenge"
className="flex gap-4 items-center justify-center overflow-clip px-6 py-3 rounded-sm shrink-0 max-w-full bg-brand hover:brightness-95 active:scale-[0.97] transition-all"
>
{/* Letting this wrap to two lines below md: (tried 2026-07-24)
{/* Letting this wrap to two lines below lg: (tried 2026-07-24)
put the icon beside a two-line text block, which read as
broken rather than intentional. Smaller fixed size below
md: instead, so the full phrase fits on one line within
the stacked mobile column's width — text-h3's own 19px
floor was still too wide for that at ~236px of available
text budget on a 375px phone. */}
<span className="font-semibold leading-[2.375rem] text-text-primary text-[0.8125rem] md:text-h3 whitespace-nowrap not-italic">
lg: instead, so the full phrase fits on one line within
the column's width — text-h3's own 19px floor was still
too wide for that, both on a 375px phone AND in the
~283-320px Tablet grid column. */}
<span className="font-semibold leading-[2.375rem] text-text-primary text-[0.8125rem] lg:text-h3 whitespace-nowrap not-italic">
Starte mit der 7-Tage-Challenge
</span>
{/* Scaled down to match the smaller mobile CTA text (same
~0.76 aspect ratio as the md: size), full size again from
md: up alongside text-h3. */}
<div className="relative h-[0.8125rem] w-[1.0625rem] md:h-[1.1875rem] md:w-[1.5625rem] shrink-0">
<Image alt="" src="/icon-check.svg" fill sizes="(min-width: 768px) 26px, 17px" />
{/* Scaled down to match the smaller CTA text (same ~0.76
aspect ratio as the lg: size), full size again from lg: up
alongside text-h3. */}
<div className="relative h-[0.8125rem] w-[1.0625rem] lg:h-[1.1875rem] lg:w-[1.5625rem] shrink-0">
<Image alt="" src="/icon-check.svg" fill sizes="(min-width: 1024px) 26px, 17px" />
</div>
</Link>
{/* Social proof — always avatars-then-text on two lines below
md: (not just when it happens to overflow), single row again
from md: up where the real column width fits it fine. */}
<div className="flex flex-col md:flex-row gap-3 items-center justify-center overflow-clip shrink-0 w-full">
lg: (not just when it happens to overflow), single row again
from lg: up where the real column width fits it fine. */}
<div className="flex flex-col lg:flex-row gap-3 items-center justify-center overflow-clip shrink-0 w-full">
{/* Avatars — gap 2px, not overlapping */}
<div className="flex gap-[0.125rem] items-center shrink-0">
{["/avatar-1.jpg", "/avatar-2.jpg", "/avatar-3.jpg"].map((src, i) => (