Serif + Grotesk als ‚Duotone‘ (Mono als dritte Stimme)
Startseite einer Bremer Kanzlei mit drei klar verteilten Stimmen: Newsreader für Titel und Zitate, Schibsted Grotesk für Text und Bedienung, DM Mono für Daten und Labels; ein Knopf färbt jedes Element nach seiner Schrift.
Zwei Schriften mit klar getrennten Rollen: eine Serif für Überschriften und Zitate, also für Haltung und Gefühl, eine Grotesk für Fließtext, Navigation und alles Bedienbare. Eine Mono kommt oft als dritte Stimme für Daten, Datum und Labels dazu.
Der Kontrast der Formen macht die Hierarchie sofort lesbar, ohne dass Größe oder Fett sie tragen müssen. Die Serif gibt Charakter, die Grotesk hält Interface und Text sachlich. Die Mono trennt Metadaten sichtbar vom Inhalt.
Wann einsetzen
Kanzleien, Beratungen, Verlage, Kultur, Agenturen und Produkte, die seriös und zugleich zeitgemäß wirken sollen. Gut bei Seiten mit viel Inhalt und vielen Metadaten wie Insights, Studien oder Projektlisten.
Wann nicht
Wenn die Rollen nicht durchgehalten werden: Eine Serif im Knopf und eine Grotesk im Zitat zerstören das System. Nicht bei sehr kleinen Seiten, auf denen eine Schrift reicht, und nicht mit zwei Schriften, die sich zu ähnlich sind.
Varianten
- Drei Stimmen: Serif für Titel, Grotesk für Text und Bedienung, Mono für Labels (Instrument, Resend)
- Serif als Bühne: sehr große, leichte Serif-Titel mit Grotesk und Mono (Your Majesty: IvyPresto 100, Messina, DM Mono)
- Reines Duotone ohne Mono, Labels in der Grotesk in Versalien
Umsetzung
Rollen als Custom Properties festlegen (--f-titel, --f-text, --f-label) und nur über Klassen zuweisen, nie Element für Element. Serif nur für h1 bis h3 und Zitate, Grotesk für Text, Navigation, Knöpfe und Formulare, Mono für Datum, Rubrik, Zahlen und Labels (klein, versal, Laufweite um .08em). Am einfachsten mit einer Superfamilie wie Instrument Sans, Serif und Mono.
Robust umsetzen
Telefon. Die Rollen bleiben gleich, nur die Titelgrößen schrumpfen über clamp(). Labels nicht unter 11 px setzen.
Ohne Bewegung. Nicht relevant, die Technik hat keine Bewegung.
Barrierefrei. Hierarchie auch semantisch auszeichnen (h1 bis h3), nicht nur über die Schriftwahl. Versalien per text-transform setzen. Serif-Texte in kleinen Größen auf Kontrast und Strichstärke prüfen, eine Serif mit opsz-Achse hilft dabei.
Code
<!DOCTYPE html>
<!--
Serif + Grotesk als ‚Duotone‘ (Mono als dritte Stimme)
Fundus · Typo-Techniken · https://cecodesign.de/lab/fundus/typo-techniken/serif-grotesk-duotone/
Eigenständige Datei. Bilder liegen hier unter bilder/ – eigene einsetzen.
-->
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Serif + Grotesk als ‚Duotone‘ (Mono als dritte Stimme) · Fundus-Demo</title>
<script>document.documentElement.classList.add('js');if(matchMedia('(prefers-reduced-motion: reduce)').matches)document.documentElement.classList.add('reduziert')</script>
<style>
@font-face { font-family: 'Newsreader'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/newsreader:vf@latest/latin-opsz-normal.woff2') format('woff2-variations'); font-weight: 200 800; font-style: normal; font-display: swap; }
@font-face { font-family: 'Newsreader'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/newsreader:vf@latest/latin-opsz-italic.woff2') format('woff2-variations'); font-weight: 200 800; font-style: italic; font-display: swap; }
@font-face { font-family: 'Schibsted Grotesk'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/schibsted-grotesk:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 400 900; font-display: swap; }
@font-face { font-family: 'DM Mono'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/dm-mono@latest/latin-400-normal.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'DM Mono'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/dm-mono@latest/latin-500-normal.woff2') format('woff2'); font-weight: 500; font-display: swap; }
:root {
/* Rezept „Kanzlei & Beratung“: ein tiefer Markenton (hier Aubergine), warme Graus, ein heller Akzent nur für Links und Fokus */
--grund: #f9f8f8; --flaeche: #efebeb; --linie: #d2cdc7; --text: #212529; --meta: #736458;
--marke: #2e1a47; --marke-2: #50316d; --lavendel: #9594d1; --lavendel-hell: #dbd9e7;
--akzent: #00bee6;
--kurve: cubic-bezier(0.4, 0, 0.22, 1); /* Oppenhoff */
--farbe: 125ms var(--kurve);
--ui: 250ms var(--kurve);
--serif: 'Newsreader', Georgia, serif;
--grotesk: 'Schibsted Grotesk', system-ui, sans-serif;
--mono: 'DM Mono', ui-monospace, monospace;
}
* { box-sizing: border-box; margin: 0; }
html { background: var(--grund); color: var(--text); font-family: var(--grotesk); -webkit-font-smoothing: antialiased; overflow-x: clip; }
body { min-height: 100svh; overflow-x: clip; }
button { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--akzent); outline-offset: 3px; }
/* ================= Der Effekt: drei Stimmen als Rollen-Token ================= */
.seite {
/* Standard „Rollen klar“: Serif für Titel und Zitate, Grotesk für Text und Bedienung, Mono für Daten und Labels */
--f-titel: var(--serif); --w-titel: 400; --ls-titel: -.01em;
--f-text: var(--grotesk); --w-ui: 500;
--f-label: var(--mono); --w-label: 400; --ls-label: .08em;
--h1: clamp(2rem, 1.3rem + 2.6vw, 3.5rem);
--h2: clamp(1.625rem, 1.2rem + 1.6vw, 2.5rem);
font-family: var(--f-text);
}
/* Variante: Serif als Bühne (sehr groß und leicht, wie bei Your Majesty) */
.seite[data-rolle='buehne'] { --w-titel: 200; --ls-titel: -.025em; --h1: clamp(2.5rem, 1.2rem + 4.6vw, 5.25rem); --h2: clamp(1.875rem, 1.2rem + 2.2vw, 3rem); }
/* Variante: reines Duotone, Labels in der Grotesk */
.seite[data-rolle='duo'] { --f-label: var(--grotesk); --w-label: 500; --ls-label: .06em; }
/* Gegenproben */
.seite[data-rolle='grotesk'] { --f-titel: var(--grotesk); --w-titel: 500; --ls-titel: -.025em; --f-label: var(--grotesk); --w-label: 500; --ls-label: .06em; }
.seite[data-rolle='serif'] { --f-text: var(--serif); --w-ui: 500; --f-label: var(--serif); --w-label: 500; --ls-label: .06em; }
.titel { font-family: var(--f-titel); font-weight: var(--w-titel); letter-spacing: var(--ls-titel); font-optical-sizing: auto; }
.titel em { font-style: italic; }
.lbl { font-family: var(--f-label); font-weight: var(--w-label); letter-spacing: var(--ls-label); font-size: .75rem; line-height: 1.4; text-transform: uppercase; font-variant-numeric: tabular-nums; }
.ui { font-weight: var(--w-ui); }
.leise { color: var(--meta); }
/* Stimmen zeigen: die Demo liest die berechnete Schrift jedes Textelements und färbt es ein */
.seite [data-stimme] { transition: background-color var(--ui), box-shadow var(--ui); }
.seite[data-zeigen='ja'] [data-stimme='serif'] { background-color: rgba(149, 148, 209, .38); box-shadow: 0 0 0 3px rgba(149, 148, 209, .38); }
.seite[data-zeigen='ja'] [data-stimme='grotesk'] { background-color: rgba(210, 205, 199, .62); box-shadow: 0 0 0 3px rgba(210, 205, 199, .62); }
.seite[data-zeigen='ja'] [data-stimme='mono'] { background-color: rgba(0, 190, 230, .22); box-shadow: 0 0 0 3px rgba(0, 190, 230, .22); }
.seite[data-zeigen='ja'] .knopf[data-stimme] { background-color: var(--marke); box-shadow: 0 0 0 3px rgba(210, 205, 199, .9); }
.seite[data-zeigen='ja'] .dunkel [data-stimme='grotesk'] { background-color: rgba(210, 205, 199, .22); box-shadow: 0 0 0 3px rgba(210, 205, 199, .22); }
.seite[data-zeigen='ja'] .dunkel [data-stimme='serif'] { background-color: rgba(149, 148, 209, .34); box-shadow: 0 0 0 3px rgba(149, 148, 209, .34); }
.seite[data-zeigen='ja'] .dunkel [data-stimme='mono'] { background-color: rgba(0, 190, 230, .26); box-shadow: 0 0 0 3px rgba(0, 190, 230, .26); }
/* Wechsel als ruhiger Crossfade (View Transitions, wie im Rezept für Seitenwechsel) */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 250ms; animation-timing-function: cubic-bezier(0.4, 0, 0.22, 1); }
/* ================= Fundus-Leiste (außerhalb der Seite, nicht fixiert) ================= */
.leiste { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 24px; padding: 12px clamp(16px, 3vw, 40px); background: #fff; border-bottom: 1px solid var(--linie); font: 400 11px/1.3 'DM Mono', ui-monospace, monospace; letter-spacing: .1em; text-transform: uppercase; color: var(--meta); }
.gruppen { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; }
.gruppe { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.gruppe > span { margin-right: 6px; }
.gruppe button { font: inherit; letter-spacing: .06em; text-transform: inherit; color: var(--meta); background: none; border: 1px solid var(--linie); border-radius: 999px; height: 28px; padding: 0 11px; cursor: pointer; white-space: nowrap; transition: color var(--farbe), background-color var(--farbe), border-color var(--farbe); }
.gruppe button:hover { color: var(--marke); border-color: var(--meta); }
.gruppe button[aria-pressed='true'] { background: var(--marke); border-color: var(--marke); color: #fff; }
.gruppe.gegen button[aria-pressed='true'] { background: #fff; color: var(--marke); border-color: var(--marke); }
.legende { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center; font-variant-numeric: tabular-nums; }
.legende i { display: inline-block; width: 10px; height: 10px; margin-right: 6px; vertical-align: -1px; border-radius: 2px; }
.legende b { font-weight: 500; color: var(--text); }
.legende .code { text-transform: none; letter-spacing: 0; color: var(--text); }
/* ================= Seite: Kopf ================= */
.kopf { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 20px clamp(16px, 3vw, 40px); border-bottom: 1px solid var(--linie); }
.marke-wort { display: grid; gap: 2px; color: var(--marke); white-space: nowrap; }
.marke-wort b { font-size: 1.5rem; line-height: 1; font-weight: var(--w-titel); }
.marke-wort span { font-size: .75rem; color: var(--meta); }
.nav { display: flex; gap: clamp(16px, 2vw, 30px); list-style: none; padding: 0; font-size: .9375rem; }
.nav a { position: relative; padding-block: 6px; transition: color var(--farbe); }
.nav a::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: left; transition: transform var(--ui); }
.nav a:hover { color: var(--marke-2); }
.nav a:hover::after { transform: scaleX(1); }
.kopf-rechts { display: flex; align-items: center; gap: 22px; font-size: .9375rem; }
.portal { color: var(--meta); transition: color var(--farbe); }
.portal:hover { color: var(--marke); }
.knopf { display: inline-flex; align-items: center; gap: 10px; background: var(--marke); color: #fff; padding: 12px 18px; border-radius: 2px; transition: background-color var(--farbe); }
.knopf:hover { background: var(--marke-2); }
.menue { display: none; }
/* ================= Seite: Einstieg ================= */
.einstieg { display: grid; grid-template-columns: 7fr 5fr; gap: clamp(32px, 5vw, 88px); padding: clamp(40px, 5.5vw, 84px) clamp(16px, 3vw, 40px) clamp(48px, 6vw, 92px); align-items: start; }
.einstieg-text { display: grid; gap: 26px; }
h1 { font-size: var(--h1); line-height: 1.1; color: var(--marke); text-wrap: balance; max-width: 15em; }
h1 em { font-weight: inherit; }
.lead { font-size: 1.0625rem; line-height: 1.6; max-width: 38em; text-wrap: pretty; }
.aktionen { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 26px; }
.textlink { border-bottom: 1px solid var(--linie); padding-block: 4px; transition: border-color var(--farbe), color var(--farbe); }
.textlink:hover { border-color: var(--marke); color: var(--marke); }
.fakten { display: grid; grid-template-columns: repeat(3, auto); justify-content: start; gap: 8px clamp(28px, 4vw, 56px); padding-top: 22px; border-top: 1px solid var(--linie); margin-top: 6px; }
.fakten div { display: grid; gap: 6px; }
.fakten dd { font-size: 1.0625rem; font-variant-numeric: tabular-nums; }
/* Studie als Einstieg (statt Stockfoto) */
.studie { background: var(--flaeche); padding: clamp(22px, 2.4vw, 34px); display: grid; gap: 16px; border-top: 3px solid var(--marke); }
.studie-kopf { display: flex; justify-content: space-between; gap: 12px; }
.studie h2 { font-size: clamp(1.5rem, 1.15rem + 1vw, 2rem); line-height: 1.12; color: var(--marke); text-wrap: balance; }
.studie p { font-size: .9375rem; line-height: 1.6; }
.balken { display: grid; gap: 10px; padding: 6px 0 4px; }
.balken div { display: grid; grid-template-columns: 1fr auto; gap: 6px 12px; align-items: baseline; }
.balken span:first-child { font-size: .875rem; }
.balken s { grid-column: 1 / -1; height: 8px; background: var(--grund); position: relative; text-decoration: none; }
.balken s::before { content: ''; position: absolute; inset: 0 auto 0 0; width: var(--w); background: var(--marke); }
.balken div:nth-child(2) s::before { background: var(--marke-2); }
.balken div:nth-child(3) s::before { background: var(--lavendel); }
.studie-fuss { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; padding-top: 14px; border-top: 1px solid var(--linie); }
/* ================= Seite: Insights ================= */
.insights { padding: clamp(48px, 6vw, 88px) clamp(16px, 3vw, 40px); border-top: 1px solid var(--linie); }
.abschnitt-kopf { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; margin-bottom: clamp(24px, 3vw, 40px); }
.abschnitt-kopf h2 { font-size: var(--h2); line-height: 1.1; color: var(--marke); }
.karten { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(20px, 2.6vw, 40px); }
.karte { display: grid; gap: 14px; align-content: start; padding-top: 18px; border-top: 1px solid var(--marke); }
.karte h3 { font-size: clamp(1.25rem, 1.1rem + .5vw, 1.5rem); line-height: 1.2; color: var(--marke); text-wrap: balance; transition: color var(--farbe); }
.karte p { font-size: .9375rem; line-height: 1.6; text-wrap: pretty; }
.karte:hover h3 { color: var(--marke-2); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .18em; }
/* ================= Seite: Rechtsgebiete (dunkle Sektion) ================= */
.dunkel { background: var(--marke); color: #f4f1f5; }
.dunkel .leise { color: rgba(219, 217, 231, .7); }
.gebiete { display: grid; grid-template-columns: 4fr 7fr; gap: clamp(32px, 5vw, 88px); padding: clamp(48px, 6vw, 88px) clamp(16px, 3vw, 40px); }
.gebiete h2 { font-size: var(--h2); line-height: 1.1; color: #fff; }
.gebiete-intro { display: grid; gap: 18px; align-content: start; }
.gebiete-intro p { font-size: 1.0625rem; line-height: 1.6; max-width: 32em; color: rgba(244, 241, 245, .86); }
.gebiete blockquote { font-size: 1.25rem; line-height: 1.35; font-style: italic; color: var(--lavendel-hell); margin-top: 10px; padding-left: 18px; border-left: 1px solid var(--lavendel); }
.liste { list-style: none; padding: 0; border-top: 1px solid rgba(219, 217, 231, .28); }
.liste li { display: grid; grid-template-columns: 48px 1fr auto; gap: 16px; align-items: baseline; padding: 16px 0 15px; border-bottom: 1px solid rgba(219, 217, 231, .18); transition: background-color var(--farbe); }
.liste h3 { font-size: clamp(1.25rem, 1.1rem + .5vw, 1.5rem); line-height: 1.2; font-weight: var(--w-titel); }
.liste li:hover { background: rgba(255, 255, 255, .04); }
.liste li:hover h3 { color: var(--lavendel-hell); }
/* ================= Seite: Visitenkarte ================= */
.fuss { display: grid; grid-template-columns: 1.3fr 1fr 1fr 1fr; gap: 24px; padding: 36px clamp(16px, 3vw, 40px) 40px; font-size: .9375rem; line-height: 1.55; }
.fuss .lbl { display: block; margin-bottom: 8px; }
.fuss a { border-bottom: 1px solid var(--linie); transition: border-color var(--farbe); }
.fuss a:hover { border-color: var(--akzent); }
/* ================= Vorschau 960 × 720: nur Kopf und Einstieg ================= */
.vorschau body { overflow: hidden; }
.vorschau .insights, .vorschau .gebiete, .vorschau .fuss, .vorschau .nav, .vorschau .portal, .vorschau .gruppe.gegen, .vorschau .gruppe > span, .vorschau .legende .code { display: none; }
.vorschau .einstieg { padding-top: 34px; gap: 40px; }
.vorschau .fakten { display: none; }
/* ================= Schmal ================= */
@media (max-width: 1180px) { .nav { display: none; } .menue { display: inline-flex; } }
@media (max-width: 900px) {
.einstieg, .gebiete { grid-template-columns: 1fr; }
.karten { grid-template-columns: 1fr 1fr; }
.karten .karte:last-child { display: none; }
.fuss { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
.portal { display: none; }
.marke-wort b { font-size: 1.25rem; }
.marke-wort span { font-size: .6875rem; }
.kopf { gap: 12px; }
.kopf .knopf { padding: 9px 12px; font-size: .875rem; }
.kopf-rechts { gap: 14px; }
.karten { grid-template-columns: 1fr; }
.karten .karte:last-child { display: grid; }
.fakten { grid-template-columns: 1fr 1fr; }
.liste li { grid-template-columns: 36px 1fr; }
.liste li .lbl:last-child { grid-column: 2; }
.fuss { grid-template-columns: 1fr; }
.legende .code { flex-basis: 100%; }
}
@media (hover: none) {
.gruppe button { height: 36px; padding: 0 13px; }
.nav a::after { display: none; }
}
:root.reduziert * { transition-duration: .01ms !important; animation-duration: .01ms !important; }
@media (forced-colors: active) { button, [role=button], [role=tab], [role=switch] { border: 1px solid ButtonText !important; } }
</style>
</head>
<body>
<div class="leiste">
<div class="gruppen">
<div class="gruppe" role="group" aria-label="Rollen">
<span>Rollen</span>
<button type="button" data-rolle-knopf="klar" aria-pressed="true">Drei Stimmen</button>
<button type="button" data-rolle-knopf="buehne" aria-pressed="false">Serif als Bühne</button>
<button type="button" data-rolle-knopf="duo" aria-pressed="false">Ohne Mono</button>
</div>
<div class="gruppe gegen" role="group" aria-label="Gegenprobe">
<span>Gegenprobe</span>
<button type="button" data-rolle-knopf="grotesk" aria-pressed="false">Nur Grotesk</button>
<button type="button" data-rolle-knopf="serif" aria-pressed="false">Nur Serif</button>
</div>
<div class="gruppe" role="group" aria-label="Anzeige">
<button type="button" data-zeigen-knopf aria-pressed="false">Stimmen zeigen</button>
</div>
</div>
<p class="legende" aria-live="polite">
<span><i style="background: rgba(149, 148, 209, .7)"></i>Serif <b data-zahl="serif">0</b></span>
<span><i style="background: #d2cdc7"></i>Grotesk <b data-zahl="grotesk">0</b></span>
<span><i style="background: rgba(0, 190, 230, .5)"></i>Mono <b data-zahl="mono">0</b></span>
<span class="code" data-code></span>
</p>
</div>
<div class="seite" data-buehne data-rolle="klar" data-zeigen="nein">
<header class="kopf">
<a class="marke-wort" href="#"><b class="titel">Osterholt Vahl</b><span>Rechtsanwälte Partnerschaft mbB</span></a>
<nav aria-label="Hauptnavigation">
<ul class="nav ui">
<li><a href="#">Rechtsgebiete</a></li>
<li><a href="#">Branchen</a></li>
<li><a href="#">Köpfe</a></li>
<li><a href="#">Insights</a></li>
<li><a href="#">Karriere</a></li>
</ul>
</nav>
<div class="kopf-rechts ui">
<a class="portal" href="#">Mandantenportal</a>
<a class="menue" href="#">Menü</a>
<a class="knopf" href="#">Erstgespräch</a>
</div>
</header>
<main>
<section class="einstieg" aria-labelledby="h1">
<div class="einstieg-text">
<p class="lbl leise">Handel · Schifffahrt · Mittelstand · Bremen</p>
<h1 class="titel" id="h1">Wir beraten Unternehmen, die <em>vom Handel leben.</em> Seit 1962 an der Schlachte.</h1>
<p class="lead">Osterholt Vahl begleitet Reedereien, Logistiker und Familienunternehmen im Nordwesten: bei Verträgen und Streitfällen, bei Nachfolge und Kauf, bei allem, was im Kontor entschieden wird und im Hafen gelten muss.</p>
<div class="aktionen ui">
<a class="knopf" href="#">Erstgespräch vereinbaren <span aria-hidden="true">→</span></a>
<a class="textlink" href="#">Alle Rechtsgebiete</a>
</div>
<dl class="fakten">
<div><dt class="lbl leise">Gegründet</dt><dd>1962</dd></div>
<div><dt class="lbl leise">Berufsträger</dt><dd>34</dd></div>
<div><dt class="lbl leise">Sprachen</dt><dd>DE · EN · NL · PL</dd></div>
</dl>
</div>
<article class="studie" aria-labelledby="studie-titel">
<div class="studie-kopf"><span class="lbl">Studie 03 / 2026</span><span class="lbl leise">212 Befragte</span></div>
<h2 class="titel" id="studie-titel">Lieferketten im Bremer Mittelstand</h2>
<p>Wir haben Händler, Reedereien und Zulieferer zwischen Weser und Ems gefragt, wie weit sie ihre Lieferanten geprüft haben.</p>
<div class="balken" aria-label="Stand der Lieferantenprüfung">
<div><span>Vollständig geprüft</span><span class="lbl">38 %</span><s style="--w: 38%"></s></div>
<div><span>Teilweise geprüft</span><span class="lbl">44 %</span><s style="--w: 44%"></s></div>
<div><span>Noch nicht begonnen</span><span class="lbl">18 %</span><s style="--w: 18%"></s></div>
</div>
<div class="studie-fuss"><span class="lbl leise">32 Seiten · PDF · 2,4 MB</span><a class="textlink ui" href="#">Studie lesen →</a></div>
</article>
</section>
<section class="insights" aria-labelledby="insights-titel">
<div class="abschnitt-kopf"><h2 class="titel" id="insights-titel">Insights</h2><a class="lbl leise" href="#">Alle Beiträge (48)</a></div>
<div class="karten">
<a class="karte" href="#">
<span class="lbl leise">14.10.2026 · Arbeitsrecht</span>
<h3 class="titel">Saisonkräfte im Hafen: Befristung richtig aufsetzen</h3>
<p>Wer Aushilfen für den Umschlag braucht, sollte Grund, Dauer und Verlängerung von Anfang an schriftlich regeln.</p>
<span class="lbl">Gesche Brüning</span>
</a>
<a class="karte" href="#">
<span class="lbl leise">02.10.2026 · Transportrecht</span>
<h3 class="titel">Wenn der Liegeplatz ausfällt: Wer trägt die Wartezeit?</h3>
<p>Drei Klauseln, die wir in Charterverträgen immer prüfen, bevor ein Schiff vor der Kaje warten muss.</p>
<span class="lbl">Malte Vahl</span>
</a>
<a class="karte" href="#">
<span class="lbl leise">19.09.2026 · Gesellschaftsrecht</span>
<h3 class="titel">Gesellschafterwechsel ohne Streit</h3>
<p>Vorkaufsrecht, Abfindung, Bewertung: was im Vertrag stehen muss, damit der Wechsel in der nächsten Generation gelingt.</p>
<span class="lbl">Dr. Janne Osterholt</span>
</a>
</div>
</section>
<section class="gebiete dunkel" aria-labelledby="gebiete-titel">
<div class="gebiete-intro">
<span class="lbl leise">Rechtsgebiete</span>
<h2 class="titel" id="gebiete-titel">Sechs Schwerpunkte, ein Team</h2>
<p>Jedes Mandat hat eine feste Ansprechperson. Sie holt die Kolleginnen und Kollegen dazu, die es braucht.</p>
<blockquote class="titel">„Wir schreiben Verträge so, dass man sie im Streit nicht braucht.“</blockquote>
<span class="lbl leise">Okke Siefken, Partner</span>
</div>
<ol class="liste">
<li><span class="lbl leise">01</span><h3 class="titel">Schifffahrts- und Transportrecht</h3><span class="lbl leise">8 Köpfe</span></li>
<li><span class="lbl leise">02</span><h3 class="titel">Handels- und Vertriebsrecht</h3><span class="lbl leise">6 Köpfe</span></li>
<li><span class="lbl leise">03</span><h3 class="titel">Gesellschaftsrecht und Nachfolge</h3><span class="lbl leise">7 Köpfe</span></li>
<li><span class="lbl leise">04</span><h3 class="titel">Arbeitsrecht</h3><span class="lbl leise">5 Köpfe</span></li>
<li><span class="lbl leise">05</span><h3 class="titel">Immobilien- und Baurecht</h3><span class="lbl leise">4 Köpfe</span></li>
<li><span class="lbl leise">06</span><h3 class="titel">Prozessführung und Schiedsverfahren</h3><span class="lbl leise">4 Köpfe</span></li>
</ol>
</section>
</main>
<footer class="fuss">
<div><span class="lbl leise">Bremen</span>Martinistraße 58<br>28195 Bremen<br><a href="#">0421 520 77 0</a></div>
<div><span class="lbl leise">Bremerhaven</span>Am Alten Hafen 9<br>27568 Bremerhaven<br><a href="#">0471 300 81 4</a></div>
<div><span class="lbl leise">Kontakt</span><a href="#">kanzlei@osterholt-vahl.de</a><br><a href="#">Mandantenportal</a></div>
<div><span class="lbl leise">Berufsrecht</span>Hanseatische Rechtsanwaltskammer Bremen<br><a href="#">Impressum</a></div>
</footer>
</div>
<script>
(() => {
const html = document.documentElement;
const reduziert = () => html.classList.contains('reduziert');
const buehne = document.querySelector('[data-buehne]');
const rollenKnoepfe = [...document.querySelectorAll('[data-rolle-knopf]')];
const zeigenKnopf = document.querySelector('[data-zeigen-knopf]');
const code = document.querySelector('[data-code]');
const zahlen = { serif: document.querySelector('[data-zahl="serif"]'), grotesk: document.querySelector('[data-zahl="grotesk"]'), mono: document.querySelector('[data-zahl="mono"]') };
// Exakt die Werte aus dem CSS (für die Anzeige)
const CODE = {
klar: 'Newsreader 400 · Schibsted Grotesk 400/500 · DM Mono 400 .08em',
buehne: 'Newsreader 200, -0.025em · Schibsted Grotesk 400/500 · DM Mono 400 .08em',
duo: 'Newsreader 400 · Schibsted Grotesk 400/500, Labels 500 .06em',
grotesk: 'nur Schibsted Grotesk 400/500',
serif: 'nur Newsreader 400/500'
};
// Welche Stimme spricht? Aus der berechneten Schrift jedes Textelements gelesen.
function stimmen() {
const n = { serif: 0, grotesk: 0, mono: 0 };
buehne.querySelectorAll('[data-stimme]').forEach(el => el.removeAttribute('data-stimme'));
buehne.querySelectorAll('*').forEach(el => {
if (!el.offsetParent && el.tagName !== 'BODY') return;
const text = [...el.childNodes].some(k => k.nodeType === 3 && k.textContent.trim());
if (!text) return;
const f = getComputedStyle(el).fontFamily.toLowerCase();
const s = f.includes('newsreader') ? 'serif' : f.includes('mono') ? 'mono' : 'grotesk';
const eltern = el.parentElement.closest('[data-stimme]');
if (eltern && eltern.dataset.stimme === s && eltern.contains(el)) return;
el.dataset.stimme = s; n[s]++;
});
for (const k in n) zahlen[k].textContent = n[k];
}
let rolle = 'klar', zeigen = false;
function anwenden(neu, an) {
rolle = neu; zeigen = an;
buehne.dataset.rolle = neu; buehne.dataset.zeigen = an ? 'ja' : 'nein';
rollenKnoepfe.forEach(k => k.setAttribute('aria-pressed', String(k.dataset.rolleKnopf === neu)));
zeigenKnopf.setAttribute('aria-pressed', String(an));
code.textContent = CODE[neu];
stimmen();
}
// Schriftwechsel lassen sich nicht interpolieren: kurzer Crossfade per View Transition, sonst sofort
function setzen(neu, an) {
if (neu === rolle && an === zeigen) return;
if (document.startViewTransition && !reduziert() && neu !== rolle) document.startViewTransition(() => anwenden(neu, an));
else anwenden(neu, an);
}
rollenKnoepfe.forEach(k => k.addEventListener('click', () => { pause(); setzen(k.dataset.rolleKnopf, zeigen); }));
zeigenKnopf.addEventListener('click', () => { pause(); setzen(rolle, !zeigen); });
addEventListener('resize', stimmen);
anwenden('klar', false);
document.fonts && document.fonts.ready.then(stimmen);
// Vorführung: Stimmen zeigen, Gegenprobe Nur Grotesk, dann die Varianten
const FOLGE = [
['klar', true], ['grotesk', true], ['grotesk', false], ['klar', false],
['serif', false], ['klar', false], ['buehne', false], ['duo', true], ['klar', true]
];
const TAKT = 2400;
let uhr = null, schritt = 0;
function takt() {
const [r, an] = FOLGE[schritt % FOLGE.length];
setzen(r, an);
schritt++;
uhr = setTimeout(takt, TAKT);
}
function neustart() { pause(); schritt = 0; anwenden('klar', false); }
function vorfuehren() { neustart(); html.classList.add('vorfuehrung'); uhr = setTimeout(takt, 900); }
function pause() { clearTimeout(uhr); uhr = null; }
function weiter() { if (!uhr && html.classList.contains('vorfuehrung')) uhr = setTimeout(takt, 600); }
})();
</script>
</body>
</html>