feat: mobile typography overhaul + layout fixes

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
This commit is contained in:
Jeffrey 2026-02-26 10:32:23 +01:00
parent 82d2e48ee5
commit 89f6ab505d
20 changed files with 111 additions and 102 deletions

View File

@ -379,37 +379,37 @@ html:not([data-theme]) {
Usage: text-fd-display, text-fd-h1, text-fd-body, etc. */ Usage: text-fd-display, text-fd-h1, text-fd-body, etc. */
/* Level 1 — Display / Hero H1 */ /* 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--line-height: 1.05;
--text-fd-display--letter-spacing: -0.02em; --text-fd-display--letter-spacing: -0.02em;
/* Level 2 — Section H1 */ /* 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--line-height: 1.15;
--text-fd-h1--letter-spacing: -0.01em; --text-fd-h1--letter-spacing: -0.01em;
/* Level 3 — Block titles / H2 */ /* 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; --text-fd-h2--line-height: 1.2;
/* Level 4 — Card titles / H3 */ /* 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; --text-fd-h3--line-height: 1.3;
/* Level 5 — Subheadings / H4 */ /* 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; --text-fd-h4--line-height: 1.4;
/* Level 6 — Lead / large body */ /* 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; --text-fd-body-lg--line-height: 1.6;
/* Level 7 — Body text */ /* 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; --text-fd-body--line-height: 1.7;
/* Level 8 — Small / captions */ /* 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; --text-fd-small--line-height: 1.6;
/* Level 9 — Extra small / fine print */ /* Level 9 — Extra small / fine print */

View File

@ -17,13 +17,13 @@ export const FDContactBlockComponent: React.FC<FDContactBlockProps> = ({
{heading} {heading}
</h2> </h2>
<div className="flex flex-col sm:flex-row items-stretch gap-4 md:gap-7 w-full max-w-[656px]"> <div className="grid grid-cols-3 gap-4 md:gap-7 w-full max-w-[656px]">
{contactMethods?.map((method, index) => { {contactMethods?.map((method, index) => {
const media = method.icon as Media const media = method.icon as Media
const card = ( const card = (
<div className="flex-1 flex flex-col items-center gap-3 md:gap-5 cursor-pointer transition-transform hover:scale-105"> <div className="flex-1 flex flex-col items-center gap-3 md:gap-5 cursor-pointer transition-transform hover:scale-105">
{media?.url && ( {media?.url && (
<div className={`relative w-full h-[140px] sm:h-[120px] md:h-[160px] lg:h-[200px] overflow-hidden ${imageRadius}`}> <div className={`relative w-full h-[100px] sm:h-[120px] md:h-[160px] lg:h-[200px] overflow-hidden ${imageRadius}`}>
<FDImage <FDImage
media={media} media={media}
size="medium" size="medium"

View File

@ -60,9 +60,9 @@ export const FDCtaBannerBlockComponent: React.FC<FDCtaBannerBlockProps> = ({
return ( return (
<section id={anchorId || undefined} className={`w-full ${sizing.py} ${theme.section}`}> <section id={anchorId || undefined} className={`w-full ${sizing.py} ${theme.section}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8"> <div className="max-w-[1200px] mx-auto px-6 md:px-8">
<div className={`flex flex-col gap-6 md:gap-8 ${isCenter ? 'items-center text-center' : 'items-start text-left'} max-w-[800px] ${isCenter ? 'mx-auto' : ''}`}> <div className={`flex flex-col gap-6 md:gap-8 items-center text-center min-[820px]:${isCenter ? 'items-center text-center' : 'items-start text-left'} max-w-[800px] ${isCenter ? 'mx-auto' : ''}`}>
<div className={`flex flex-col gap-3 ${isCenter ? 'items-center' : 'items-start'}`}> <div className={`flex flex-col gap-3 items-center min-[820px]:${isCenter ? 'items-center' : 'items-start'}`}>
<h2 className={`font-joey-heavy leading-tight ${sizing.heading} ${theme.heading}`}> <h2 className={`font-joey-heavy leading-tight ${sizing.heading} ${theme.heading}`}>
{heading} {heading}
</h2> </h2>
@ -74,11 +74,11 @@ export const FDCtaBannerBlockComponent: React.FC<FDCtaBannerBlockProps> = ({
</div> </div>
{(ctaText || secondaryCtaText) && ( {(ctaText || secondaryCtaText) && (
<div className={`flex flex-col sm:flex-row gap-4 ${isCenter ? 'justify-center' : ''}`}> <div className={`flex flex-col sm:flex-row gap-4 w-full sm:w-auto ${isCenter ? 'justify-center' : ''}`}>
{ctaText && ( {ctaText && (
<a <a
href={ctaLink || '#'} href={ctaLink || '#'}
className={`inline-flex items-center justify-center px-8 py-3 rounded-full font-joey-bold text-fd-btn transition-colors ${theme.primaryBtn}`} className={`inline-flex items-center justify-center px-8 py-3 rounded-full font-joey-bold text-fd-btn transition-colors w-full sm:w-auto ${theme.primaryBtn}`}
> >
{ctaText} {ctaText}
</a> </a>
@ -86,7 +86,7 @@ export const FDCtaBannerBlockComponent: React.FC<FDCtaBannerBlockProps> = ({
{secondaryCtaText && secondaryCtaLink && ( {secondaryCtaText && secondaryCtaLink && (
<a <a
href={secondaryCtaLink} href={secondaryCtaLink}
className={`inline-flex items-center justify-center px-8 py-3 rounded-full font-joey-bold text-fd-btn transition-colors ${theme.secondaryBtn}`} className={`inline-flex items-center justify-center px-8 py-3 rounded-full font-joey-bold text-fd-btn transition-colors w-full sm:w-auto ${theme.secondaryBtn}`}
> >
{secondaryCtaText} {secondaryCtaText}
</a> </a>

View File

@ -47,46 +47,52 @@ export const FDCtaSideImageBlockComponent: React.FC<FDCtaSideImageBlockProps> =
? 'text-white' ? 'text-white'
: 'text-fd-navy dark:text-white' : 'text-fd-navy dark:text-white'
const textContent = ( // Mobile order is always: heading → image → body → button
<div className={`flex flex-col flex-1 items-start gap-8 min-[820px]:gap-[41px] ${!hasImage ? 'max-w-2xl' : ''}`}> // Desktop order respects imagePosition (left/right)
<div className="flex flex-col items-start gap-4 w-full"> // We achieve this by splitting heading from body+button and using CSS order
<h2 className={`w-full font-joey-heavy text-fd-h1 leading-tight ${headingClass}`}>
{heading}
</h2>
<p className={`w-full font-joey text-fd-body-lg leading-relaxed ${bodyClass}`}>
{body}
</p>
</div>
{ctaText && ( const desktopTextOrder = imagePosition === 'left' ? 'min-[820px]:order-2' : 'min-[820px]:order-1'
<FDButton href={ctaLink || '#'} variant="primary" onDark={isDark}> const desktopImageOrder = imagePosition === 'left' ? 'min-[820px]:order-1' : 'min-[820px]:order-2'
{ctaText}
</FDButton>
)}
</div>
)
const imageContent = hasImage ? (
<div className={`relative w-full min-[820px]:w-[45%] lg:w-[575px] lg:h-[479px] flex-shrink-0 overflow-hidden ${imageRadius}`}>
<FDImage
media={image as Media}
size="large"
fallbackAlt={heading}
className="w-full h-full object-cover"
sizes="(max-width: 1024px) 100vw, 575px"
/>
{overlay && <div className={`absolute inset-0 ${overlay}`} />}
</div>
) : null
return ( return (
<section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}> <section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col min-[820px]:flex-row items-center gap-10 min-[820px]:gap-16"> <div className="max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col min-[820px]:flex-row min-[820px]:items-center gap-6 min-[820px]:gap-16">
{imagePosition === 'left' ? (
<>{imageContent}{textContent}</> {/* Heading — always first on mobile */}
) : ( <h2 className={`w-full font-joey-heavy text-fd-h1 leading-tight order-1 min-[820px]:hidden ${headingClass}`}>
<>{textContent}{imageContent}</> {heading}
</h2>
{/* Image — always second on mobile, position-aware on desktop */}
{hasImage && (
<div className={`relative w-full min-[820px]:w-[45%] lg:w-[575px] lg:h-[479px] flex-shrink-0 overflow-hidden order-2 ${desktopImageOrder} ${imageRadius}`}>
<FDImage
media={image as Media}
size="large"
fallbackAlt={heading}
className="w-full h-full object-cover"
sizes="(max-width: 1024px) 100vw, 575px"
/>
{overlay && <div className={`absolute inset-0 ${overlay}`} />}
</div>
)} )}
{/* Text block — heading hidden on mobile (shown above), body+button always third */}
<div className={`flex flex-col flex-1 items-start gap-4 min-[820px]:gap-[41px] order-3 ${desktopTextOrder} ${!hasImage ? 'max-w-2xl' : ''}`}>
{/* Heading shown only on desktop inside the text column */}
<h2 className={`hidden min-[820px]:block w-full font-joey-heavy text-fd-h1 leading-tight ${headingClass}`}>
{heading}
</h2>
<p className={`w-full font-joey text-fd-body-lg leading-relaxed ${bodyClass}`}>
{body}
</p>
{ctaText && (
<FDButton href={ctaLink || '#'} variant="primary" onDark={isDark} className="w-full sm:w-auto justify-center mt-4 min-[820px]:mt-0">
{ctaText}
</FDButton>
)}
</div>
</div> </div>
</section> </section>
) )

View File

@ -242,11 +242,7 @@ export const FDDataTableBlockComponent: React.FC<Props> = ({
</div> </div>
)} )}
{!loading && !error && tableData && tableData.rows.length > 0 && ( {!loading && !error && tableData && tableData.rows.length > 0 && null}
<p className={`mt-3 font-joey text-fd-xs opacity-40 ${bodyClass}`}>
{tableData.rows.length} rader · {tableData.headers.length} kolumner
</p>
)}
</div> </div>
</section> </section>

View File

@ -54,13 +54,16 @@ export const FDFaqBlockComponent: React.FC<FDFaqBlockProps> = ({
<div key={index} className={`border-b ${borderColor}`}> <div key={index} className={`border-b ${borderColor}`}>
<button <button
id={triggerId} id={triggerId}
className={`flex w-full items-center gap-3 md:gap-4 py-4 md:py-5 text-left transition-colors ${textColor}`} className={`flex w-full items-center justify-between gap-3 md:gap-4 py-4 md:py-5 text-left transition-colors ${textColor}`}
onClick={() => setOpenIndex(isOpen ? null : index)} onClick={() => setOpenIndex(isOpen ? null : index)}
aria-expanded={isOpen} aria-expanded={isOpen}
aria-controls={panelId} aria-controls={panelId}
> >
<span className="font-joey text-fd-h3">
{item.question}
</span>
<svg <svg
className={`w-4 h-4 md:w-5 md:h-5 flex-shrink-0 transition-transform duration-200 ${ className={`w-5 h-5 flex-shrink-0 transition-transform duration-200 ${
isOpen ? 'rotate-45' : '' isOpen ? 'rotate-45' : ''
}`} }`}
viewBox="0 0 20 20" viewBox="0 0 20 20"
@ -72,9 +75,6 @@ export const FDFaqBlockComponent: React.FC<FDFaqBlockProps> = ({
<line x1="10" y1="2" x2="10" y2="18" /> <line x1="10" y1="2" x2="10" y2="18" />
<line x1="2" y1="10" x2="18" y2="10" /> <line x1="2" y1="10" x2="18" y2="10" />
</svg> </svg>
<span className="font-joey text-fd-h3">
{item.question}
</span>
</button> </button>
<div <div
id={panelId} id={panelId}

View File

@ -41,7 +41,7 @@ export const FDFeatureAnnouncementBlockComponent: React.FC<FDFeatureAnnouncement
</h2> </h2>
<p <p
className={`w-full max-w-[1112px] font-joey text-xl md:text-2xl lg:text-4xl text-center leading-relaxed ${bodyColor}`} className={`w-full max-w-[1112px] font-joey text-xl md:text-fd-body-lg text-center leading-relaxed ${bodyColor}`}
> >
{body} {body}
</p> </p>

View File

@ -75,14 +75,14 @@ export const FDHeroBlockComponent: React.FC<FDHeroBlockProps> = ({
{body} {body}
</p> </p>
)} )}
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4"> <div className="flex flex-col items-stretch sm:flex-row sm:items-center gap-4 w-full sm:w-auto">
{ctaText && ( {ctaText && (
<FDButton href={ctaLink || '#'} variant="primary" onDark={isDark}> <FDButton href={ctaLink || '#'} variant="primary" onDark={isDark} className="w-full sm:w-auto justify-center">
{ctaText} {ctaText}
</FDButton> </FDButton>
)} )}
{secondaryCtaText && ( {secondaryCtaText && (
<FDButton href={secondaryCtaLink || '#'} variant="outline" onDark={secondaryOnDark}> <FDButton href={secondaryCtaLink || '#'} variant="outline" onDark={secondaryOnDark} className="w-full sm:w-auto justify-center">
{secondaryCtaText} {secondaryCtaText}
</FDButton> </FDButton>
)} )}

View File

@ -38,7 +38,6 @@ export const FDLocationsGridBlockComponent: React.FC<Props> = ({
{(heading || description || ctaText) && ( {(heading || description || ctaText) && (
<div className="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6 mb-12 md:mb-16"> <div className="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6 mb-12 md:mb-16">
{heading && ( {heading && (
/* Priority #6: Was font-joey-medium — now font-joey-heavy for consistency with all section headings */
<h2 className={`font-joey-heavy text-fd-h1 ${titleClass} lg:max-w-[380px]`}> <h2 className={`font-joey-heavy text-fd-h1 ${titleClass} lg:max-w-[380px]`}>
{heading} {heading}
</h2> </h2>
@ -49,7 +48,7 @@ export const FDLocationsGridBlockComponent: React.FC<Props> = ({
)} )}
{ctaText && ( {ctaText && (
<a href={ctaLink || '#'} className="self-start fd-btn-primary"> <a href={ctaLink || '#'} className="self-start fd-btn-primary">
{ctaText} {ctaText}
</a> </a>
)} )}
</div> </div>
@ -60,7 +59,7 @@ export const FDLocationsGridBlockComponent: React.FC<Props> = ({
{(cards ?? []).map((card, i) => { {(cards ?? []).map((card, i) => {
const media = card.image as Media | undefined const media = card.image as Media | undefined
const isLink = Boolean(card.link) 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 = ( const inner = (
<> <>

View File

@ -26,32 +26,34 @@ export const FDPartnersLogosBlockComponent: React.FC<FDPartnersLogosBlockProps>
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${bgClass}`}> <section className={`w-full py-16 md:py-20 lg:py-[99px] ${bgClass}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8"> <div className="max-w-[1200px] mx-auto px-6 md:px-8">
{heading && ( {heading && (
/* Priority #6: Was font-joey-medium — now font-joey-heavy for section heading consistency */
<h2 className={`font-joey-heavy text-fd-h2 text-center mb-10 md:mb-14 ${titleClass}`}> <h2 className={`font-joey-heavy text-fd-h2 text-center mb-10 md:mb-14 ${titleClass}`}>
{heading} {heading}
</h2> </h2>
)} )}
<div className="flex flex-wrap items-center justify-center gap-10 md:gap-14 lg:gap-16"> {/* Mobile: horizontal scroll. Desktop: wrap grid */}
{(logos ?? []).map((item, i) => { <div className="overflow-x-auto pb-2 sm:overflow-visible sm:pb-0 -mx-6 px-6 sm:mx-0 sm:px-0">
const media = item.image as Media | undefined <div className="flex sm:flex-wrap items-center justify-start sm:justify-center gap-8 sm:gap-10 md:gap-14 lg:gap-16 min-w-max sm:min-w-0">
if (!media?.url) return null {(logos ?? []).map((item, i) => {
const media = item.image as Media | undefined
if (!media?.url) return null
const logoEl = ( const logoEl = (
<img <img
src={media.url} src={media.url}
alt={item.alt || ''} alt={item.alt || ''}
className={`h-12 md:h-16 lg:h-[72px] w-auto max-w-[180px] md:max-w-[220px] object-contain ${imgFilter}`} className={`h-14 sm:h-12 md:h-16 lg:h-[72px] w-auto max-w-[160px] sm:max-w-[180px] md:max-w-[220px] object-contain ${imgFilter}`}
/> />
) )
return item.link ? ( return item.link ? (
<a key={i} href={item.link} target="_blank" rel="noopener noreferrer" className="flex items-center justify-center"> <a key={i} href={item.link} target="_blank" rel="noopener noreferrer" className="flex items-center justify-center flex-shrink-0">
{logoEl} {logoEl}
</a> </a>
) : ( ) : (
<div key={i} className="flex items-center justify-center">{logoEl}</div> <div key={i} className="flex items-center justify-center flex-shrink-0">{logoEl}</div>
) )
})} })}
</div>
</div> </div>
</div> </div>
</section> </section>

View File

@ -131,6 +131,7 @@ export const FDPricingCardBlockComponent: React.FC<FDPricingCardBlockProps> = ({
href={card.ctaLink || '#'} href={card.ctaLink || '#'}
variant={variant} variant={variant}
onDark={variant === 'outline' ? outlineOnDark : style.isDark} onDark={variant === 'outline' ? outlineOnDark : style.isDark}
className="w-full sm:w-auto justify-center"
> >
{card.ctaText} {card.ctaText}
</FDButton> </FDButton>

View File

@ -52,7 +52,7 @@ function ResourceRow({
style={{ appearance: 'textfield' }} style={{ appearance: 'textfield' }}
aria-label={label} aria-label={label}
/> />
<span className="font-joey text-fd-body w-8 text-fd-navy/40 dark:text-white/40">{unit}</span> <span className="hidden sm:inline font-joey text-fd-body w-8 text-fd-navy/40 dark:text-white/40">{unit}</span>
<button <button
type="button" type="button"
onClick={() => onChange(Math.min(max, value + step))} onClick={() => onChange(Math.min(max, value + step))}

View File

@ -44,7 +44,7 @@ export const FDServicesGridBlockComponent: React.FC<FDServicesGridBlockProps> =
/> />
)} )}
<p className="font-joey text-fd-navy dark:text-white/80 text-fd-body"> <p className="font-joey text-fd-navy dark:text-white/80 text-fd-body px-3">
{service.description} {service.description}
</p> </p>
</div> </div>

View File

@ -82,7 +82,7 @@ export const FDStatisticsBlockComponent: React.FC<Props> = ({
}`} }`}
style={prefersReducedMotion ? undefined : { transitionDelay: `${i * 120}ms` }} style={prefersReducedMotion ? undefined : { transitionDelay: `${i * 120}ms` }}
> >
<span className={`font-joey-heavy text-5xl md:text-7xl lg:text-[96px] leading-none ${getNumberClass()}`}> <span className={`font-joey-heavy text-[3.5rem] sm:text-5xl md:text-7xl lg:text-[96px] leading-none ${getNumberClass()}`}>
{stat.number} {stat.number}
</span> </span>
<span className={`font-joey text-fd-body max-w-[180px] ${labelClass}`}> <span className={`font-joey text-fd-body max-w-[180px] ${labelClass}`}>

View File

@ -80,7 +80,7 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
const avatar = t.avatar as Media | undefined const avatar = t.avatar as Media | undefined
return ( return (
<div className={`${theme.card} ${cardRadius} px-8 md:px-16 py-10 md:py-16 flex flex-col gap-8`}> <div className={`${theme.card} ${cardRadius} px-8 md:px-16 py-10 md:py-16 flex flex-col gap-8`}>
<p className={`font-joey-medium text-xl md:text-2xl lg:text-3xl leading-relaxed ${theme.quote}`}> <p className={`font-joey-medium text-fd-h3 leading-relaxed ${theme.quote}`}>
&ldquo;{t.quote}&rdquo; &ldquo;{t.quote}&rdquo;
</p> </p>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
@ -102,7 +102,7 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
const avatar = t.avatar as Media | undefined const avatar = t.avatar as Media | undefined
return ( return (
<div key={i} className={`${theme.card} ${cardRadius} px-8 md:px-12 py-10 md:py-12 flex flex-col gap-6`}> <div key={i} className={`${theme.card} ${cardRadius} px-8 md:px-12 py-10 md:py-12 flex flex-col gap-6`}>
<p className={`font-joey-medium text-lg md:text-xl leading-relaxed ${theme.quote}`}> <p className={`font-joey-medium text-fd-body-lg leading-relaxed ${theme.quote}`}>
&ldquo;{t.quote}&rdquo; &ldquo;{t.quote}&rdquo;
</p> </p>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
@ -129,7 +129,7 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
<span className={`font-joey-heavy text-5xl leading-none ${theme.accent} opacity-30`}> <span className={`font-joey-heavy text-5xl leading-none ${theme.accent} opacity-30`}>
&ldquo; &ldquo;
</span> </span>
<p className={`font-joey-medium text-lg leading-relaxed -mt-4 ${theme.quote}`}> <p className={`font-joey-medium text-fd-body-lg leading-relaxed -mt-4 ${theme.quote}`}>
{t.quote} {t.quote}
</p> </p>
<div className="flex items-center gap-3 mt-auto"> <div className="flex items-center gap-3 mt-auto">

View File

@ -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" 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' }} style={{ appearance: 'textfield' }}
/> />
<span className="font-joey text-fd-body w-8 text-fd-navy/40 dark:text-white/40">{unit}</span> <span className="hidden sm:inline font-joey text-fd-body w-8 text-fd-navy/40 dark:text-white/40">{unit}</span>
<button <button
type="button" type="button"
onClick={() => onChange(Math.min(max, value + step))} onClick={() => onChange(Math.min(max, value + step))}

View File

@ -44,7 +44,7 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
return ( return (
<section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}> <section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8"> <div className="max-w-[1200px] mx-auto px-6 md:px-8">
<div className={`${card.bg} ${cardRadius} overflow-hidden flex flex-col min-[820px]:flex-row`}> <div className={`${card.bg} ${cardRadius} flex flex-col min-[820px]:flex-row`}>
<div className="flex-1 flex flex-col justify-center gap-5 md:gap-6 px-8 md:px-14 lg:px-16 py-12 md:py-16"> <div className="flex-1 flex flex-col justify-center gap-5 md:gap-6 px-8 md:px-14 lg:px-16 py-12 md:py-16">
<h2 className={`font-joey-heavy text-fd-h1 leading-tight ${card.heading}`}> <h2 className={`font-joey-heavy text-fd-h1 leading-tight ${card.heading}`}>
{heading} {heading}
@ -56,7 +56,7 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
)} )}
{ctaText && ( {ctaText && (
<div> <div>
<FDButton href={ctaLink || '#'} variant={variant} onDark={card.isDark}> <FDButton href={ctaLink || '#'} variant={variant} onDark={card.isDark} className="w-full sm:w-auto justify-center">
{ctaText} {ctaText}
</FDButton> </FDButton>
</div> </div>
@ -64,13 +64,12 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
</div> </div>
{hasImage && ( {hasImage && (
<div className="relative flex-1 min-h-[250px] lg:min-h-0"> <div className="flex items-center justify-center w-full min-[820px]:w-[45%] lg:w-[480px] flex-shrink-0 p-6 md:p-10 lg:p-12">
<FDImage <FDImage
media={media} media={media}
size="large" size="large"
fill className="w-full h-auto max-h-[320px] object-contain drop-shadow-xl"
className="object-cover" sizes="(max-width: 820px) 80vw, 400px"
sizes="(max-width: 1024px) 100vw, 50vw"
fallbackAlt={heading || ''} fallbackAlt={heading || ''}
/> />
</div> </div>

View File

@ -60,7 +60,7 @@ type Props = {
} & React.HTMLAttributes<HTMLDivElement> } & React.HTMLAttributes<HTMLDivElement>
export default function RichText(props: Props) { export default function RichText(props: Props) {
const { className, enableProse = true, enableGutter = true, ...rest } = props const { className, enableProse = true, enableGutter = false, ...rest } = props
return ( return (
<ConvertRichText <ConvertRichText
converters={jsxConverters} converters={jsxConverters}

View File

@ -1590,6 +1590,9 @@ export interface User {
role: 'admin' | 'editor'; role: 'admin' | 'editor';
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
enableAPIKey?: boolean | null;
apiKey?: string | null;
apiKeyIndex?: string | null;
email: string; email: string;
resetPasswordToken?: string | null; resetPasswordToken?: string | null;
resetPasswordExpiration?: string | null; resetPasswordExpiration?: string | null;
@ -2728,6 +2731,9 @@ export interface UsersSelect<T extends boolean = true> {
role?: T; role?: T;
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;
enableAPIKey?: T;
apiKey?: T;
apiKeyIndex?: T;
email?: T; email?: T;
resetPasswordToken?: T; resetPasswordToken?: T;
resetPasswordExpiration?: T; resetPasswordExpiration?: T;

File diff suppressed because one or more lines are too long