diff --git a/README.md b/README.md index a030126..15e7ece 100644 --- a/README.md +++ b/README.md @@ -1479,6 +1479,40 @@ while auditing every page's metadata were fixed in the same pass: 3 route (now uses the real order number), and `/shop`/`/blog` were missing an Open Graph image. +## Tablet responsive fixes (2026-07-24) + +A follow-up to the Mobile pass above — testing at real Tablet widths +(768-1023px) surfaced a few spots where the Mobile-focused fixes had left +Tablet worse off than before, or where a component's own structural +breakpoint no longer needed to be as conservative as originally set: + +- **`Hero.tsx` reverted from `lg:` back to `md:` as its structural + breakpoint.** It was moved to `lg:` earlier (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 then-full-size CTA/subtitle text made the whole + row wrap to 3 cramped lines. The smaller fixed CTA/subtitle/icon sizes + added during the Mobile pass (for true phone widths) are well under half + that column's width, so the original wrapping problem doesn't recur — + moving back to `md:` means Tablet gets the real 5/7 grid (image beside + text) again instead of a phone-style stacked layout. Every `lg:`-gated + size override in that file moved to `md:` to match. +- **`Tools.tsx`'s card icon** — full 56px size pushed from `md:` to `lg:`; + at Tablet the title/description text is still close to its own fluid + floor, and the full-size icon read as too big next to it. +- **`About.tsx`'s text/photo columns** — the Desktop overlap layout + (`flex-[1.4_0_0]` on the photo, `-ml-48`, gradient) kicked in from `md:` + already, giving the text column (fixed against the smaller 1:1.4 share) + too little room for its fixed-width statement + quote/bio row at Tablet. + The ratio is swapped at Tablet (text gets the bigger 1.4 share, photo the + smaller one, no overlap) and reverts to the original ratio + overlap only + from `lg:` up, where it was designed for. +- **`Newsletter.tsx`'s input+submit row** and **`Footer.tsx`'s logo/handle/ + legal-links row** — both went side-by-side at `md:`, but the columns + around them (the newsletter card's fixed-width copy column; the footer's + 3 groups sharing one `justify-between` row) didn't leave enough width at + 768px. Both pushed from `md:flex-row` to `lg:flex-row` — stacked through + the whole Tablet range, side by side again once there's real room. + ## Tests `npm run test:unit` (Vitest, `node` environment, no jsdom/Next.js runtime diff --git a/app/components/About.tsx b/app/components/About.tsx index 362fb89..9dd0f89 100644 --- a/app/components/About.tsx +++ b/app/components/About.tsx @@ -6,9 +6,16 @@ export function About() {
{/* Text content — relative + z-10 so it renders above the overlapping - photo at md+. Comes first in DOM at every breakpoint (no reorder - here — unlike Hero, there's no conversion CTA at stake). */} - + photo at lg+. Comes first in DOM at every breakpoint (no reorder + here — unlike Hero, there's no conversion CTA at stake). + md:flex-[1.4_0_0] lg:flex-[1_0_0] — at Tablet the text column got + the narrower 1:1.4 share meant for Desktop's overlap layout, + leaving it too cramped for the fixed-width statement + quote/bio + row. Widened at Tablet (text gets the bigger share, image the + smaller one, no overlap yet) and reverted to the original ratio + from lg: up, where the overlap trick actually needs the image to + have more room. */} + {/* Large serif statement — width-constrained as per design */}

- {/* Author photo — overlaps the text column via -ml-48 from md+ only - (that overlap trick has nothing to blend into once stacked); - plain full-width photo below the text on Mobile. */} + {/* Author photo — overlaps the text column via -ml-48 from lg+ only + (that overlap trick has nothing to blend into once stacked, and + at Tablet it would eat back into the extra width the text column + above just gained); plain full-width photo below the text on + Mobile, plain side-by-side (no overlap) at Tablet. */} @@ -80,11 +89,11 @@ export function About() { alt="Björn" src="/about-author.jpg" fill - sizes="(min-width: 768px) 58vw, 100vw" + sizes="(min-width: 1024px) 58vw, (min-width: 768px) 42vw, 100vw" className="object-cover object-center pointer-events-none" /> - {/* Left gradient: wide enough to cover the text-column overlap — md+ only */} -

+ {/* Left gradient: wide enough to cover the text-column overlap — lg+ only */} +
diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx index 848a7ad..3dee45e 100644 --- a/app/components/Footer.tsx +++ b/app/components/Footer.tsx @@ -18,8 +18,12 @@ export function Footer() { {/* Footer inner — max-width 1280px, centered */}
- {/* Three groups: logo | @handle | links — stacked + centered below md */} -
+ {/* Three groups: logo | @handle | links — stacked + centered below + lg: (was md:). Logo + handle + 5 legal links all side by side + with justify-between read too cramped on Tablet — stacked + through that range instead, side by side again once there's + real room at lg:. */} +
{/* Logo: "einfach produktiv" white + "." gold */}
diff --git a/app/components/Hero.tsx b/app/components/Hero.tsx index 1a4dfc6..bb97bf8 100644 --- a/app/components/Hero.tsx +++ b/app/components/Hero.tsx @@ -11,7 +11,7 @@ function HeroImage() { alt="" fill priority - sizes="(min-width: 1024px) 58vw, 100vw" + sizes="(min-width: 768px) 58vw, 100vw" className="object-cover" style={{ WebkitMaskImage: @@ -28,36 +28,39 @@ function HeroImage() { export function Hero() { return (
- {/* Structural breakpoint is lg: (1024px) here, not the site-wide md: - (768px) — a documented exception (see Gotcha in the figma-to-nextjs - skill). At md:col-span-5 the text column was only ~320px at - 768-1023px viewports, too narrow for the heading/CTA/social-proof - row (which wrapped to 3 cramped lines). Staying stacked full-width - through the whole Tablet range and only splitting into the 5/7 - grid once there's real room (≥1024px) fixes that without touching - the 5/7 ratio itself, which is fine once it has space. */} -
+ {/* 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. */} +
{/* Text content — first in DOM/visual order at every breakpoint so the CTA stays above the fold on Mobile (deliberate exception to the "keep DOM order" default, see Hero decision in the plan). Reveal fires ~immediately since Hero is already in the initial viewport — this doubles as the page's entrance animation. */} - + - {/* Heading — forced break after "darf" only in the sm-lg tablet - range (Hero stacked full-width, natural wrap there landed + {/* 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 lg: up too, once + little text above the CTA. Natural wrap from md: up too, once the 5/12 grid gives the column real width again. */}

- Produktivität darf
sich leicht anfühlen + Produktivität darf
sich leicht anfühlen
{/* Brand's signature orange dot (also in the logo/footer) — bouncy pop-in once the heading scrolls into view, timed to @@ -70,10 +73,10 @@ export function Hero() {

- {/* Subheading — smaller fixed size below lg:, text-h-emphasis's + {/* 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. */} -

+

Für Menschen mit Familie, Verantwortung und zu wenig Zeit

@@ -82,28 +85,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 lg: (tried 2026-07-24) + {/* Letting this wrap to two lines below md: (tried 2026-07-24) put the icon beside a two-line text block, which read as broken rather than intentional. Smaller fixed size below - lg: instead, so the full phrase fits on one line within + 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. */} - + Starte mit der 7-Tage-Challenge {/* Scaled down to match the smaller mobile CTA text (same - ~0.76 aspect ratio as the lg: size), full size again from - lg: up alongside text-h3. */} -
- + ~0.76 aspect ratio as the md: size), full size again from + md: up alongside text-h3. */} +
+
{/* Social proof — always avatars-then-text on two lines below - lg: (not just when it happens to overflow), single row again - from lg: up where the real column width fits it fine. */} -
+ md: (not just when it happens to overflow), single row again + from md: up where the real column width fits it fine. */} +
{/* Avatars — gap 2px, not overlapping */}
{["/avatar-1.jpg", "/avatar-2.jpg", "/avatar-3.jpg"].map((src, i) => ( @@ -123,33 +126,29 @@ export function Hero() { {/* Image — bleeds to the true edge at every breakpoint (never - padded). Below lg: (stacked layout) the full 887:583 aspect + padded). Below md: (stacked layout) the full 887:583 aspect ratio at 100vw would make the image ~600-900px tall and dominate the page, so height is capped and object-cover crops - it into a supporting banner instead; at lg:+ (grid, image only + it into a supporting banner instead; at md:+ (grid, image only 58% width) the full aspect ratio looks right again, so the cap - is lifted. A small negative top margin below lg: pulls it up to - slightly tuck under the text block (deliberately less than the - social-proof row's height, so it never covers the avatars/text). - Scoped to md:-only (mt-0 at base and again at lg:) — it's a - Tablet-specific touch, not a permanent effect. No shadow: a - plain box-shadow reads as a hard rectangular edge against the - existing corner/right/bottom mask-gradient fade below, which - looked worse than no shadow at all — tried and reverted. */} - {/* No Reveal (fade-in-on-scroll) below lg: — whileInView's -80px + is lifted. No shadow: a plain box-shadow reads as a hard + rectangular edge against the existing corner/right/bottom + mask-gradient fade below, which looked worse than no shadow at + all — tried and reverted. */} + {/* No Reveal (fade-in-on-scroll) below md: — whileInView's -80px viewport margin means the image doesn't fade in until scrolled that much further into view; on a short mobile viewport this image sits right at the initial fold, so it stayed at opacity:0 (a white gap, matching the section's own bg-bg-base) above the fold until the user scrolled (reported 2026-07-24). - Plain, always-visible image below lg: instead; Reveal's fade - kept from lg: up, where the image is beside the text with + Plain, always-visible image below md: instead; Reveal's fade + kept from md: up, where the image is beside the text with plenty of room and this was never an issue. */} -
+
diff --git a/app/components/Newsletter.tsx b/app/components/Newsletter.tsx index 810dea0..2e83b4f 100644 --- a/app/components/Newsletter.tsx +++ b/app/components/Newsletter.tsx @@ -98,8 +98,14 @@ export function Newsletter({ ) : (
- {/* Input + submit button — stacked below md, side by side from md+ */} -
+ {/* Input + submit button — stacked below lg: (was md:). + The card above already goes side-by-side at md: with a + fixed-width copy column (--newsletter-copy-width), which + only leaves ~200px for this form column at 768px — not + enough room for input+button side by side. Stacked + through the whole Tablet range instead, side by side + again once the form column has real room at lg:. */} +
- + which does shrink toward its own fluid floor there. Full + 56px only from lg: up — at md: (Tablet, where this grid + already switches to 3-up) the title/description are still + fairly close to their own fluid floor, so the full-size + icon read as too big next to them too. */} +
+
{/* Card content — self-stretch + h-full + justify-between so