diff --git a/admin/lib/fonts.js b/admin/lib/fonts.js index ca8838b..3af8810 100644 --- a/admin/lib/fonts.js +++ b/admin/lib/fonts.js @@ -10,6 +10,7 @@ const FONT_OPTIONS = [ { name: 'Merriweather', fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Libre Baskerville', fallback: "Georgia, 'Times New Roman', serif" }, { name: 'DM Serif Display', fallback: "Georgia, 'Times New Roman', serif" }, + { name: 'Newsreader', fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Georgia (Systemschrift)', fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Inter', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Roboto', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, @@ -19,6 +20,7 @@ const FONT_OPTIONS = [ { name: 'Nunito', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Work Sans', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Source Sans 3', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, + { name: 'Schibsted Grotesk', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'System UI (Systemschrift)', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, ]; diff --git a/admin/public/app.js b/admin/public/app.js index da1a5fd..fdd44a3 100644 --- a/admin/public/app.js +++ b/admin/public/app.js @@ -64,7 +64,7 @@ .flatMap(([name, list]) => list.map( (face) => - `@font-face { font-family: '${name}'; font-weight: ${face.weight}; font-display: swap; ` + + `@font-face { font-family: '${name}'; font-style: ${face.style || 'normal'}; font-weight: ${face.weight}; font-display: swap; ` + `src: url('/admin${face.file}') format('woff2'); unicode-range: ${face.unicodeRange}; }`, ), ) diff --git a/content/theme.json b/content/theme.json index 74bb8c4..7896c0f 100644 --- a/content/theme.json +++ b/content/theme.json @@ -1,7 +1,7 @@ { "fonts": { - "heading": "Playfair Display", - "body": "Inter" + "heading": "Newsreader", + "body": "Schibsted Grotesk" }, "fontSizes": { "sm": "0.875rem", @@ -20,9 +20,9 @@ "a": 1 }, "bgAlt": { - "r": 244, + "r": 233, "g": 239, - "b": 228, + "b": 234, "a": 1 }, "surface": { @@ -32,57 +32,57 @@ "a": 1 }, "text": { - "r": 28, - "g": 24, - "b": 19, + "r": 26, + "g": 38, + "b": 34, "a": 1 }, "textMuted": { - "r": 107, - "g": 97, - "b": 84, + "r": 78, + "g": 93, + "b": 87, "a": 1 }, "border": { - "r": 220, - "g": 207, - "b": 182, + "r": 185, + "g": 198, + "b": 190, "a": 1 }, "primary": { - "r": 122, - "g": 93, - "b": 31, + "r": 44, + "g": 74, + "b": 66, "a": 1 }, "primaryDark": { - "r": 94, - "g": 71, - "b": 22, + "r": 31, + "g": 53, + "b": 48, "a": 1 }, "primaryContrast": { - "r": 255, - "g": 253, - "b": 248, + "r": 252, + "g": 250, + "b": 246, "a": 1 }, "accent": { - "r": 122, - "g": 93, - "b": 31, + "r": 142, + "g": 79, + "b": 63, "a": 1 }, "accentDark": { - "r": 94, - "g": 71, - "b": 22, + "r": 115, + "g": 62, + "b": 49, "a": 1 }, "success": { - "r": 79, + "r": 63, "g": 107, - "b": 66, + "b": 85, "a": 1 }, "danger": { @@ -101,7 +101,7 @@ "r": 138, "g": 59, "b": 34, - "a": 0.1 + "a": 1 }, "googleBlue": { "r": 26, diff --git a/public/fonts/newsreader/newsreader-latin-1.woff2 b/public/fonts/newsreader/newsreader-latin-1.woff2 new file mode 100644 index 0000000..11a48ec Binary files /dev/null and b/public/fonts/newsreader/newsreader-latin-1.woff2 differ diff --git a/public/fonts/newsreader/newsreader-latin-3.woff2 b/public/fonts/newsreader/newsreader-latin-3.woff2 new file mode 100644 index 0000000..816261a Binary files /dev/null and b/public/fonts/newsreader/newsreader-latin-3.woff2 differ diff --git a/public/fonts/newsreader/newsreader-latin-ext-0.woff2 b/public/fonts/newsreader/newsreader-latin-ext-0.woff2 new file mode 100644 index 0000000..7a7ae44 Binary files /dev/null and b/public/fonts/newsreader/newsreader-latin-ext-0.woff2 differ diff --git a/public/fonts/newsreader/newsreader-latin-ext-2.woff2 b/public/fonts/newsreader/newsreader-latin-ext-2.woff2 new file mode 100644 index 0000000..06116f4 Binary files /dev/null and b/public/fonts/newsreader/newsreader-latin-ext-2.woff2 differ diff --git a/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-1.woff2 b/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-1.woff2 new file mode 100644 index 0000000..ea0f36f Binary files /dev/null and b/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-1.woff2 differ diff --git a/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-ext-0.woff2 b/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-ext-0.woff2 new file mode 100644 index 0000000..041da55 Binary files /dev/null and b/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-ext-0.woff2 differ diff --git a/public/form/fleck-maske.svg b/public/form/fleck-maske.svg new file mode 100644 index 0000000..c317153 --- /dev/null +++ b/public/form/fleck-maske.svg @@ -0,0 +1 @@ + diff --git a/public/form/fleck.svg b/public/form/fleck.svg new file mode 100644 index 0000000..9c1a34f --- /dev/null +++ b/public/form/fleck.svg @@ -0,0 +1 @@ + diff --git a/public/form/pille.svg b/public/form/pille.svg new file mode 100644 index 0000000..ff9d512 --- /dev/null +++ b/public/form/pille.svg @@ -0,0 +1 @@ + diff --git a/scripts/fonts-holen.py b/scripts/fonts-holen.py index 2d2bd59..d24b29e 100644 --- a/scripts/fonts-holen.py +++ b/scripts/fonts-holen.py @@ -1,30 +1,41 @@ -import re, json, urllib.request, urllib.error, pathlib +# Aufruf: python scripts/fonts-holen.py -> alle Schriften neu holen +# python scripts/fonts-holen.py "Name" ... -> nur diese, Manifest wird ergänzt +import re, json, sys, urllib.request, urllib.error, pathlib UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0 Safari/537.36" -FAMS = ['Playfair Display','Lora','Merriweather','Libre Baskerville','DM Serif Display','Inter','Roboto','Open Sans','Poppins','Montserrat','Nunito','Work Sans','Source Sans 3'] +FAMS = ['Playfair Display','Lora','Merriweather','Libre Baskerville','DM Serif Display','Inter','Roboto','Open Sans','Poppins','Montserrat','Nunito','Work Sans','Source Sans 3','Newsreader','Schibsted Grotesk'] +# Diese Schriften auch kursiv holen (echte Kursive statt schräg gerechneter) +ITAL = {'Newsreader'} +manifest_path = pathlib.Path('src/lib/font-faces.json') +if sys.argv[1:]: + FAMS = sys.argv[1:] out_dir = pathlib.Path('public/fonts'); out_dir.mkdir(parents=True, exist_ok=True) -manifest = {} +manifest = json.load(open(manifest_path, encoding='utf8')) if sys.argv[1:] else {} def get(url): return urllib.request.urlopen(urllib.request.Request(url, headers={'User-Agent': UA})).read() for fam in FAMS: css = None for w in ['400;500;600;700', '400;700', '400']: + axis = 'wght' + if fam in ITAL: + axis = 'ital,wght'; w = ';'.join([f'0,{x}' for x in w.split(';')] + [f'1,{x}' for x in w.split(';')]) try: - css = get(f"https://fonts.googleapis.com/css2?family={fam.replace(' ','+')}:wght@{w}&display=swap").decode(); break + css = get(f"https://fonts.googleapis.com/css2?family={fam.replace(' ','+')}:{axis}@{w}&display=swap").decode(); break except urllib.error.HTTPError: pass slug = fam.lower().replace(' ', '-'); d = out_dir / slug; d.mkdir(exist_ok=True) faces = []; seen = {} for subset, body in re.findall(r'/\* ([\w-]+) \*/\s*@font-face \{(.*?)\}', css, re.S): if subset not in ('latin', 'latin-ext'): continue weight = re.search(r'font-weight: (\d+)', body).group(1) + style = re.search(r'font-style: (\w+)', body).group(1) url = re.search(r'url\((.*?)\)', body).group(1) rng = re.search(r'unicode-range: (.*?);', body).group(1) if url not in seen: fn = f"{slug}-{subset}-{len(seen)}.woff2"; (d / fn).write_bytes(get(url)); seen[url] = fn - faces.append({'weight': int(weight), 'subset': subset, 'file': f"/fonts/{slug}/{seen[url]}", 'unicodeRange': rng}) + faces.append({'weight': int(weight), 'style': style, 'subset': subset, 'file': f"/fonts/{slug}/{seen[url]}", 'unicodeRange': rng}) # gleiche Datei fuer mehrere Gewichte (variable Schrift) -> eine Regel mit Gewichtsbereich merged = {} for f in faces: - k = (f['file'], f['subset']); merged.setdefault(k, dict(f, weights=[]))['weights'].append(f['weight']) - manifest[fam] = [{'file': v['file'], 'weight': f"{min(v['weights'])} {max(v['weights'])}" if len(v['weights']) > 1 else str(v['weights'][0]), 'unicodeRange': v['unicodeRange']} for v in merged.values()] + k = (f['file'], f['subset'], f['style']); merged.setdefault(k, dict(f, weights=[]))['weights'].append(f['weight']) + manifest[fam] = [dict({'file': v['file'], 'weight': f"{min(v['weights'])} {max(v['weights'])}" if len(v['weights']) > 1 else str(v['weights'][0]), 'unicodeRange': v['unicodeRange']}, **({'style': 'italic'} if v['style'] == 'italic' else {})) for v in merged.values()] print(fam, len(manifest[fam]), 'Regeln', len(seen), 'Dateien') -json.dump(manifest, open('src/lib/font-faces.json', 'w', encoding='utf8'), indent=2) +json.dump(manifest, open(manifest_path, 'w', encoding='utf8'), indent=2) diff --git a/src/components/Kicker.astro b/src/components/Kicker.astro new file mode 100644 index 0000000..81c3920 --- /dev/null +++ b/src/components/Kicker.astro @@ -0,0 +1,22 @@ +--- +/** + * Abschnittskennung als Randnotiz: "02 · Was uns unterscheidet" wird zu + * großer Ziffer im Fleck plus kleiner Zeile darunter. Ohne Ziffer am Anfang + * bleibt es eine einfache Zeile. + */ +interface Props { + text: string; +} + +const { text } = Astro.props; +const match = text.match(/^(\d+)\s*·\s*(.+)$/); +--- + +{match ? ( +

+ {match[1]} + {match[2]} +

+) : ( +

{text}

+)} diff --git a/src/lib/font-faces.json b/src/lib/font-faces.json index ffbf9f1..293e6d0 100644 --- a/src/lib/font-faces.json +++ b/src/lib/font-faces.json @@ -184,5 +184,41 @@ "weight": "400 700", "unicodeRange": "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" } + ], + "Newsreader": [ + { + "file": "/fonts/newsreader/newsreader-latin-ext-0.woff2", + "weight": "400 700", + "unicodeRange": "U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF", + "style": "italic" + }, + { + "file": "/fonts/newsreader/newsreader-latin-1.woff2", + "weight": "400 700", + "unicodeRange": "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD", + "style": "italic" + }, + { + "file": "/fonts/newsreader/newsreader-latin-ext-2.woff2", + "weight": "400 700", + "unicodeRange": "U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF" + }, + { + "file": "/fonts/newsreader/newsreader-latin-3.woff2", + "weight": "400 700", + "unicodeRange": "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + } + ], + "Schibsted Grotesk": [ + { + "file": "/fonts/schibsted-grotesk/schibsted-grotesk-latin-ext-0.woff2", + "weight": "400 700", + "unicodeRange": "U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF" + }, + { + "file": "/fonts/schibsted-grotesk/schibsted-grotesk-latin-1.woff2", + "weight": "400 700", + "unicodeRange": "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + } ] } \ No newline at end of file diff --git a/src/lib/fonts.ts b/src/lib/fonts.ts index ad46191..51f140d 100644 --- a/src/lib/fonts.ts +++ b/src/lib/fonts.ts @@ -18,6 +18,7 @@ export const FONT_OPTIONS: FontOption[] = [ { name: 'Merriweather', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Libre Baskerville', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'DM Serif Display', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, + { name: 'Newsreader', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Georgia (Systemschrift)', category: 'serif', google: false, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Inter', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Roboto', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, @@ -27,6 +28,7 @@ export const FONT_OPTIONS: FontOption[] = [ { name: 'Nunito', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Work Sans', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Source Sans 3', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, + { name: 'Schibsted Grotesk', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'System UI (Systemschrift)', category: 'sans', google: false, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, ]; @@ -43,7 +45,7 @@ export function fontFamilyCss(name: string): string { * public/fonts (see font-faces.json). The fonts are served from our own * server so a page view never contacts Google. System fonts are skipped. */ export function localFontFacesCss(fontNames: string[]): string { - const faces = fontFaces as Record; + const faces = fontFaces as Record; return fontNames .map(findFont) .filter((f) => f.google) @@ -51,7 +53,7 @@ export function localFontFacesCss(fontNames: string[]): string { .flatMap((f) => (faces[f.name] || []).map( (face) => - `@font-face { font-family: '${f.name}'; font-style: normal; font-weight: ${face.weight}; ` + + `@font-face { font-family: '${f.name}'; font-style: ${face.style || 'normal'}; font-weight: ${face.weight}; ` + `font-display: swap; src: url('${face.file}') format('woff2'); unicode-range: ${face.unicodeRange}; }`, ), ) diff --git a/src/pages/index.astro b/src/pages/index.astro index d243451..529261d 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -2,6 +2,7 @@ import Layout from '../layouts/Layout.astro'; import Devices from '../components/Devices.astro'; import Zoom from '../components/Zoom.astro'; +import Kicker from '../components/Kicker.astro'; import { site, rich } from '../lib/content'; const { hero, warum, preis, highlights, leistungen, mappe, ablauf, about, faq, kontakt } = site; @@ -21,7 +22,7 @@ const findItem = (src: string) =>
-

{hero.eyebrow}

+

{hero.titleBefore}{hero.titleEmphasis}{hero.titleAfter}

@@ -33,6 +34,7 @@ const findItem = (src: string) =>
+ {hero.visual.customImage ? ( ) : ( @@ -52,7 +54,7 @@ const findItem = (src: string) =>
-

{preis.eyebrow}

+

{preis.title}

{preis.amount} {preis.amountNote}

@@ -78,9 +80,9 @@ const findItem = (src: string) =>

-
-
-

{warum.eyebrow}

+
+
+

{warum.title}

@@ -117,9 +119,9 @@ const findItem = (src: string) =>

-
-
-

{leistungen.eyebrow}

+
+
+

{leistungen.title}

@@ -139,7 +141,7 @@ const findItem = (src: string) =>

{leistungen.nichtMachenTitle}

{leistungen.nichtMachen.map((text) => ( -

— {text}

+

{text}

))}
@@ -147,9 +149,9 @@ const findItem = (src: string) =>
-
-
-

{mappe.eyebrow}

+
+
+

{mappe.title}

@@ -190,9 +192,9 @@ const findItem = (src: string) =>
-
-
-

{ablauf.eyebrow}

+
+
+

{ablauf.title}

@@ -211,7 +213,7 @@ const findItem = (src: string) =>
-
+
{about.photo ? (
@@ -227,9 +229,9 @@ const findItem = (src: string) => )}
-

{about.eyebrow}

+

{about.title}

-

{about.quote}

+

{about.quote}

{about.paragraphs.map((paragraph) => (

@@ -240,8 +242,8 @@ const findItem = (src: string) =>

-
-

{faq.eyebrow}

+
+

{faq.title}

@@ -264,7 +266,7 @@ const findItem = (src: string) =>
-

{kontakt.eyebrow}

+

{kontakt.title}

@@ -363,19 +365,43 @@ const findItem = (src: string) => diff --git a/src/styles/global.css b/src/styles/global.css index 6a5b7bd..f0635cb 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -27,8 +27,8 @@ --color-google-blue: #8fb2e8; /* Typografie */ - --font-serif: 'Playfair Display', Georgia, 'Times New Roman', serif; - --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; + --font-serif: 'Newsreader', Georgia, 'Times New Roman', serif; + --font-sans: 'Schibsted Grotesk', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; --font-size-sm: 0.875rem; --font-size-base: 1rem; @@ -106,13 +106,20 @@ svg { h1, h2, h3, h4 { margin: 0 0 var(--space-4) 0; line-height: var(--line-height-tight); - font-weight: var(--font-weight-bold); - letter-spacing: -0.01em; + font-weight: var(--font-weight-medium); + letter-spacing: -0.015em; font-family: var(--font-serif); + color: var(--color-text); } h1 { font-size: var(--font-size-3xl); } -h2 { font-size: var(--font-size-2xl); } +/* Skala mit Loch: Fließtext bleibt klein, Abschnittstitel werden deutlich größer */ +h2 { + font-size: clamp(2.1rem, 4.2vw, 3.5rem); + line-height: 1.08; + letter-spacing: -0.025em; + max-width: 20ch; +} h3 { font-size: var(--font-size-lg); } h4 { font-size: var(--font-size-md); } @@ -196,49 +203,145 @@ textarea { padding-block: var(--space-7); } -/* Dunkles Band (aus dem Prototyp "Nacht"): Angebot und Kontakt. +/* Dunkles Band in Petrol (Logofarbe): Angebot und Kontakt. Die Farben werden hier als Variablen neu gesetzt, damit Text, Karten, Buttons und Formularfelder darin automatisch mitdrehen - keine Einzelregeln, die gegen Bauteilklassen verlieren koennten. - Kontraste auf #1E1A14: Text 15,0 · leise 9,9 · Gold 9,1 · Rand 3,8. */ + Kontraste auf #1F3530: Text 11,5 · leise 8,2 · Rosé 7,6 · Rand 3,4. + Oberkante als Welle aus der Logoform: per Maske ausgeschnitten, darüber + scheint der Papiergrund durch. */ .section-dark { - --color-bg: #1e1a14; - --color-bg-alt: #2a241b; - --color-surface: #2a241b; - --color-text: #f5eee2; - --color-text-muted: #cfc2ac; - --color-border: #82755f; - --color-primary: #d8b87e; - --color-primary-dark: #e8d2a6; - --color-primary-contrast: #241c0b; - --color-accent: #d8b87e; - --color-accent-dark: #e8d2a6; - --color-flag: #e0836a; - --color-flag-bg: rgba(224, 131, 106, 0.14); + --color-bg: #1f3530; + --color-bg-alt: #2a443d; + --color-surface: #2a443d; + --color-text: #f3f0e8; + --color-text-muted: #c5d0c9; + --color-border: #6c877e; + --color-primary: #d9c0b4; + --color-primary-dark: #ead8cf; + --color-primary-contrast: #1f3530; + --color-accent: #d9c0b4; + --color-accent-dark: #ead8cf; + --color-flag: #f0a08a; + --color-flag-bg: rgba(240, 160, 138, 0.14); + --welle: 56px; background: var(--color-bg); color: var(--color-text); - padding-block: var(--space-9); + padding-block: calc(var(--space-9) + var(--welle) * 0.5) var(--space-9); + -webkit-mask: + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 56' preserveAspectRatio='none'%3E%3Cpath d='M0 34 C 240 2 520 52 830 24 C 1070 4 1270 8 1440 30 V56 H0 Z'/%3E%3C/svg%3E") top / 100% var(--welle) no-repeat, + linear-gradient(#000 0 0) 0 calc(var(--welle) - 1px) / 100% 100% no-repeat; + mask: + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 56' preserveAspectRatio='none'%3E%3Cpath d='M0 34 C 240 2 520 52 830 24 C 1070 4 1270 8 1440 30 V56 H0 Z'/%3E%3C/svg%3E") top / 100% var(--welle) no-repeat, + linear-gradient(#000 0 0) 0 calc(var(--welle) - 1px) / 100% 100% no-repeat; } .section-dark h1, .section-dark h2, .section-dark h3 { - color: #fffaf2; + color: #fbf8f1; } .section-dark ::placeholder { - color: #9a8f7b; + color: #9fb1a8; opacity: 1; } +/* Getönte Abschnitte für Rhythmus: Salbei, Sand, Rosé aus dem Logoverlauf */ +.tint-salbei { background: #e9efea; } +.tint-sand { background: #f1efe3; } +.tint-rose { background: #f5eae4; } + .eyebrow { display: inline-block; - color: var(--color-primary); - font-weight: var(--font-weight-semibold); + color: var(--color-text-muted); + font-weight: var(--font-weight-medium); font-size: var(--font-size-sm); - letter-spacing: 0.06em; - text-transform: uppercase; - margin-bottom: var(--space-3); + letter-spacing: 0.01em; + margin-bottom: var(--space-4); +} + +/* Abschnittskennung: Ziffer im Fleck aus dem Logo + Zeile daneben */ +.eyebrow-rand { + display: flex; + align-items: center; + gap: var(--space-3); +} + +.eyebrow-num { + position: relative; + display: grid; + place-items: center; + flex: none; + width: 2.6em; + height: 2.3em; + font-family: var(--font-serif); + font-style: italic; + font-size: 1.05rem; + font-weight: 500; + color: #2c4a42; + isolation: isolate; +} + +.eyebrow-num::before { + content: ''; + position: absolute; + inset: 0; + z-index: -1; + background: url('/form/fleck.svg') center / 100% 100% no-repeat; +} + +/* Randspalten-Raster: Kennung links in der Marginalie, Inhalt rechts. + Kinder landen standardmäßig in Spalte 2; wer volle Breite braucht, + setzt grid-column: 1 / -1. */ +.split { + display: grid; + grid-template-columns: minmax(8rem, 13rem) minmax(0, 1fr); + column-gap: clamp(2rem, 5vw, 5rem); +} + +.split > * { + grid-column: 2; +} + +.split > .eyebrow-rand { + grid-column: 1; + grid-row: 1 / span 3; + align-self: start; + flex-direction: column; + align-items: flex-start; + gap: var(--space-3); + max-width: 12rem; +} + +.split > .eyebrow-rand .eyebrow-num { + font-size: 2.6rem; +} + +@media (max-width: 900px) { + .split { + grid-template-columns: minmax(0, 1fr); + } + + .split > *, + .split > .eyebrow-rand { + grid-column: 1; + grid-row: auto; + } + + .split > .eyebrow-rand { + flex-direction: row; + align-items: center; + max-width: none; + } + + .split > .eyebrow-rand .eyebrow-num { + font-size: 1.4rem; + } + + .section-dark { + --welle: 32px; + } } .text-lead { @@ -268,7 +371,7 @@ textarea { .card { background: var(--color-surface); border: 1px solid var(--color-border); - border-radius: var(--radius-md); + border-radius: var(--radius-lg); padding: var(--space-6); box-shadow: var(--shadow-sm); } @@ -277,8 +380,8 @@ textarea { display: inline-flex; align-items: center; gap: var(--space-2); - border-radius: var(--radius-sm); - padding: var(--space-3) var(--space-5); + border-radius: 999px; + padding: 0.8rem 1.6rem; font-weight: var(--font-weight-semibold); font-size: var(--font-size-base); border: 1px solid transparent; @@ -299,13 +402,13 @@ textarea { .btn-secondary { background: transparent; - color: var(--color-text); - border-color: var(--color-border); + color: var(--color-primary); + border: 1.5px solid var(--color-primary); } .btn-secondary:hover { - border-color: var(--color-primary); - color: var(--color-primary); + background: var(--color-primary); + color: var(--color-primary-contrast); text-decoration: none; }