@@ -214,18 +207,15 @@ export default function BlogDetail() { style={{ marginBottom: 48 }} > {section.heading && ( -
{section.heading}
)} -{section.body}
@@ -249,7 +239,7 @@ export default function BlogDetail() {diff --git a/src/app/(frontend)/globals.css b/src/app/(frontend)/globals.css index 74651b0..2222009 100644 --- a/src/app/(frontend)/globals.css +++ b/src/app/(frontend)/globals.css @@ -24,6 +24,17 @@ --color-input: var(--input); --color-ring: var(--ring); + --font-size-eyebrow: var(--type-eyebrow); + --font-size-caption: var(--type-caption); + --font-size-small: var(--type-small); + --font-size-body: var(--type-step-0); + --font-size-lead: var(--type-step-1); + --font-size-card-title: var(--type-step-2); + --font-size-subtitle: var(--type-step-3); + --font-size-section-title: var(--type-step-4); + --font-size-page-title: var(--type-step-6); + --font-size-display: var(--type-step-7); + --radius-lg: 0.5rem; --radius-md: calc(0.5rem - 2px); --radius-sm: calc(0.5rem - 4px); @@ -43,11 +54,45 @@ --muted: #f1f5f9; --muted-foreground: #64748b; --accent: #EFBF04; - --accent-foreground: #ffffff; + --accent-foreground: #101828; --destructive: #ef4444; --border: #e2e8f0; --input: #e2e8f0; --ring: #03093A; + + /* Fluid type scale: 320px -> 1440px, 16px -> 18px body. */ + --type-eyebrow: clamp(0.6875rem, 0.6696rem + 0.0893vw, 0.75rem); + --type-caption: clamp(0.75rem, 0.7143rem + 0.1786vw, 0.875rem); + --type-small: clamp(0.875rem, 0.8393rem + 0.1786vw, 1rem); + --type-step-0: clamp(1rem, 0.9643rem + 0.1786vw, 1.125rem); + --type-step-1: clamp(1.125rem, 1.0446rem + 0.4018vw, 1.4063rem); + --type-step-2: clamp(1.2656rem, 1.125rem + 0.7031vw, 1.7578rem); + --type-step-3: clamp(1.4238rem, 1.2028rem + 1.1049vw, 2.1973rem); + --type-step-4: clamp(1.6018rem, 1.2747rem + 1.6354vw, 2.7466rem); + --type-step-5: clamp(1.802rem, 1.336rem + 2.3303vw, 3.4332rem); + --type-step-6: clamp(2.0273rem, 1.3804rem + 3.2346vw, 4.2915rem); + --type-step-7: clamp(2.2807rem, 1.3996rem + 4.4053vw, 5.3644rem); + + --leading-display: 0.98; + --leading-heading: 1.05; + --leading-body: 1.7; + --leading-small: 1.55; + + /* Semantic text roles. Gold stays bright on dark surfaces and decorative uses. */ + --text-heading: #101828; + --text-body: #344054; + --text-secondary: #475467; + --text-muted: #596579; + --text-link: #111D55; + --text-link-hover: #051A87; + --text-eyebrow-light: #285F8C; + --text-brand-on-light: #765600; + --text-brand-on-dark: #EFBF04; + --text-on-accent: #101828; + --text-inverse: #ffffff; + --text-inverse-secondary: rgba(255, 255, 255, 0.72); + --text-inverse-muted: rgba(255, 255, 255, 0.65); + --text-danger: #B91C1C; } .dark { @@ -64,7 +109,7 @@ --muted: #1e293b; --muted-foreground: #94a3b8; --accent: #EFBF04; - --accent-foreground: #ffffff; + --accent-foreground: #101828; --destructive: #7f1d1d; --border: rgba(255, 255, 255, 0.1); --input: rgba(255, 255, 255, 0.15); @@ -77,6 +122,9 @@ } body { @apply bg-background text-foreground font-body; + color: var(--text-body); + font-size: var(--type-step-0); + line-height: var(--leading-body); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; margin: 0; @@ -88,6 +136,7 @@ } h1, h2, h3, h4, h5, h6 { @apply font-display font-bold; + color: var(--text-heading); } blockquote, q, @@ -106,6 +155,99 @@ } } +@layer components { + .type-display, + .type-page-title, + .type-section-title, + .type-subtitle, + .type-card-title, + .type-eyebrow { + font-family: var(--font-display); + font-weight: 700; + hyphens: auto; + overflow-wrap: anywhere; + } + + .type-display { + font-size: var(--type-step-7); + line-height: var(--leading-display); + letter-spacing: -0.03em; + } + + .type-page-title { + font-size: var(--type-step-6); + line-height: var(--leading-display); + letter-spacing: -0.03em; + } + + .type-section-title { + font-size: var(--type-step-4); + line-height: var(--leading-heading); + letter-spacing: -0.025em; + } + + .type-subtitle { + font-size: var(--type-step-3); + line-height: var(--leading-heading); + letter-spacing: -0.02em; + } + + .type-card-title { + font-size: var(--type-step-2); + line-height: 1.1; + letter-spacing: -0.02em; + } + + .type-lead, + .type-body, + .type-small, + .type-caption { + font-family: var(--font-body); + font-weight: 400; + overflow-wrap: anywhere; + } + + .type-lead { + font-size: var(--type-step-1); + line-height: var(--leading-body); + } + + .type-body { + font-size: var(--type-step-0); + line-height: var(--leading-body); + } + + .type-small { + font-size: var(--type-small); + line-height: var(--leading-small); + } + + .type-caption { + font-size: var(--type-caption); + line-height: var(--leading-small); + } + + .type-eyebrow { + font-size: var(--type-eyebrow); + line-height: 1.3; + letter-spacing: 0.18em; + text-transform: uppercase; + } + + .text-role-heading { color: var(--text-heading); } + .text-role-body { color: var(--text-body); } + .text-role-secondary { color: var(--text-secondary); } + .text-role-muted { color: var(--text-muted); } + .text-role-link { color: var(--text-link); } + .text-role-eyebrow { color: var(--text-eyebrow-light); } + .text-role-brand-light { color: var(--text-brand-on-light); } + .text-role-brand-dark { color: var(--text-brand-on-dark); } + .text-role-inverse { color: var(--text-inverse); } + .text-role-inverse-secondary { color: var(--text-inverse-secondary); } + .text-role-inverse-muted { color: var(--text-inverse-muted); } + .text-role-danger { color: var(--text-danger); } +} + @keyframes fade-in { from { opacity: 0; diff --git a/src/spa/components/AwardsGridSection.tsx b/src/spa/components/AwardsGridSection.tsx index 7b5f159..386dd22 100644 --- a/src/spa/components/AwardsGridSection.tsx +++ b/src/spa/components/AwardsGridSection.tsx @@ -110,14 +110,14 @@ function FeaturedAwardCard({ card }: { card: ResolvedAwardCard }) {
+
{fallbackText(card.description, '')}
@@ -228,14 +228,14 @@ function SupportingAwardCards({+
{fallbackText(card.description, '')}
@@ -306,14 +306,14 @@ export default function AwardsGridSection({ content, featuredGoldeneBavaria = fa+
{fallbackText(section.description, participationContent.awardsGrid.description)}
+
{fallbackText(section.supportingDescription, participationContent.awardsGrid.supportingDescription)}
{winner?.category || staticWinner?.category}
+{winner?.category || staticWinner?.category}
{t.quote}
+{t.quote}
+
{t.quote}
@@ -148,7 +148,7 @@ export default function TestimonialsSection({ data }: { data?: TestimonialsCms }+
{fallbackText(section.description, participationContent.process.description)}
+
{fallbackText(item.desc, '')}
{/* Step progress indicator */} @@ -101,11 +101,11 @@ export default function WegZurAuszeichnungSection({ content }: { content?: Proce+
{fallbackText(section.description, participationContent.process.description)}
+
{fallbackText(item.desc, '')}
{/* Step progress indicator */} diff --git a/src/spa/components/forms/ApplicationFormSection.tsx b/src/spa/components/forms/ApplicationFormSection.tsx index 63cf790..4879aeb 100644 --- a/src/spa/components/forms/ApplicationFormSection.tsx +++ b/src/spa/components/forms/ApplicationFormSection.tsx @@ -50,11 +50,11 @@ export function ApplicationFormSection({ source }: { source: NewsletterSource })+
{showApplicationForm ? fallbackText(section.body, homeContent.application.body) : newsletterCopy.body}
@@ -99,7 +99,7 @@ export function ApplicationFormSection({ source }: { source: NewsletterSource })+
{data.type === 'selbst' ? <>{fallbackText(formContent.success.selfPrefix, participationContent.form.success.selfPrefix)}{data.firmenname}{fallbackText(formContent.success.selfMiddle, participationContent.form.success.selfMiddle)}{data.email}{fallbackText(formContent.success.selfSuffix, participationContent.form.success.selfSuffix)}> : <>{fallbackText(formContent.success.nominationPrefix, participationContent.form.success.nominationPrefix)}{data.nomName}{fallbackText(formContent.success.nominationMiddle, participationContent.form.success.nominationMiddle)}{data.nomFirma}{fallbackText(formContent.success.nominationSuffix, participationContent.form.success.nominationSuffix)}> @@ -400,8 +400,8 @@ export default function BewerbungsForm({ theme = 'dark', content }: { theme?: 'd {/* ── Step 0: Typ-Wahl ── */} {step === 0 && (
{fallbackText(formContent.typeStep.eyebrow, participationContent.form.typeStep.eyebrow)}
-{fallbackText(formContent.typeStep.eyebrow, participationContent.form.typeStep.eyebrow)}
+{fallbackText(formContent.eligibility.eyebrow, participationContent.form.eligibility.eyebrow)}
-{fallbackText(formContent.eligibility.eyebrow, participationContent.form.eligibility.eyebrow)}
++
{fallbackText(formContent.eligibility.ineligibleBody, participationContent.form.eligibility.ineligibleBody)}
-+
{fallbackText(formContent.eligibility.ineligibleContactPrefix, participationContent.form.eligibility.ineligibleContactPrefix)} {fallbackText(formContent.eligibility.ineligibleContactEmail, participationContent.form.eligibility.ineligibleContactEmail)}
{fallbackText(formContent.selfContact.eyebrow, participationContent.form.selfContact.eyebrow)}
-{fallbackText(formContent.selfContact.eyebrow, participationContent.form.selfContact.eyebrow)}
++
{fallbackText(formContent.selfContact.footnote, participationContent.form.selfContact.footnote)}
{fallbackText(formContent.selfSummary.eyebrow, participationContent.form.selfSummary.eyebrow)}
-{fallbackText(formContent.selfSummary.eyebrow, participationContent.form.selfSummary.eyebrow)}
+{fallbackText(formContent.nominationCompany.eyebrow, participationContent.form.nominationCompany.eyebrow)}
-{fallbackText(formContent.nominationCompany.eyebrow, participationContent.form.nominationCompany.eyebrow)}
+{fallbackText(formContent.nominationContact.eyebrow, participationContent.form.nominationContact.eyebrow)}
-{fallbackText(formContent.nominationContact.eyebrow, participationContent.form.nominationContact.eyebrow)}
++
{fallbackText(formContent.nominationContact.footnote, participationContent.form.nominationContact.footnote)}
{fallbackText(formContent.nominationSummary.eyebrow, participationContent.form.nominationSummary.eyebrow)}
-{fallbackText(formContent.nominationSummary.eyebrow, participationContent.form.nominationSummary.eyebrow)}
++
{fallbackText(copy.success.prefix, contactFormContent.success.prefix)} {data.name}. {fallbackText(copy.success.suffixBeforeEmail, contactFormContent.success.suffixBeforeEmail)}{' '} {data.email}.
@@ -326,7 +326,7 @@ export default function KontaktForm({ theme = 'dark', content }: { theme?: 'dark {step === 0 && ({fallbackText(copy.prompts.subject, contactFormContent.prompts.subject)}
+{fallbackText(copy.prompts.subject, contactFormContent.prompts.subject)}
{copy.subjects.map(item => ({fallbackText(copy.prompts.contact, contactFormContent.prompts.contact)}
+{fallbackText(copy.prompts.contact, contactFormContent.prompts.contact)}
{([ { label: copy.fields.nameLabel, key: 'name' as const, type: 'text', placeholder: copy.fields.namePlaceholder, error: errors.name }, { label: copy.fields.emailLabel, key: 'email' as const, type: 'email', placeholder: copy.fields.emailPlaceholder, error: errors.email }, @@ -352,7 +352,7 @@ export default function KontaktForm({ theme = 'dark', content }: { theme?: 'dark {step === 2 && ({fallbackText(copy.prompts.message, contactFormContent.prompts.message)}
+{fallbackText(copy.prompts.message, contactFormContent.prompts.message)}
{submissionError}
} + {submissionError &&{submissionError}
}+
{copy.successBody}
+
{copy.formBody}
-+
{copy.privacy}
diff --git a/src/spa/components/forms/SponsoringForm.tsx b/src/spa/components/forms/SponsoringForm.tsx index 822b238..c6c2d95 100644 --- a/src/spa/components/forms/SponsoringForm.tsx +++ b/src/spa/components/forms/SponsoringForm.tsx @@ -212,10 +212,10 @@ export default function SponsoringForm({ theme = 'dark', content }: { theme?: 'd+
{fallbackText(copy.successMessagePrefix, netzwerkContent.sponsoringForm.successMessagePrefix)} {data.kontakt}. {fallbackText(copy.successMessageSuffix, netzwerkContent.sponsoringForm.successMessageSuffix)}
{numberedStepLabel(copy.step2Eyebrow, netzwerkContent.sponsoringForm.step2Eyebrow, 1)}
-{numberedStepLabel(copy.step2Eyebrow, netzwerkContent.sponsoringForm.step2Eyebrow, 1)}
+{numberedStepLabel(copy.step3Eyebrow, netzwerkContent.sponsoringForm.step3Eyebrow, 2)}
-{numberedStepLabel(copy.step3Eyebrow, netzwerkContent.sponsoringForm.step3Eyebrow, 2)}
+{submissionError}
} + {submissionError &&{submissionError}
} -+
{fallbackText(copy.footerText, netzwerkContent.sponsoringForm.footerText)}
@@ -778,13 +768,7 @@ const Layout: React.FC {column.label}
{footer.copyright}
diff --git a/src/spa/components/legal/LegalPage.tsx b/src/spa/components/legal/LegalPage.tsx
index 87bd14e..1a7c49e 100644
--- a/src/spa/components/legal/LegalPage.tsx
+++ b/src/spa/components/legal/LegalPage.tsx
@@ -66,19 +66,20 @@ export default function LegalPage({ content, cmsKey }: { content: LegalPageConte
{subtitle}
{success.message}
+
{fallbackText(hero.description, aboutContent.hero.description)}
+
{text}
+
{text}
+
{fallbackText(values.description, aboutContent.values.description)}
+
{fallbackText(cta.description, aboutContent.cta.description)}
@@ -214,18 +207,15 @@ export default function BlogDetail() {
style={{ marginBottom: 48 }}
>
{section.heading && (
-
{section.body}
@@ -864,13 +848,9 @@ const Layout: React.FC
+
-
{fallbackText(hero.heading, content.hero.heading)}
+
{title}
+
+
{lines.map((line, index) => (
{item.items.map((entry, index) => (
{title}
+ {num}.
+ {title}
{title}
{subtitle && (
-
{success.heading}
-
+
{fallbackText(hero.heading, aboutContent.hero.heading).split('\n').map((line, index) => (
-
}
@@ -126,7 +126,7 @@ const About: React.FC = () => {
+ {fallbackText(prize.eyebrow, aboutContent.prize.eyebrow)}
+
>
)}
{paragraphs(prize.body, aboutContent.prize.body).map((text, index, arr) => (
-
+
+
+
>
)}
{paragraphs(mittelstand.body, aboutContent.mittelstand.body).map((text, index, arr) => (
-
+
{fallbackText(history.heading, aboutContent.history.heading).split('\n').map((line, index) => (
}
@@ -295,15 +295,15 @@ const About: React.FC = () => {
+ {fallbackText(goals.eyebrow, aboutContent.goals.eyebrow)}
+
+ {fallbackText(values.eyebrow, aboutContent.values.eyebrow)}
+
+
- {fallbackText(item.title, '')}
+ {fallbackText(item.title, '')}
{fallbackText(notFound.title, blogDetailContent.notFound.title)}
+ {fallbackText(notFound.title, blogDetailContent.notFound.title)}
{section.heading}
)}
-