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
+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) => (