From 89f6ab505d2944f3689c77b601e11e145458db31 Mon Sep 17 00:00:00 2001 From: Jeffrey Date: Thu, 26 Feb 2026 10:32:23 +0100 Subject: [PATCH] feat: mobile typography overhaul + layout fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typography: - Raise all fd-* token minimums in globals.css for larger mobile text (fd-h1: 28→40px, fd-h2: 22→32px, fd-h3: 18→22px, body-lg: 15→18px, body: 14→16px) - Strip all text-[x] sm:text-fd-* overrides from 25 block components — tokens now handle full range, no block-level hacks - Change RichText enableGutter default to false — fixes rich text indenting in FAQ, TextBlock, posts, and form confirmations Layout fixes (mobile): - FDContactBlock: 3-column grid on all screen sizes - FDHeroBlock: full-width buttons on mobile - FDServicesGridBlock: px-3 padding on description text under images - FDWideCardBlock: image now padded inside card, object-contain, no longer bleeds edge-to-edge - FDCtaSideImageBlock: consistent mobile order (heading → image → body → button) regardless of imagePosition setting; extra mt-4 between body and button on mobile - FDTestimonialBlock: quote text sizes migrated to fd-h3/fd-body-lg tokens --- src/app/(frontend)/globals.css | 16 ++-- src/blocks/FDContactBlock/Component.tsx | 4 +- src/blocks/FDCtaBannerBlock/Component.tsx | 10 +-- src/blocks/FDCtaSideImageBlock/Component.tsx | 76 ++++++++++--------- src/blocks/FDDataTableBlock/Component.tsx | 6 +- src/blocks/FDFaqBlock/Component.tsx | 10 +-- .../FDFeatureAnnouncementBlock/Component.tsx | 2 +- src/blocks/FDHeroBlock/Component.tsx | 6 +- src/blocks/FDLocationsGridBlock/Component.tsx | 5 +- src/blocks/FDPartnersLogosBlock/Component.tsx | 42 +++++----- src/blocks/FDPricingCardBlock/Component.tsx | 1 + .../FDServiceCalculatorBlock/Component.tsx | 2 +- src/blocks/FDServicesGridBlock/Component.tsx | 2 +- src/blocks/FDStatisticsBlock/Component.tsx | 2 +- src/blocks/FDTestimonialBlock/Component.tsx | 6 +- src/blocks/FDVpsCalculatorBlock/Component.tsx | 2 +- src/blocks/FDWideCardBlock/Component.tsx | 11 ++- src/components/RichText/index.tsx | 2 +- src/payload-types.ts | 6 ++ tsconfig.tsbuildinfo | 2 +- 20 files changed, 111 insertions(+), 102 deletions(-) diff --git a/src/app/(frontend)/globals.css b/src/app/(frontend)/globals.css index 4a33322..c14e823 100644 --- a/src/app/(frontend)/globals.css +++ b/src/app/(frontend)/globals.css @@ -379,37 +379,37 @@ html:not([data-theme]) { Usage: text-fd-display, text-fd-h1, text-fd-body, etc. */ /* Level 1 — Display / Hero H1 */ - --text-fd-display: clamp(2.25rem, 5vw + 0.5rem, 4.875rem); /* 36px → 78px */ + --text-fd-display: clamp(2.75rem, 5vw + 0.5rem, 4.875rem); /* 44px → 78px */ --text-fd-display--line-height: 1.05; --text-fd-display--letter-spacing: -0.02em; /* Level 2 — Section H1 */ - --text-fd-h1: clamp(1.75rem, 3.5vw + 0.25rem, 3.125rem); /* 28px → 50px */ + --text-fd-h1: clamp(2.5rem, 3.5vw + 0.25rem, 3.125rem); /* 40px → 50px */ --text-fd-h1--line-height: 1.15; --text-fd-h1--letter-spacing: -0.01em; /* Level 3 — Block titles / H2 */ - --text-fd-h2: clamp(1.375rem, 2.5vw + 0.25rem, 2.25rem); /* 22px → 36px */ + --text-fd-h2: clamp(2rem, 2.5vw + 0.25rem, 2.25rem); /* 32px → 36px */ --text-fd-h2--line-height: 1.2; /* Level 4 — Card titles / H3 */ - --text-fd-h3: clamp(1.125rem, 2vw + 0.125rem, 1.75rem); /* 18px → 28px */ + --text-fd-h3: clamp(1.375rem, 2vw + 0.125rem, 1.75rem); /* 22px → 28px */ --text-fd-h3--line-height: 1.3; /* Level 5 — Subheadings / H4 */ - --text-fd-h4: clamp(1rem, 1.5vw + 0.125rem, 1.375rem); /* 16px → 22px */ + --text-fd-h4: clamp(1.125rem, 1.5vw + 0.125rem, 1.375rem); /* 18px → 22px */ --text-fd-h4--line-height: 1.4; /* Level 6 — Lead / large body */ - --text-fd-body-lg: clamp(0.9375rem, 1.2vw + 0.125rem, 1.25rem); /* 15px → 20px */ + --text-fd-body-lg: clamp(1.125rem, 1.2vw + 0.125rem, 1.25rem); /* 18px → 20px */ --text-fd-body-lg--line-height: 1.6; /* Level 7 — Body text */ - --text-fd-body: clamp(0.875rem, 1vw + 0.125rem, 1.0625rem); /* 14px → 17px */ + --text-fd-body: clamp(1rem, 1vw + 0.125rem, 1.0625rem); /* 16px → 17px */ --text-fd-body--line-height: 1.7; /* Level 8 — Small / captions */ - --text-fd-small: clamp(0.8125rem, 0.9vw + 0.0625rem, 0.9375rem); /* 13px → 15px */ + --text-fd-small: clamp(0.875rem, 0.9vw + 0.0625rem, 0.9375rem); /* 14px → 15px */ --text-fd-small--line-height: 1.6; /* Level 9 — Extra small / fine print */ diff --git a/src/blocks/FDContactBlock/Component.tsx b/src/blocks/FDContactBlock/Component.tsx index ead8dfa..e1d96fb 100644 --- a/src/blocks/FDContactBlock/Component.tsx +++ b/src/blocks/FDContactBlock/Component.tsx @@ -17,13 +17,13 @@ export const FDContactBlockComponent: React.FC = ({ {heading} -
+
{contactMethods?.map((method, index) => { const media = method.icon as Media const card = (
{media?.url && ( -
+
= ({ return (
-
+
-
+

{heading}

@@ -74,11 +74,11 @@ export const FDCtaBannerBlockComponent: React.FC = ({
{(ctaText || secondaryCtaText) && ( -
+
{ctaText && ( {ctaText} @@ -86,7 +86,7 @@ export const FDCtaBannerBlockComponent: React.FC = ({ {secondaryCtaText && secondaryCtaLink && ( {secondaryCtaText} diff --git a/src/blocks/FDCtaSideImageBlock/Component.tsx b/src/blocks/FDCtaSideImageBlock/Component.tsx index c2b0c40..0a6546f 100644 --- a/src/blocks/FDCtaSideImageBlock/Component.tsx +++ b/src/blocks/FDCtaSideImageBlock/Component.tsx @@ -47,46 +47,52 @@ export const FDCtaSideImageBlockComponent: React.FC = ? 'text-white' : 'text-fd-navy dark:text-white' - const textContent = ( -
-
-

- {heading} -

-

- {body} -

-
+ // Mobile order is always: heading → image → body → button + // Desktop order respects imagePosition (left/right) + // We achieve this by splitting heading from body+button and using CSS order - {ctaText && ( - - {ctaText} - - )} -
- ) - - const imageContent = hasImage ? ( -
- - {overlay &&
} -
- ) : null + const desktopTextOrder = imagePosition === 'left' ? 'min-[820px]:order-2' : 'min-[820px]:order-1' + const desktopImageOrder = imagePosition === 'left' ? 'min-[820px]:order-1' : 'min-[820px]:order-2' return (
-
- {imagePosition === 'left' ? ( - <>{imageContent}{textContent} - ) : ( - <>{textContent}{imageContent} +
+ + {/* Heading — always first on mobile */} +

+ {heading} +

+ + {/* Image — always second on mobile, position-aware on desktop */} + {hasImage && ( +
+ + {overlay &&
} +
)} + + {/* Text block — heading hidden on mobile (shown above), body+button always third */} +
+ {/* Heading shown only on desktop inside the text column */} +

+ {heading} +

+

+ {body} +

+ {ctaText && ( + + {ctaText} + + )} +
+
) diff --git a/src/blocks/FDDataTableBlock/Component.tsx b/src/blocks/FDDataTableBlock/Component.tsx index f6570a7..0fe9739 100644 --- a/src/blocks/FDDataTableBlock/Component.tsx +++ b/src/blocks/FDDataTableBlock/Component.tsx @@ -242,11 +242,7 @@ export const FDDataTableBlockComponent: React.FC = ({
)} - {!loading && !error && tableData && tableData.rows.length > 0 && ( -

- {tableData.rows.length} rader · {tableData.headers.length} kolumner -

- )} + {!loading && !error && tableData && tableData.rows.length > 0 && null}
diff --git a/src/blocks/FDFaqBlock/Component.tsx b/src/blocks/FDFaqBlock/Component.tsx index 01c6c02..0cb0eb8 100644 --- a/src/blocks/FDFaqBlock/Component.tsx +++ b/src/blocks/FDFaqBlock/Component.tsx @@ -54,13 +54,16 @@ export const FDFaqBlockComponent: React.FC = ({

{body}

diff --git a/src/blocks/FDHeroBlock/Component.tsx b/src/blocks/FDHeroBlock/Component.tsx index dbd538d..4163ed3 100644 --- a/src/blocks/FDHeroBlock/Component.tsx +++ b/src/blocks/FDHeroBlock/Component.tsx @@ -75,14 +75,14 @@ export const FDHeroBlockComponent: React.FC = ({ {body}

)} -
+
{ctaText && ( - + {ctaText} )} {secondaryCtaText && ( - + {secondaryCtaText} )} diff --git a/src/blocks/FDLocationsGridBlock/Component.tsx b/src/blocks/FDLocationsGridBlock/Component.tsx index 01d0eb1..ff8ef9c 100644 --- a/src/blocks/FDLocationsGridBlock/Component.tsx +++ b/src/blocks/FDLocationsGridBlock/Component.tsx @@ -38,7 +38,6 @@ export const FDLocationsGridBlockComponent: React.FC = ({ {(heading || description || ctaText) && (
{heading && ( - /* Priority #6: Was font-joey-medium — now font-joey-heavy for consistency with all section headings */

{heading}

@@ -49,7 +48,7 @@ export const FDLocationsGridBlockComponent: React.FC = ({ )} {ctaText && ( - {ctaText} → + {ctaText} )}
@@ -60,7 +59,7 @@ export const FDLocationsGridBlockComponent: React.FC = ({ {(cards ?? []).map((card, i) => { const media = card.image as Media | undefined const isLink = Boolean(card.link) - const className = `group relative overflow-hidden rounded-[32px] md:rounded-[50px] lg:rounded-[70px] aspect-[4/3] block ${isLink ? 'cursor-pointer' : ''}` + const className = `group relative overflow-hidden rounded-[32px] md:rounded-[50px] lg:rounded-[70px] aspect-[16/9] sm:aspect-[4/3] block ${isLink ? 'cursor-pointer' : ''}` const inner = ( <> diff --git a/src/blocks/FDPartnersLogosBlock/Component.tsx b/src/blocks/FDPartnersLogosBlock/Component.tsx index aa87300..d910da1 100644 --- a/src/blocks/FDPartnersLogosBlock/Component.tsx +++ b/src/blocks/FDPartnersLogosBlock/Component.tsx @@ -26,32 +26,34 @@ export const FDPartnersLogosBlockComponent: React.FC
{heading && ( - /* Priority #6: Was font-joey-medium — now font-joey-heavy for section heading consistency */

{heading}

)} -
- {(logos ?? []).map((item, i) => { - const media = item.image as Media | undefined - if (!media?.url) return null + {/* Mobile: horizontal scroll. Desktop: wrap grid */} +
+
+ {(logos ?? []).map((item, i) => { + const media = item.image as Media | undefined + if (!media?.url) return null - const logoEl = ( - {item.alt - ) + const logoEl = ( + {item.alt + ) - return item.link ? ( - - {logoEl} - - ) : ( -
{logoEl}
- ) - })} + return item.link ? ( + + {logoEl} + + ) : ( +
{logoEl}
+ ) + })} +
diff --git a/src/blocks/FDPricingCardBlock/Component.tsx b/src/blocks/FDPricingCardBlock/Component.tsx index cc4d4b3..8d598b4 100644 --- a/src/blocks/FDPricingCardBlock/Component.tsx +++ b/src/blocks/FDPricingCardBlock/Component.tsx @@ -131,6 +131,7 @@ export const FDPricingCardBlockComponent: React.FC = ({ href={card.ctaLink || '#'} variant={variant} onDark={variant === 'outline' ? outlineOnDark : style.isDark} + className="w-full sm:w-auto justify-center" > {card.ctaText}
diff --git a/src/blocks/FDServiceCalculatorBlock/Component.tsx b/src/blocks/FDServiceCalculatorBlock/Component.tsx index e113a77..deeda08 100644 --- a/src/blocks/FDServiceCalculatorBlock/Component.tsx +++ b/src/blocks/FDServiceCalculatorBlock/Component.tsx @@ -52,7 +52,7 @@ function ResourceRow({ style={{ appearance: 'textfield' }} aria-label={label} /> - {unit} + {unit}
diff --git a/src/blocks/FDStatisticsBlock/Component.tsx b/src/blocks/FDStatisticsBlock/Component.tsx index 4569ef3..49b4b58 100644 --- a/src/blocks/FDStatisticsBlock/Component.tsx +++ b/src/blocks/FDStatisticsBlock/Component.tsx @@ -82,7 +82,7 @@ export const FDStatisticsBlockComponent: React.FC = ({ }`} style={prefersReducedMotion ? undefined : { transitionDelay: `${i * 120}ms` }} > - + {stat.number} diff --git a/src/blocks/FDTestimonialBlock/Component.tsx b/src/blocks/FDTestimonialBlock/Component.tsx index e01c8fb..0a60599 100644 --- a/src/blocks/FDTestimonialBlock/Component.tsx +++ b/src/blocks/FDTestimonialBlock/Component.tsx @@ -80,7 +80,7 @@ export const FDTestimonialBlockComponent: React.FC = ({ const avatar = t.avatar as Media | undefined return (
-

+

“{t.quote}”

@@ -102,7 +102,7 @@ export const FDTestimonialBlockComponent: React.FC = ({ const avatar = t.avatar as Media | undefined return (
-

+

“{t.quote}”

@@ -129,7 +129,7 @@ export const FDTestimonialBlockComponent: React.FC = ({ -

+

{t.quote}

diff --git a/src/blocks/FDVpsCalculatorBlock/Component.tsx b/src/blocks/FDVpsCalculatorBlock/Component.tsx index 1b7a8b0..9969b5b 100644 --- a/src/blocks/FDVpsCalculatorBlock/Component.tsx +++ b/src/blocks/FDVpsCalculatorBlock/Component.tsx @@ -54,7 +54,7 @@ function ResourceRow({ className="w-20 text-center font-joey-medium text-fd-body-lg rounded-full px-2 py-1.5 border-2 bg-fd-surface-alt border-fd-navy/15 text-fd-navy dark:bg-white/10 dark:border-white/20 dark:text-white [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none" style={{ appearance: 'textfield' }} /> - {unit} + {unit}