Die Trias im Cover: Claim unter dem Monogramm, neue Headline
Unter dem großen Zeichen steht jetzt der Claim „Persönlichkeit · Wirkung · Erfolg“ (englisch „Personality · Impact · Success“), rechtsbündig auf dessen Kante, in der Kapitälchen-Zeile der Seite. Das Trennzeichen setzt der Hero, wie im Ledger – im Inhalt stehen nur die drei Wörter. Das Monogramm schrumpft dafür von 45vh auf 40vh, mobil von 14 auf 12svh: so kostet der Claim keine Höhe, das Cover bleibt bei min-h-svh. Der Nackenstrich endet nicht mehr an der Folio-Haarlinie, sondern an der Oberkante des Claims (20 px bei 1440×900, 1 px Luft). Der Ursprung der Haarlinie bleibt derselbe Punkt unter dem V – nachgemessen: --handoff-x 957+151 = 1108, transform-origin der Regel 72+1036 = 1108. Die Vertikale liest sich Nacken → Strich → Claim → Haarlinie. Die H1 heißt „Mit deiner Persönlichkeit entwickelst du deine Wirkung – und deinen Erfolg.“ Sie betont drei Wörter statt einem, weil sie den Claim wiederholt; den Gold-Verlauf trägt weiterhin genau eines. Dafür gibt es Headline.parts, und em-plain nimmt den übrigen das Gold wieder ab (Regel in globals.css, Ausnahme in AGENTS.md notiert). Die Größe ist gemessen, nicht geschätzt. Playfair bei 100 px: „Mit deiner Persönlichkeit“ = 1033 px, „entwickelst du deine Wirkung –“ = 1315 px. max-w-[10.9em] liegt zwischen beiden, damit bricht die Headline auf jeder Schriftgröße in dieselben vier Zeilen – der Umbruch hängt nicht mehr an der Fensterbreite. Der Clamp bleibt zusätzlich von der Fensterhöhe gedeckelt (22vh − 120px), für 800- und 768-px-Laptops. HeadlinePart.tail klammert Wort und Satzzeichen in ein white-space: nowrap. Nötig, weil SplitText die Zeilen selbst neu aufbaut: es normalisiert U+00A0 zu einem gewöhnlichen Leerzeichen und darf an jeder Elementgrenze umbrechen. Ohne die Klammer fing der Gedankenstrich im Englischen eine Zeile an, mit einem Punkt statt des Strichs derselbe Fehler. Ein Margin verschiebt den Umbruch nur, nowrap nimmt ihn weg. 02 Trainings & Workshops nimmt HR auf: „Leadership & HR mit Persönlichkeit – für Führungskräfte und Teams.“ Die Stichworte tragen HR-Teambuilding & Konfliktlösung und Kommunikation & Teamgeist – es geht darum, dass ein Team sich besser kennenlernt und versteht. Bei 1280 px bleiben 76 px Luft zur Link-Spalte. Geprüft bei 390/1024/1180/1440/1600 px in beiden Sprachen: kein Gedankenstrich am Zeilenanfang, kein waagerechter Überlauf, Cover trifft die Fensterhöhe. Kein Build gelaufen – der Dev-Server einer anderen Sitzung hält .next; geprüft ist tsc --noEmit und eslint. Offen und nicht Teil dieses Commits: src/content/coaching.ts sichert seinen Gedankenstrich noch mit U+00A0 ab, was aus demselben Grund nicht wirkt. Dort fällt der Umbruch derzeit zufällig richtig. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
389b3b9d71
commit
ecf66c7340
5 files changed
+154
-23
No files matched your search
@@ -25,6 +25,10 @@ schreibt den Block neu, dieser Teil bleibt).
|
|||||||
- Betonungswort einer Headline: genau ein `<em>`. Kursiv, und auf `data-theme="dark"`
|
- Betonungswort einer Headline: genau ein `<em>`. Kursiv, und auf `data-theme="dark"`
|
||||||
zusätzlich golden – das macht eine Regel in `globals.css`, nicht die Komponente.
|
zusätzlich golden – das macht eine Regel in `globals.css`, nicht die Komponente.
|
||||||
Auf hellem Grund bleibt es rein typografisch (Gold-Verlauf auf Elfenbein = 2,4:1).
|
Auf hellem Grund bleibt es rein typografisch (Gold-Verlauf auf Elfenbein = 2,4:1).
|
||||||
|
Einzige Ausnahme: eine Headline, die eine Aufzählung IST – die Trias der Startseite
|
||||||
|
(„Persönlichkeit … Wirkung … Erfolg“), weil sie den Claim unter dem Monogramm
|
||||||
|
wiederholt. Dann trägt jedes Wort ein `<em>`, den Gold-Verlauf aber weiterhin nur
|
||||||
|
eines; die übrigen bekommen `em-plain` (`Headline.parts[].gold` im Inhalt steuert das).
|
||||||
- Goldene Schrift nur auf `[data-theme="dark"]`; auf Ivory gilt `--gold-deep`.
|
- Goldene Schrift nur auf `[data-theme="dark"]`; auf Ivory gilt `--gold-deep`.
|
||||||
- Sichtbare Copy lebt ausschließlich in `src/content/*.ts`, nie im JSX.
|
- Sichtbare Copy lebt ausschließlich in `src/content/*.ts`, nie im JSX.
|
||||||
|
|
||||||
|
|||||||
@@ -285,6 +285,17 @@ svg {
|
|||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ausnahme für eine Headline, die eine Aufzählung IST – die Trias der Startseite
|
||||||
|
(„Persönlichkeit … Wirkung … Erfolg“) betont drei Wörter, weil sie den Claim unter
|
||||||
|
dem Monogramm wiederholt. Gold bleibt trotzdem rationiert: den Verlauf trägt genau
|
||||||
|
das letzte Wort, die übrigen bleiben rein kursiv. Gesetzt über `parts[].gold` im
|
||||||
|
Inhalt, nicht in der Komponente. */
|
||||||
|
[data-theme="dark"] .font-display em.em-plain {
|
||||||
|
color: inherit;
|
||||||
|
background: none;
|
||||||
|
-webkit-text-fill-color: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
/* Hairlines */
|
/* Hairlines */
|
||||||
.rule-gold { height: 1px; background: var(--gold-hairline); }
|
.rule-gold { height: 1px; background: var(--gold-hairline); }
|
||||||
[data-theme="light"] .rule-gold { background: var(--gold-hairline-light); }
|
[data-theme="light"] .rule-gold { background: var(--gold-hairline-light); }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useLayoutEffect, useRef, useState, type ReactNode } from "react";
|
import { Fragment, useLayoutEffect, useRef, useState, type ReactNode } from "react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { flags } from "@/lib/site";
|
import { flags } from "@/lib/site";
|
||||||
import { gsap, MM } from "@/lib/gsap";
|
import { gsap, MM } from "@/lib/gsap";
|
||||||
@@ -15,6 +15,7 @@ import { Magnet } from "@/components/motion/Magnet";
|
|||||||
import { DrawMark } from "@/components/brand/DrawMark";
|
import { DrawMark } from "@/components/brand/DrawMark";
|
||||||
import { Button } from "@/components/ui/Button";
|
import { Button } from "@/components/ui/Button";
|
||||||
import { PlaceholderText } from "@/components/ui/Facts";
|
import { PlaceholderText } from "@/components/ui/Facts";
|
||||||
|
import { EYEBROW_TEXT } from "@/components/ui/Eyebrow";
|
||||||
|
|
||||||
export interface HeroProps {
|
export interface HeroProps {
|
||||||
/** `<BrandMark idPrefix="hero" handoff/>` – Server Component, rendered by page.tsx. */
|
/** `<BrandMark idPrefix="hero" handoff/>` – Server Component, rendered by page.tsx. */
|
||||||
@@ -26,8 +27,10 @@ export interface HeroProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load choreography (spec §6.1), seconds from mount. Masthead hairlines 0 / 0.15 are
|
/* Load choreography (spec §6.1), seconds from mount. Masthead hairlines 0 / 0.15 are
|
||||||
Masthead's own; the folio hairline waits for the neck stroke (draw 0.7 + handoff 1.2–1.4). */
|
Masthead's own; the folio hairline waits for the neck stroke (draw 0.7 + handoff 1.2–1.4).
|
||||||
const T = { lines: 0.3, door: 0.5, draw: 0.7, cta: 1.2, folio: 2.0 } as const;
|
Der Claim liegt dazwischen: erst zeichnet der Strich zu Ende, dann steht das Wort da,
|
||||||
|
dann läuft die Haarlinie aus. */
|
||||||
|
const T = { lines: 0.3, door: 0.5, draw: 0.7, cta: 1.2, claim: 1.5, folio: 2.0 } as const;
|
||||||
|
|
||||||
/** Fallback length of the handoff hairline until it is measured (px). */
|
/** Fallback length of the handoff hairline until it is measured (px). */
|
||||||
const HANDOFF = 40;
|
const HANDOFF = 40;
|
||||||
@@ -36,6 +39,8 @@ const MONO_11 = "font-mono text-[11px] tracking-[0.06em]";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handoff x for `<Rule origin={x}/>`, measured from the folio's left edge.
|
* Handoff x for `<Rule origin={x}/>`, measured from the folio's left edge.
|
||||||
|
* Unverändert vom Claim: der Ursprung der Folio-Haarlinie bleibt der Punkt
|
||||||
|
* direkt unter dem V, auch wenn der Strich jetzt am Claim endet.
|
||||||
* DrawMark writes `--handoff-x` on its wrapper (fallback WolfMark); a client
|
* DrawMark writes `--handoff-x` on its wrapper (fallback WolfMark); a client
|
||||||
* SVG with `path#handoff` is measured at the path's end point.
|
* SVG with `path#handoff` is measured at the path's end point.
|
||||||
*/
|
*/
|
||||||
@@ -105,14 +110,18 @@ function markBottomY(markWrap: HTMLElement, pts: { x: number; y: number }[]): nu
|
|||||||
* Variant A (photo): portrait cols 8–12 bleeding to the page edge with scrims,
|
* Variant A (photo): portrait cols 8–12 bleeding to the page edge with scrims,
|
||||||
* monogram 28vh in cols 6–8 overlapping its left edge, neck handoff into the
|
* monogram 28vh in cols 6–8 overlapping its left edge, neck handoff into the
|
||||||
* folio hairline, which draws outward from that x. Variant B (no photo):
|
* folio hairline, which draws outward from that x. Variant B (no photo):
|
||||||
* monogram 56vh cols 7–12, right-aligned, same handoff. Mobile: masthead,
|
* monogram 40vh cols 7–12, right-aligned, same handoff. Unter dem Monogramm
|
||||||
* monogram 14svh, H1, CTAs, portrait 3:4 (≤ 48svh) – no folio row (it costs
|
* steht der Claim („Persönlichkeit · Wirkung · Erfolg“) – dafür ist das Zeichen
|
||||||
* 69 px the phone cover does not have; Positionierung carries „01 / 06“).
|
* von 45vh auf 40vh geschrumpft, damit das Cover nicht wächst; der Nackenstrich
|
||||||
|
* endet an seiner Oberkante. Mobile: masthead, monogram 12svh, Claim, H1, CTAs,
|
||||||
|
* portrait 3:4 (≤ 48svh) – no folio row (it costs 69 px the phone cover does not
|
||||||
|
* have; Positionierung carries „01 / 06“).
|
||||||
*/
|
*/
|
||||||
export function Hero({ mark, photo, content: hero = heroDe }: HeroProps) {
|
export function Hero({ mark, photo, content: hero = heroDe }: HeroProps) {
|
||||||
const root = useRef<HTMLDivElement>(null);
|
const root = useRef<HTMLDivElement>(null);
|
||||||
const h1 = useRef<HTMLDivElement>(null);
|
const h1 = useRef<HTMLDivElement>(null);
|
||||||
const markWrap = useRef<HTMLDivElement>(null);
|
const markWrap = useRef<HTMLDivElement>(null);
|
||||||
|
const claim = useRef<HTMLDivElement>(null);
|
||||||
const folio = useRef<HTMLDivElement>(null);
|
const folio = useRef<HTMLDivElement>(null);
|
||||||
const [origin, setOrigin] = useState<number | null>(null);
|
const [origin, setOrigin] = useState<number | null>(null);
|
||||||
const [handoffLength, setHandoffLength] = useState(HANDOFF);
|
const [handoffLength, setHandoffLength] = useState(HANDOFF);
|
||||||
@@ -133,7 +142,13 @@ export function Hero({ mark, photo, content: hero = heroDe }: HeroProps) {
|
|||||||
if (!pts) pts = sampleMarkPoints(m);
|
if (!pts) pts = sampleMarkPoints(m);
|
||||||
const bottom = markBottomY(m, pts);
|
const bottom = markBottomY(m, pts);
|
||||||
if (bottom !== null) {
|
if (bottom !== null) {
|
||||||
const gap = f.getBoundingClientRect().top - bottom;
|
/* Der Strich endet an der Oberkante des Claims, wenn einer da steht –
|
||||||
|
sonst wie bisher an der Folio-Haarlinie. Die Vertikale liest sich damit
|
||||||
|
Nacken → Strich → Claim → Haarlinie, und der Ursprung der Haarlinie
|
||||||
|
bleibt derselbe x. Der Claim animiert `y`, sein Wrapper nicht: dessen
|
||||||
|
Kasten steht schon zur Messzeit an der richtigen Stelle. */
|
||||||
|
const target = claim.current ?? f;
|
||||||
|
const gap = target.getBoundingClientRect().top - bottom;
|
||||||
setHandoffLength(Math.round(Math.min(72, Math.max(16, gap))));
|
setHandoffLength(Math.round(Math.min(72, Math.max(16, gap))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -226,20 +241,22 @@ export function Hero({ mark, photo, content: hero = heroDe }: HeroProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Monogram: bottom-aligned to the folio hairline; the neck hands off into it. */}
|
{/* Monogramm + Claim: als Block unten an der Folio-Haarlinie ausgerichtet.
|
||||||
|
Der Nackenstrich endet am Claim, der Ursprung der Haarlinie bleibt der
|
||||||
|
Punkt direkt unter dem V. `items-end`/`items-start` statt `justify-self`,
|
||||||
|
weil der Kasten jetzt zwei Kinder trägt und die Spalte füllen muss. */}
|
||||||
<div
|
<div
|
||||||
ref={markWrap}
|
ref={markWrap}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative z-[1] col-span-12 row-start-2 mt-6 h-[14svh] text-ivory lg:row-start-2 lg:row-end-5 lg:mt-0 lg:mb-4 lg:self-end",
|
"relative z-[1] col-span-12 row-start-2 mt-6 flex flex-col text-ivory lg:row-start-2 lg:row-end-5 lg:mt-0 lg:mb-4 lg:self-end",
|
||||||
"max-lg:[&_span[aria-hidden=true]]:hidden",
|
"max-lg:[&_span[aria-hidden=true]]:hidden",
|
||||||
/* WolfMark's 7-unit stroke is ~18 px at hero size – far from the
|
/* WolfMark's 7-unit stroke is ~18 px at hero size – far from the
|
||||||
spec's hairline mark. Overridden here, not in WolfMark.tsx. */
|
spec's hairline mark. Overridden here, not in WolfMark.tsx. */
|
||||||
"[&_.wolfmark-v]:[stroke-width:3] [&_.wolfmark-wolf]:[stroke-width:2.6]",
|
"[&_.wolfmark-v]:[stroke-width:3] [&_.wolfmark-wolf]:[stroke-width:2.6]",
|
||||||
hasPhoto
|
hasPhoto ? "lg:col-span-3 lg:col-start-6 lg:items-start" : "lg:col-span-6 lg:col-start-7 lg:items-end",
|
||||||
? "lg:col-span-3 lg:col-start-6 lg:h-[28vh] lg:justify-self-start"
|
|
||||||
: "lg:col-span-6 lg:col-start-7 lg:h-[min(45vh,24vw)] lg:justify-self-end",
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
<div className={cn("h-[12svh]", hasPhoto ? "lg:h-[24vh]" : "lg:h-[min(40vh,22vw)]")}>
|
||||||
<DrawMark
|
<DrawMark
|
||||||
play="load"
|
play="load"
|
||||||
sheen
|
sheen
|
||||||
@@ -252,25 +269,68 @@ export function Hero({ mark, photo, content: hero = heroDe }: HeroProps) {
|
|||||||
</DrawMark>
|
</DrawMark>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Der Wrapper trägt das Ref und wird NICHT animiert – `<Reveal/>` verschiebt
|
||||||
|
nur sein eigenes Element, sodass die Messung oben den ruhenden Kasten trifft.
|
||||||
|
Trennzeichen wie im Ledger von der Komponente gesetzt, nicht aus dem Inhalt. */}
|
||||||
|
<div ref={claim} className="mt-3 lg:mt-4">
|
||||||
|
<Reveal play="load" delay={T.claim} as="p" className={cn(EYEBROW_TEXT, "leading-[1.5] text-ivory/75")}>
|
||||||
|
{hero.claim.map((word, i) => (
|
||||||
|
<Fragment key={word}>
|
||||||
|
{i > 0 && <span className="mx-[0.7em] text-gold">·</span>}
|
||||||
|
{word}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</Reveal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* H1 */}
|
{/* H1 */}
|
||||||
<div
|
<div
|
||||||
ref={h1}
|
ref={h1}
|
||||||
className="relative z-[2] col-span-12 row-start-3 mt-6 lg:col-span-8 lg:col-start-1 lg:row-start-3 lg:mt-0 lg:self-end"
|
className="relative z-[2] col-span-12 row-start-3 mt-6 lg:col-span-8 lg:col-start-1 lg:row-start-3 lg:mt-0 lg:self-end"
|
||||||
>
|
>
|
||||||
{/* The H1 is capped by viewport HEIGHT as well as width: `26vh - 108px`
|
{/* Zwei Maße, beide gemessen statt geschätzt (Playfair bei 100 px:
|
||||||
is neutral at 1440×900 (the cover's reference frame) and pulls the
|
„Mit deiner Persönlichkeit“ = 1033 px, „entwickelst du deine Wirkung –“
|
||||||
three Bodoni lines back on 800/768 px laptops, where the vw term
|
= 1315 px, ganze Zeile = 3314 px):
|
||||||
alone grows faster than the fold shrinks. */}
|
|
||||||
|
`max-w-[10.9em]` liegt zwischen diesen beiden Werten. Damit bricht die
|
||||||
|
Headline auf JEDER Schriftgröße in dieselben vier Zeilen – der Umbruch
|
||||||
|
hängt nicht mehr an der Fenstergröße. Ab lg begrenzt die Spalte (854 px
|
||||||
|
bei 1440) auf 10.95 em; auch das liegt noch über 1033.
|
||||||
|
|
||||||
|
Der Clamp bleibt zusätzlich von der Fenster-HÖHE gedeckelt: `22vh - 120px`
|
||||||
|
ist bei 1440×900 neutral und zieht die vier Zeilen auf 800/768-px-Laptops
|
||||||
|
zurück, wo der vw-Term schneller wächst als der Bildschirm schrumpft. */}
|
||||||
<Lines
|
<Lines
|
||||||
as="h1"
|
as="h1"
|
||||||
play="load"
|
play="load"
|
||||||
delay={T.lines}
|
delay={T.lines}
|
||||||
stagger={0.09}
|
stagger={0.09}
|
||||||
className="max-w-[12ch] font-display text-[clamp(3rem,min(1.4rem_+_7.4vw,26vh_-_108px),8rem)] font-normal leading-[0.94] tracking-[-0.015em] text-ivory [text-wrap:balance]"
|
className="max-w-[10.9em] font-display text-[clamp(2.5rem,min(0.5rem_+_4.9vw,22vh_-_120px),5.25rem)] font-normal leading-[0.94] tracking-[-0.015em] text-ivory [text-wrap:balance]"
|
||||||
>
|
>
|
||||||
|
{hero.h1.parts ? (
|
||||||
|
/* Mehr als eine Betonung: kursiv trägt jedes Teil, den Gold-Verlauf
|
||||||
|
genau eines – `em-plain` nimmt ihn den übrigen wieder ab. */
|
||||||
|
hero.h1.parts.map((part, i) => {
|
||||||
|
if (!part.em) return <Fragment key={i}>{part.text}</Fragment>;
|
||||||
|
const word = <em className={cn("italic", !part.gold && "em-plain")}>{part.text}</em>;
|
||||||
|
/* `tail` klammert Wort und Satzzeichen zusammen – siehe `HeadlinePart.tail`. */
|
||||||
|
return part.tail ? (
|
||||||
|
<span key={i} className="whitespace-nowrap">
|
||||||
|
{word}
|
||||||
|
{part.tail}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<Fragment key={i}>{word}</Fragment>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
{hero.h1.before}
|
{hero.h1.before}
|
||||||
<em className="italic">{hero.h1.em}</em>
|
<em className="italic">{hero.h1.em}</em>
|
||||||
{hero.h1.after}
|
{hero.h1.after}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Lines>
|
</Lines>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+17
-3
@@ -21,7 +21,21 @@ export const homeEn: HomeContent = {
|
|||||||
center: "Sales Mentoring & Potential Development",
|
center: "Sales Mentoring & Potential Development",
|
||||||
lang: "German & English",
|
lang: "German & English",
|
||||||
},
|
},
|
||||||
h1: { before: "Who you are decides how you ", em: "land", after: "." },
|
h1: {
|
||||||
|
before: "With your personality you shape your impact – and your ",
|
||||||
|
em: "success",
|
||||||
|
after: ".",
|
||||||
|
parts: [
|
||||||
|
{ text: "With your " },
|
||||||
|
{ text: "personality", em: true },
|
||||||
|
{ text: " you shape your " },
|
||||||
|
{ text: "impact", em: true, tail: " –" },
|
||||||
|
{ text: " and your " },
|
||||||
|
{ text: "success", em: true, gold: true },
|
||||||
|
{ text: "." },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
claim: ["Personality", "Impact", "Success"],
|
||||||
subline:
|
subline:
|
||||||
"Welcome. Whether as a speaker at your company event, in one-to-one coaching or as a trainer for your team – I am glad to hear what you need.",
|
"Welcome. Whether as a speaker at your company event, in one-to-one coaching or as a trainer for your team – I am glad to hear what you need.",
|
||||||
cta: {
|
cta: {
|
||||||
@@ -67,8 +81,8 @@ export const homeEn: HomeContent = {
|
|||||||
{
|
{
|
||||||
numeral: "02",
|
numeral: "02",
|
||||||
title: "Training & Workshops",
|
title: "Training & Workshops",
|
||||||
oneLiner: "Sales with personality – for teams and their leaders.",
|
oneLiner: "Leadership & HR with personality – for leaders and their teams.",
|
||||||
keywords: ["B2B sales training", "New and existing customers", "Leadership & team dynamics"],
|
keywords: ["B2B sales training", "HR team building & conflict resolution", "Communication & team spirit"],
|
||||||
link: { label: "See training", href: r.trainings },
|
link: { label: "See training", href: r.trainings },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+45
-3
@@ -8,10 +8,37 @@ import { assertNoPlaceholders, collectStrings, ph } from "@/lib/legal";
|
|||||||
|
|
||||||
/* ---------- gemeinsame Typen (werden von allen content/*.ts genutzt) ---------- */
|
/* ---------- gemeinsame Typen (werden von allen content/*.ts genutzt) ---------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ein Stück einer Headline. `em` setzt kursiv, `gold` zusätzlich den Verlauf –
|
||||||
|
* der greift ohnehin nur auf `data-theme="dark"` (Regel in globals.css).
|
||||||
|
*/
|
||||||
|
export interface HeadlinePart {
|
||||||
|
text: string;
|
||||||
|
em?: boolean;
|
||||||
|
gold?: boolean;
|
||||||
|
/**
|
||||||
|
* Satzzeichen, das untrennbar an `text` hängt – Gedankenstrich, Punkt. Wird mit
|
||||||
|
* dem Wort in ein `white-space: nowrap` gesetzt, inklusive führendem Leerzeichen.
|
||||||
|
*
|
||||||
|
* Nötig, weil SplitText die Zeilen selbst neu aufbaut und dabei an jeder
|
||||||
|
* Elementgrenze umbrechen darf: ohne die Klammer landete „–“ bzw. „.“ hinter
|
||||||
|
* einem `<em>` am Zeilenanfang. Ein geschütztes Leerzeichen hilft nicht,
|
||||||
|
* SplitText normalisiert es zu einem gewöhnlichen; ein Margin auch nicht, der
|
||||||
|
* verschiebt den Umbruch nur. `nowrap` nimmt dem Browser die Stelle wirklich weg.
|
||||||
|
*/
|
||||||
|
tail?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Headline {
|
export interface Headline {
|
||||||
before: string;
|
before: string;
|
||||||
em: string;
|
em: string;
|
||||||
after: string;
|
after: string;
|
||||||
|
/**
|
||||||
|
* Headline mit mehr als einer Betonung – nur für Aufzählungen wie die Trias
|
||||||
|
* der Startseite. Wird bevorzugt gerendert; `before`/`em`/`after` bleiben als
|
||||||
|
* einfache Fassung stehen (Schrift-Test, Fallback). Gold trägt genau ein Teil.
|
||||||
|
*/
|
||||||
|
parts?: readonly HeadlinePart[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Cta {
|
export interface Cta {
|
||||||
@@ -100,7 +127,22 @@ export const hero = {
|
|||||||
center: "Sales Mentoring & Potential Development",
|
center: "Sales Mentoring & Potential Development",
|
||||||
lang: "Deutsch & Englisch",
|
lang: "Deutsch & Englisch",
|
||||||
},
|
},
|
||||||
h1: { before: "Wer du bist, entscheidet, wie du ", em: "wirkst", after: "." } satisfies Headline,
|
h1: {
|
||||||
|
before: "Mit deiner Persönlichkeit entwickelst du deine Wirkung – und deinen ",
|
||||||
|
em: "Erfolg",
|
||||||
|
after: ".",
|
||||||
|
parts: [
|
||||||
|
{ text: "Mit deiner " },
|
||||||
|
{ text: "Persönlichkeit", em: true },
|
||||||
|
{ text: " entwickelst du deine " },
|
||||||
|
{ text: "Wirkung", em: true, tail: " –" },
|
||||||
|
{ text: " und deinen " },
|
||||||
|
{ text: "Erfolg", em: true, gold: true },
|
||||||
|
{ text: "." },
|
||||||
|
],
|
||||||
|
} satisfies Headline,
|
||||||
|
/** Claim unter dem Monogramm. Das Trennzeichen setzt der Hero, wie im Ledger. */
|
||||||
|
claim: ["Persönlichkeit", "Wirkung", "Erfolg"],
|
||||||
subline:
|
subline:
|
||||||
"Herzlich willkommen. Ob als Speakerin für dein Firmenevent, im 1:1 Coaching oder als Trainerin für dein Team – gerne bin ich für dein Anliegen da.",
|
"Herzlich willkommen. Ob als Speakerin für dein Firmenevent, im 1:1 Coaching oder als Trainerin für dein Team – gerne bin ich für dein Anliegen da.",
|
||||||
cta: {
|
cta: {
|
||||||
@@ -148,8 +190,8 @@ export const services = {
|
|||||||
{
|
{
|
||||||
numeral: "02",
|
numeral: "02",
|
||||||
title: "Trainings & Workshops",
|
title: "Trainings & Workshops",
|
||||||
oneLiner: "Vertrieb mit Persönlichkeit – für Teams und Führungskräfte.",
|
oneLiner: "Leadership & HR mit Persönlichkeit – für Führungskräfte und Teams.",
|
||||||
keywords: ["B2B-Vertriebstraining", "Neukunden & Bestandskunden", "Leadership & Teamdynamik"],
|
keywords: ["B2B-Vertriebstraining", "HR-Teambuilding & Konfliktlösung", "Kommunikation & Teamgeist"],
|
||||||
link: { label: "Zu den Trainings", href: routes.trainings },
|
link: { label: "Zu den Trainings", href: routes.trainings },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user