Zum Inhalt
← Hero & Section-Layouts

Foto-Hero: echtes Foto, ein Satz, ein Weg

Fünf Bildregien für den Foto-Hero der KMU-Seiten: Vollbild mit Satz unten links, Split mit Foto bis an den Rand, Foto im Rahmen auf der Markenfarbe, kleiner Abzug mit Chip und Bildunterschrift als Gestaltung, je mit kurzem Auftritt beim ersten Laden.

Starkes Querformat mit ruhiger, dunkler Zone unten links: immobilien-diskret-hochwertig, verein-nonprofit-wirkung, mode-beauty-kollektion; dazu fitness-studio-rhythmus und eventlocation-hochzeit, solange keine Leiste am Bild hängt.

Der Hero der meisten KMU-Seiten: ein echtes Foto vom Haus, vom Raum, von der Lage oder von der Arbeit, dazu ein einziger Satz mit Leistung und Ort und ein bis zwei Wege (Anfrage, Termin, Telefon). Das Muster liefert kein einzelnes Layout, sondern belegte Kompositionen: wo das Bild steht, wie groß es ist, wo der Text liegt und was am Bild hängt (Rahmen, Chip, Bildunterschrift). Bewegung ist Nebensache: höchstens ein Auftritt nach intro-ohne-wartezeit beim ersten Laden.

Ein echtes Foto zeigt in einer Sekunde, wer hier arbeitet und wo. Gleichförmig wird der Foto-Hero erst durch die immer gleiche Komposition: Bild randlos, Text mittig, zwei Knöpfe, dunkler Verlauf über alles. Eine eigene Bildregie je Branche macht den Unterschied: das Haus im Rahmen auf der Markenfarbe, die Lage als kleiner Abzug auf Löss, das Projekt mit Bildunterschrift wie in einer Monografie.

Wann einsetzen

In allen Rezepten, deren hero_beschreibung einen Foto-Hero oder ein echtes Foto nennt (16 von 28). Die Variante folgt dem hero_aufbau des Rezepts und dem vorhandenen Material: großes Querformat mit ruhiger Zone, Werkstatt- oder Teamfoto, ein starkes Hausfoto, nur kleine Handyfotos, Projektfotografie.

Wann nicht

Ohne eigenes, brauchbares Foto: dann ein Schrift-Hero (schrift-hero-viewportbreit) oder die Variante passepartout mit dem einen guten Bild. Keine Stockfotos von lächelnden Menschen, kein Text quer über Gesichtern. Nicht zentriert mit zwei Knöpfen und dunklem Verlauf über dem ganzen Bild: Das ist der Template-Standard, gegen den das Muster gebaut ist. Nicht als Magazin-Titel (dafür editorial-magazin-layout, Variante cover).

Varianten

  • randlos-unten-links: Vollbild 100svh, Satz klein unten links auf ruhiger Bildzone, nur weiche Abdunklung unten (30 bis 40 % der Höhe)
  • split-randabfallend: Text über Spalte 1 bis 5, Foto bis an den rechten Bildschirmrand, asymmetrisch 60/40 oder 55/45, nie 50/50
  • inset-rahmen: Foto mit 24 bis 40 px Rand rundum auf der Markenfarbe, Kopf mit Wortmarke darüber
  • passepartout: kleines Hochformat-Foto (25 bis 35 % der Breite) wie ein Abzug auf Farb- oder Materialfläche, Bildunterschrift als Chip
  • bildunterschrift: „Fig. 1 · Ort · Jahr“ als figcaption neben dem Bild ist das Gestaltungselement

Umsetzung

Ein <picture> mit Art Direction: Quer- bzw. 3:2-Format am Desktop, 4:5 auf dem Telefon. Das LCP-Bild bekommt fetchpriority="high", nie loading="lazy", und eine feste aspect-ratio oder width und height. Das Raster kommt aus tokens.css (--raster-*), die Spalten der Variante aus dem hero_aufbau des Rezepts. Text nie auf unruhiger Bildzone: entweder ein Bildausschnitt mit ruhiger Fläche (object-position), eine weiche Abdunklung nur unter dem Text oder der Text neben dem Bild. H1 = Leistung und Ort; ein bis zwei Wege als Primär- und Sekundär-Gestalt aus muster.button, Telefon als tel:-Link mit sichtbarer Nummer. Der Auftritt folgt intro-ohne-wartezeit: Zeilen steigen aus Masken (translateY 110 % → 0), das Bild öffnet per clip-path ab 2 % sichtbarer Fläche, damit der LCP im ersten Frame zählt; nur beim ersten Aufruf der Sitzung (einmal-intro-session), danach steht alles. Anhängsel der Variante (Rahmen, Chip, Bildunterschrift) sind eigene Elemente im Fluss und fallen auf dem Telefon unter das Bild.

Robust umsetzen

Telefon. Jede Variante hat einen Telefonzustand: Foto oben im Format 4:5, Satz darunter, Wege in voller Breite. Rahmen, Chip und Bildunterschrift fallen in den Fluss unter das Bild. Nichts liegt auf dem Telefon über dem Foto.

Ohne Bewegung. Alles steht ab dem ersten Frame: keine Masken, kein clip-path, kein Zoom. Höchstens ein kurzes Einblenden unter 200 ms.

Barrierefrei. Text-Kontrast 4,5:1 gegen die tatsächliche Bildzone, im ungünstigsten Ausschnitt geprüft; sonst Abdunklung unter dem Text oder Text neben dem Bild. Das alt beschreibt das Foto, nicht den Slogan. Bei 320 px und 200 % Zoom wird kein Text über dem Bild abgeschnitten. Fokus auf allen Wegen sichtbar, Trefferflächen mindestens 44 px.

Code

<!DOCTYPE html>
<!--
  Foto-Hero: echtes Foto, ein Satz, ein Weg
  Fundus · Hero & Section-Layouts · https://cecodesign.de/lab/fundus/hero-layouts/foto-hero/
  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>Foto-Hero: echtes Foto, ein Satz, ein Weg · Fundus-Demo</title>
<script>document.documentElement.classList.add('js');if(matchMedia('(prefers-reduced-motion: reduce)').matches)document.documentElement.classList.add('reduziert')</script>
<script>/* Variante aus ?v= und Auftritt nur beim ersten Aufruf je Sitzung (wie einmal-intro-session), vor dem ersten Paint */
(function () {
  var V = ['randlos-unten-links', 'split-randabfallend', 'inset-rahmen', 'passepartout', 'bildunterschrift'];
  var h = document.documentElement, q = new URLSearchParams(location.search), v = q.get('v');
  if (V.indexOf(v) < 0) v = V[0];
  h.setAttribute('data-v', v);
  var gesehen = null;
  try { gesehen = sessionStorage.getItem('foto-hero:' + v); sessionStorage.setItem('foto-hero:' + v, '1'); } catch (e) {}
  h.setAttribute('data-intro', gesehen ? 'aus' : 'an');
})();</script>
<style>
/* Pult */
@font-face { font-family: 'Geist Mono'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/geist-mono:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-display: swap; }
/* Immobilien und Architektur */
@font-face { font-family: 'Libre Caslon Display'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/libre-caslon-display@latest/latin-400-normal.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Hanken Grotesk'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/hanken-grotesk:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 100 900; font-style: normal; font-display: swap; }
/* Handwerk */
@font-face { font-family: 'Special Gothic'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/special-gothic:vf@latest/latin-standard-normal.woff2') format('woff2-variations'); font-weight: 400 700; font-stretch: 75% 125%; font-display: swap; }
@font-face { font-family: 'Atkinson Hyperlegible Next'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/atkinson-hyperlegible-next:vf@latest/latin-wght-normal.woff2') format('woff2-variations'); font-weight: 200 800; font-display: swap; }
/* Hotel */
@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: 'Mona Sans'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/mona-sans:vf@latest/latin-wdth-normal.woff2') format('woff2-variations'); font-weight: 200 900; font-stretch: 75% 125%; font-display: swap; }
/* Weingut */
@font-face { font-family: 'EB Garamond'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/eb-garamond:vf@latest/latin-wght-normal.woff') format('woff'); font-weight: 400 800; font-style: normal; font-display: swap; }
@font-face { font-family: 'EB Garamond'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/eb-garamond:vf@latest/latin-wght-italic.woff2') format('woff2-variations'); font-weight: 400 800; font-style: italic; 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; }

* { box-sizing: border-box; margin: 0; }
html { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; background: #121212; }
body { min-height: 100svh; overflow-x: clip; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; padding: 0; }
:root:has(:focus-visible) { scroll-behavior: auto; }

/* ── Gemeinsam: eine Bühne je Variante, nur die gewählte ist sichtbar ── */
.hero { display: none; position: relative; }
:root[data-v='randlos-unten-links'] .h-randlos,
:root[data-v='split-randabfallend'] .h-split,
:root[data-v='inset-rahmen'] .h-inset,
:root[data-v='passepartout'] .h-passe,
:root[data-v='bildunterschrift'] .h-fig { display: grid; }

/* Zeilenmaske (intro-ohne-wartezeit) */
.z { display: block; overflow: hidden; padding-bottom: .12em; margin-bottom: -.12em; }
.z > span { display: block; text-wrap: balance; }
.foto { position: relative; overflow: hidden; }
.foto img { width: 100%; height: 100%; object-fit: cover; }

/* ── Der Auftritt: reines CSS, startet mit dem ersten Paint, Werte je Variante über Variablen ── */
@keyframes steigen    { from { transform: translateY(110%); } }
@keyframes auftauchen { from { opacity: 0; transform: translateY(var(--n-weg)); } }
@keyframes oeffnen    { from { clip-path: var(--clip-start); } to { clip-path: inset(0 0 0 0); } }
@keyframes entzoomen  { from { transform: scale(var(--b-scale)); } }
@keyframes linie      { from { transform: scaleX(0); } }
:root[data-intro='an'] .hero .z > span { animation: steigen var(--z-dauer) var(--kurve) both; animation-delay: calc(var(--z-start) + var(--i, 0) * var(--z-stagger)); }
:root[data-intro='an'] .hero .nach { animation: auftauchen var(--n-dauer) var(--kurve) both; animation-delay: var(--d, 0ms); }
:root[data-intro='an'] .hero .auf { animation: oeffnen var(--b-dauer) var(--kurve) both; }
:root[data-intro='an'] .hero .auf img { animation: entzoomen var(--s-dauer) var(--kurve) both; }
.reduziert .hero *, .reduziert .hero *::before, .reduziert .hero *::after { animation: none !important; transition: none !important; }

:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

/* ═════════ 1 · randlos-unten-links · Immobilien (Haldenwang, Überlingen) ═════════ */
.h-randlos {
  /* tokens immobilien-diskret-hochwertig: token-editorial-langsam */
  --kurve: cubic-bezier(0.16, 1, 0.3, 1);
  --z-dauer: 900ms; --z-stagger: 80ms; --z-start: 200ms;
  --b-dauer: 1100ms; --s-dauer: 1100ms; --clip-start: inset(98% 0 0 0); --b-scale: 1.1;
  --n-dauer: 600ms; --n-weg: 12px;
  --rand: clamp(20px, 4vw, 64px); --spalt: clamp(16px, 2vw, 32px);
  --grund: #FCFAF5; --marke: #02385C; --text: #313131; --leise: #716F6D; --signal: #ED7F1A; --hell: #FCFAF5;
  height: 100svh; max-height: 100vh; min-height: 560px;
  grid-template-columns: repeat(12, minmax(0, 1fr)); grid-template-rows: auto 1fr auto; column-gap: var(--spalt);
  padding: 0 var(--rand); background: #151a2c; color: var(--hell);
  font: 400 1.0625rem/1.55 'Hanken Grotesk', system-ui, sans-serif;
}
.r-bild { position: absolute; inset: 0; }
.r-bild img { object-position: 62% 50%; }
/* nur unten eine weiche Abdunklung, 36 % der Höhe; kein Verlauf über das ganze Bild */
.r-bild::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 36%; background: linear-gradient(to top, rgb(9 11 20 / .62), rgb(9 11 20 / .28) 55%, rgb(9 11 20 / 0)); pointer-events: none; }
.r-kopf { grid-column: 1 / -1; position: relative; display: flex; align-items: baseline; gap: clamp(20px, 3vw, 48px); padding: 26px 0; }
.r-marke { font: 400 1.6rem/1 'Libre Caslon Display', Georgia, serif; letter-spacing: -.005em; display: flex; align-items: baseline; gap: .6em; }
.r-marke span { font: 500 .75rem/1 'Hanken Grotesk', sans-serif; letter-spacing: .09em; text-transform: uppercase; }
.r-kopf nav { margin-left: auto; }
.r-kopf ul { display: flex; gap: clamp(18px, 2.4vw, 36px); font-size: .9375rem; }
.r-kopf ul a, .r-tel { padding-block: 10px; background: linear-gradient(currentColor 0 0) left 100% / 0 1px no-repeat; transition: background-size 400ms var(--kurve); }
.r-kopf ul a:hover, .r-tel:hover { background-size: 100% 1px; }
.r-tel { font-size: .9375rem; font-variant-numeric: tabular-nums; }
.r-text { grid-column: 1 / 7; grid-row: 3; position: relative; padding-bottom: clamp(36px, 7vh, 72px); }
.r-h1 { font: 400 clamp(2.25rem, 1.5rem + 2vw, 3.4rem)/1.08 'Libre Caslon Display', Georgia, serif; letter-spacing: -.005em; text-wrap: balance; }
.r-lead { margin-top: 18px; max-width: 46ch; font-size: 1.0625rem; color: rgb(252 250 245 / .9); }
.r-wege { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.r-wege a { display: inline-flex; align-items: center; gap: 12px; min-height: 48px; padding: 0 24px; border-radius: 999px; font-weight: 500; font-size: 1rem; transition: background-color 200ms var(--kurve), color 200ms var(--kurve); }
.r-primaer { background: var(--hell); color: var(--marke); }
.r-primaer i { display: grid; place-items: center; width: 26px; height: 26px; margin-right: -12px; border-radius: 50%; background: var(--marke); color: var(--hell); font-style: normal; font-size: .875rem; transition: transform 200ms var(--kurve); }
.r-primaer:hover i { transform: translateX(3px); }
.r-zweit { background: var(--signal); color: #1b1712; }
.r-zweit:hover { background: #f39441; }
.r-objekt { grid-column: 9 / -1; grid-row: 3; align-self: end; justify-self: end; position: relative; padding-bottom: clamp(36px, 7vh, 72px); text-align: right; font-size: .875rem; line-height: 1.5; font-variant-numeric: tabular-nums; color: rgb(252 250 245 / .9); }
.r-objekt b { display: block; font-weight: 600; }
.h-randlos :focus-visible { outline-color: var(--hell); }

/* ═════════ 2 · split-randabfallend · Handwerk (Stellmacher, Höxter) ═════════ */
.h-split {
  /* tokens handwerk-werkstatt-klartext: token-tech-praezise (Eintritt) */
  --kurve: cubic-bezier(0, 0, 0.38, 0.9);
  --z-dauer: 400ms; --z-stagger: 60ms; --z-start: 80ms;
  --b-dauer: 700ms; --s-dauer: 0ms; --clip-start: inset(0 0 0 98%); --b-scale: 1;
  --n-dauer: 240ms; --n-weg: 8px;
  --rand: clamp(16px, 4vw, 48px); --spalt: clamp(16px, 2.4vw, 32px); --max: 1280px;
  --grund: #EFEDEA; --flaeche: #D3CDC2; --text: #1A1A1A; --leise: #696867; --signal: #FB6100;
  min-height: 100svh;
  grid-template-columns: minmax(max(0px, calc(var(--rand) - var(--spalt))), 1fr) repeat(12, minmax(0, calc((var(--max) - 2 * var(--rand) - 11 * var(--spalt)) / 12))) minmax(max(0px, calc(var(--rand) - var(--spalt))), 1fr);
  column-gap: var(--spalt);
  background: var(--grund); color: var(--text);
  font: 400 1.0625rem/1.55 'Atkinson Hyperlegible Next', system-ui, sans-serif;
}
.h-split { grid-template-rows: auto 1fr auto; }
.s-kopf { grid-column: 2 / 7; grid-row: 1; padding-top: 26px; display: flex; flex-wrap: wrap; align-items: center; gap: 14px 28px; }
.s-marke { display: grid; gap: 4px; }
.s-marke b { font: 700 1.5rem/1 'Special Gothic', system-ui, sans-serif; font-stretch: 75%; letter-spacing: .02em; text-transform: uppercase; }
.s-marke span { font-size: .8125rem; color: var(--leise); }
.s-kopf ul { display: flex; flex-wrap: wrap; gap: 4px 20px; font-size: .9375rem; }
.s-kopf ul a { display: inline-block; padding-block: 10px; background: linear-gradient(currentColor 0 0) left 100% / 0 2px no-repeat; transition: background-size 150ms var(--kurve); }
.s-kopf ul a:hover { background-size: 100% 2px; }
.s-text { grid-column: 2 / 7; grid-row: 2; align-self: center; padding-block: 40px; container-type: inline-size; }
.s-h1 { font: 700 clamp(2.25rem, 1.5rem + 3vw, 3.5rem)/1.05 'Special Gothic', system-ui, sans-serif; font-size: min(clamp(2.25rem, 1.5rem + 3vw, 3.5rem), 14.5cqi); letter-spacing: -.01em; }
.s-region { display: flex; align-items: center; gap: 14px; margin-top: 22px; font-weight: 600; font-size: 1.0625rem; }
.s-region::before { content: ''; flex: 0 0 32px; height: 2px; background: var(--text); }
.s-wege { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }
.s-wege a { display: inline-flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 22px; border-radius: 4px; font-weight: 700; font-size: 1rem; }
.s-anfrage { background: var(--signal); color: #1A1A1A; transition: background-color 150ms var(--kurve); }
.s-anfrage:hover { background: #ff7a26; }
/* Kontur mit Eckklammern (kontur-button-zeichnen, Variante ecken) */
.s-anrufen { position: relative; font-variant-numeric: tabular-nums;
  background:
    linear-gradient(var(--text) 0 0) 0 0 / 10px 2px, linear-gradient(var(--text) 0 0) 0 0 / 2px 10px,
    linear-gradient(var(--text) 0 0) 100% 0 / 10px 2px, linear-gradient(var(--text) 0 0) 100% 0 / 2px 10px,
    linear-gradient(var(--text) 0 0) 0 100% / 10px 2px, linear-gradient(var(--text) 0 0) 0 100% / 2px 10px,
    linear-gradient(var(--text) 0 0) 100% 100% / 10px 2px, linear-gradient(var(--text) 0 0) 100% 100% / 2px 10px;
  background-repeat: no-repeat; transition: background-size 150ms var(--kurve); }
.s-anrufen:hover { background-size: 50% 2px, 2px 50%, 50% 2px, 2px 50%, 50% 2px, 2px 50%, 50% 2px, 2px 50%; }
.s-anrufen svg { width: 18px; height: 18px; }
.s-zeit { grid-column: 2 / 7; grid-row: 3; margin-bottom: 32px; font-size: .8125rem; color: var(--leise); display: flex; gap: 18px; flex-wrap: wrap; border-top: 1px solid var(--flaeche); padding-top: 14px; }
.s-zeit div { display: flex; gap: 6px; }
.s-zeit dt { font-weight: 600; color: var(--text); }
.s-zeit dd { margin: 0; }
.s-bild { grid-column: 7 / -1; grid-row: 1 / 4; position: relative; height: 100svh; min-height: 560px; }
.s-bild .foto { position: absolute; inset: 0; }
.s-bild img { object-position: 58% 62%; }
.s-bu { position: absolute; left: 0; bottom: 0; max-width: calc(100% - 24px); padding: 10px 16px 10px 14px; background: var(--grund); font: 600 .8125rem/1.3 'Special Gothic', system-ui, sans-serif; font-stretch: 75%; letter-spacing: .04em; text-transform: uppercase; }
.s-bu span { color: #4f4e4c; }
.h-split :focus-visible { outline-color: var(--text); }

/* ═════════ 3 · inset-rahmen · Boutique-Hotel (Haus Löffelente, Krakow am See) ═════════ */
.h-inset {
  /* tokens boutique-hotel-gastgeber: token-luxus-weich */
  --kurve: cubic-bezier(0.37, 0, 0.63, 1);
  --z-dauer: 1000ms; --z-stagger: 90ms; --z-start: 300ms;
  --b-dauer: 1200ms; --s-dauer: 1200ms; --clip-start: inset(0 49% 0 49%); --b-scale: 1.08;
  --n-dauer: 600ms; --n-weg: 16px;
  --r: clamp(24px, 2.8vw, 40px);           /* Rand rundum (Terreno: 40 px gemessen) */
  --rahmen: #4D5443;                        /* Markengrund: Schilf, gedämpfter Naturton vom Ufer */
  --creme: #F3EEE7; --text: #3E3A37;
  height: 100svh; max-height: 100vh; min-height: 600px;
  grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr;
  padding: 0 var(--r) var(--r); background: var(--rahmen); color: var(--creme);
  font: 400 1.0625rem/1.6 'Mona Sans', system-ui, sans-serif;
}
.i-kopf { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 24px; min-height: 84px; }
.i-kopf ul { display: flex; flex-wrap: wrap; gap: 4px 24px; }
.i-kopf ul a, .i-rechts a { display: inline-block; padding-block: 12px; font-size: .75rem; font-stretch: 118%; font-weight: 500; letter-spacing: .06em; text-transform: uppercase; background: linear-gradient(currentColor 0 0) left 100% / 0 1px no-repeat; transition: background-size 400ms var(--kurve); }
.i-kopf ul a:hover, .i-rechts a:hover { background-size: 100% 1px; }
.i-marke { font: italic 300 2.1rem/1 'Newsreader', Georgia, serif; letter-spacing: -.02em; font-variation-settings: 'opsz' 72; white-space: nowrap; }
.i-rechts { display: flex; justify-content: flex-end; align-items: center; gap: 24px; }
.i-rechts .i-tel { font-stretch: 100%; letter-spacing: .02em; text-transform: none; font-size: .875rem; font-variant-numeric: tabular-nums; }
.i-rahmen { position: relative; min-height: 0; }
.i-bild { position: absolute; inset: 0; background: #2a1f28; }
.i-bild img { object-position: 50% 58%; }
/* Karte auf Creme, überlappt die untere Rahmenkante: Text steht nie auf der unruhigen Uferzone */
.i-text { position: absolute; left: clamp(20px, 3vw, 48px); bottom: calc(var(--r) * -0.5); width: min(32rem, 52%); padding: clamp(24px, 2.6vw, 38px) clamp(24px, 2.8vw, 40px); background: #FEF2E3; color: var(--text); }
.i-h1 { font: 300 clamp(2.2rem, 1.1rem + 2.6vw, 3.7rem)/1.04 'Newsreader', Georgia, serif; letter-spacing: -.015em; font-variation-settings: 'opsz' 72; }
.i-h1 em { font-style: italic; }
.i-lead { margin-top: 12px; max-width: 40ch; color: var(--text); }
.i-wege { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 26px; margin-top: 22px; }
.i-primaer { display: inline-flex; align-items: center; gap: 14px; min-height: 48px; padding: 0 7px 0 22px; border-radius: 999px; background: #6E5A47; color: var(--creme); font-size: .75rem; font-stretch: 118%; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; transition: background-color 400ms var(--kurve); }
.i-primaer:hover { background: #5d4b3a; }
.i-primaer i { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; background: var(--creme); color: #6E5A47; font-style: normal; overflow: hidden; }
.i-primaer i span { transition: transform 400ms var(--kurve); }
.i-primaer:hover i span { transform: translateX(3px); }
.i-zweit { display: inline-flex; align-items: center; min-height: 48px; font-size: .75rem; font-stretch: 118%; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; background: linear-gradient(currentColor 0 0) left calc(100% - 13px) / 100% 1px no-repeat; transition: background-size 400ms var(--kurve); }
.i-zweit:hover { background-size: 0 1px; background-position: right calc(100% - 13px); }
/* Preiszeile in der unteren Rahmenkante, wie das Schild am Bilderrahmen */
.i-preis { position: absolute; right: 0; bottom: calc(var(--r) * -1); height: var(--r); display: flex; align-items: center; font-size: .75rem; font-stretch: 112%; letter-spacing: .04em; font-variant-numeric: tabular-nums; color: var(--creme); }
.h-inset .i-text :focus-visible { outline-color: var(--text); }
.h-inset :focus-visible { outline-color: var(--creme); }

/* ═════════ 4 · passepartout · Weingut (Ottenbreit, Brauneberg an der Mosel) ═════════ */
.h-passe {
  /* tokens weingut-hofladen-herkunft: token-luxus-weich */
  --kurve: cubic-bezier(0.37, 0, 0.63, 1);
  --z-dauer: 1000ms; --z-stagger: 90ms; --z-start: 260ms;
  --b-dauer: 1200ms; --s-dauer: 1600ms; --clip-start: inset(98% 0 0 0); --b-scale: 1.08;
  --n-dauer: 600ms; --n-weg: 16px;
  --rand: clamp(16px, 4vw, 56px); --spalt: clamp(16px, 2vw, 32px);
  --kalk: #F1ECE2; --loess: #E6DCCB; --schiefer: #2F3236; --text: #22211F; --linie: rgb(241 236 226 / .22);
  min-height: 100svh;
  grid-template-columns: repeat(12, minmax(0, 1fr)); grid-template-rows: auto 1fr; column-gap: var(--spalt);
  padding: 0 var(--rand); background: var(--schiefer); color: var(--kalk);
  font: 400 1.25rem/1.55 'EB Garamond', Georgia, serif;
}
.mono { font-family: 'DM Mono', ui-monospace, monospace; font-weight: 500; font-size: .75rem; line-height: 1.4; letter-spacing: .1em; text-transform: uppercase; }
.p-kopf { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 12px clamp(20px, 3vw, 44px); padding: 24px 0; border-bottom: 1px solid var(--linie); }
.p-marke { display: flex; align-items: baseline; gap: 14px; }
.p-marke b { font: italic 400 1.75rem/1 'EB Garamond', Georgia, serif; letter-spacing: -.01em; }
.p-kopf nav { margin-left: auto; }
.p-kopf ul { display: flex; flex-wrap: wrap; gap: 4px 24px; }
.p-kopf ul a { display: inline-block; padding-block: 12px; background: linear-gradient(currentColor 0 0) left 100% / 0 1px no-repeat; transition: background-size 400ms var(--kurve); }
.p-kopf ul a:hover { background-size: 100% 1px; }
.p-status { display: flex; align-items: center; gap: 10px; }
.p-status i { width: 8px; height: 8px; border-radius: 50%; background: #9db07a; box-shadow: 0 0 0 3px rgb(157 176 122 / .22); }
.p-status[data-zu] i { background: transparent; box-shadow: inset 0 0 0 1.5px var(--kalk); }
.p-text { grid-column: 1 / 7; grid-row: 2; align-self: end; padding: 48px 0 clamp(40px, 9vh, 96px); }
.p-h1 { font: 400 clamp(2.75rem, 1.6rem + 4.2vw, 5.6rem)/1 'EB Garamond', Georgia, serif; letter-spacing: -.015em; }
.p-h1 em { font-style: italic; }
.p-lead { margin-top: 22px; max-width: 34ch; font-feature-settings: 'onum'; color: rgb(241 236 226 / .9); }
.p-wege { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 32px; }
.p-wege a { display: inline-flex; align-items: center; min-height: 48px; padding: 0 22px; font: 500 .875rem/1 'DM Mono', ui-monospace, monospace; letter-spacing: .08em; text-transform: uppercase; }
.p-kauf { background: var(--kalk); color: var(--schiefer); transition: background-color 150ms var(--kurve); }
.p-kauf:hover { background: #fff; }
.p-kontur {
  background:
    linear-gradient(var(--kalk) 0 0) 0 0 / 10px 1px, linear-gradient(var(--kalk) 0 0) 0 0 / 1px 10px,
    linear-gradient(var(--kalk) 0 0) 100% 0 / 10px 1px, linear-gradient(var(--kalk) 0 0) 100% 0 / 1px 10px,
    linear-gradient(var(--kalk) 0 0) 0 100% / 10px 1px, linear-gradient(var(--kalk) 0 0) 0 100% / 1px 10px,
    linear-gradient(var(--kalk) 0 0) 100% 100% / 10px 1px, linear-gradient(var(--kalk) 0 0) 100% 100% / 1px 10px;
  background-repeat: no-repeat; transition: background-size 300ms var(--kurve); }
.p-kontur:hover { background-size: 50% 1px, 1px 50%, 50% 1px, 1px 50%, 50% 1px, 1px 50%, 50% 1px, 1px 50%; }
/* Der Abzug: etwa 30 % der Breite, Hochformat, Kalk-Rand wie Fotopapier, Chip als Bildunterschrift */
.p-abzug { grid-column: 8 / 12; grid-row: 2; align-self: center; justify-self: center; width: min(100%, 25rem); padding: 40px 0 56px; position: relative; }
.p-papier { background: var(--kalk); padding: clamp(8px, .9vw, 14px); }
.p-papier .foto { aspect-ratio: 4 / 5; }
.p-chip { position: absolute; left: 50%; bottom: 56px; transform: translate(-50%, 50%); white-space: nowrap; padding: 9px 14px; background: var(--loess); color: var(--text); border-radius: 999px; }
:root[data-intro='an'] .p-chip { animation-name: auftauchen-chip; }
@keyframes auftauchen-chip { from { opacity: 0; transform: translate(-50%, calc(50% + var(--n-weg))); } }
.h-passe :focus-visible { outline-color: var(--kalk); }

/* ═════════ 5 · bildunterschrift · Architektur (Vehrs Boie, Itzehoe) ═════════ */
.h-fig {
  /* tokens architektur-ruhiges-raster: token-swiss-knackig (Eintritt) */
  --kurve: cubic-bezier(0.25, 1, 0.5, 1);
  --z-dauer: 700ms; --z-stagger: 60ms; --z-start: 350ms;
  --b-dauer: 1000ms; --s-dauer: 0ms; --clip-start: inset(0 0 98% 0); --b-scale: 1;
  --n-dauer: 500ms; --n-weg: 8px;
  --rand: clamp(20px, 4vw, 64px); --spalt: clamp(16px, 2vw, 32px);
  --text: #231F20; --leise: #6B6B6F; --linie: #DCDBDB;
  min-height: 100svh;
  grid-template-columns: repeat(12, minmax(0, 1fr)); grid-template-rows: auto auto auto 1fr; column-gap: var(--spalt);
  padding: 0 var(--rand); background: #fff; color: var(--text);
  font: 400 1.0625rem/1.45 'Hanken Grotesk', system-ui, sans-serif; letter-spacing: -.012em;
}
.a-kopf { grid-column: 1 / -1; display: flex; align-items: center; gap: 24px; padding: 24px 0 clamp(20px, 3vh, 32px); }
.a-marke { font-weight: 500; font-size: 1.0625rem; }
.a-kopf nav { margin-left: auto; }
.a-kopf ul { display: flex; gap: clamp(16px, 2vw, 32px); }
.a-kopf ul a { display: inline-block; padding-block: 10px; background: linear-gradient(currentColor 0 0) left 100% / 0 1px no-repeat; transition: background-size 250ms var(--kurve); }
.a-kopf ul a:hover, .a-kopf ul a[aria-current] { background-size: 100% 1px; }
.a-fig { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: end; }
/* Bild unbeschnitten im Originalformat 3:2, Höhe vom Bildschirm begrenzt */
.a-bild { grid-column: 5 / -1; grid-row: 1; justify-self: end; width: min(100%, calc((100svh - 290px) * 1.5)); min-width: min(100%, 540px); aspect-ratio: 3 / 2; background: #e9e7e3; }
.a-bu { grid-column: 1 / 5; grid-row: 1; display: grid; gap: 8px; padding-bottom: 2px; }
.a-nr { display: flex; align-items: center; gap: 14px; font-size: .75rem; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; font-variant-numeric: tabular-nums; color: var(--text); }
.a-nr::after { content: ''; flex: 1; height: 1px; margin-right: calc(-1 * var(--spalt)); background: var(--text); transform-origin: left; }
:root[data-intro='an'] .h-fig .a-nr::after { animation: linie 700ms var(--kurve) 700ms both; }
.a-titel { font-size: clamp(1.125rem, .9rem + .5vw, 1.375rem); font-weight: 450; line-height: 1.25; letter-spacing: -.015em; }
.a-art { font-size: .8125rem; color: var(--leise); max-width: 30ch; }
.a-text { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 16px 40px; padding: clamp(24px, 4vh, 44px) 0 clamp(28px, 5vh, 56px); }
.a-h1 { font-size: clamp(1.953rem, 1.2rem + 2.4vw, 3.052rem); font-weight: 470; line-height: 1.08; letter-spacing: -.02em; }
.a-link { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; font-weight: 500; white-space: nowrap; }
.a-link svg { width: 22px; height: 12px; transition: transform 250ms var(--kurve); }
.a-link:hover svg { transform: translateX(4px); }
.a-link span { background: linear-gradient(currentColor 0 0) left 100% / 100% 1px no-repeat; padding-bottom: 2px; }
.h-fig :focus-visible { outline-color: #0022FF; }

/* ── Pult ── */
.pult { position: fixed; z-index: 20; left: 50%; bottom: 14px; transform: translateX(-50%); width: max-content; max-width: calc(100% - 24px); display: grid; gap: 8px; padding: 10px 12px; border-radius: 14px; background: rgb(18 18 20 / .88); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); color: #f3f2ee; font: 500 10.5px/1.4 'Geist Mono', ui-monospace, monospace; letter-spacing: .1em; text-transform: uppercase; box-shadow: 0 10px 30px rgb(0 0 0 / .25); }
.pult-zeile { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.pult button { font: inherit; letter-spacing: inherit; text-transform: inherit; color: rgb(243 242 238 / .78); background: none; border: 1px solid rgb(243 242 238 / .2); border-radius: 999px; height: 30px; padding: 0 12px; cursor: pointer; transition: background-color 150ms, color 150ms, border-color 150ms; }
.pult button:hover { color: #fff; border-color: rgb(243 242 238 / .5); }
.pult button[aria-pressed='true'] { background: #f3f2ee; color: #121212; border-color: #f3f2ee; }
.pult button b { font-weight: 500; opacity: .66; }
.pult .nochmal { border-color: transparent; }
.pult-werte { color: rgb(243 242 238 / .74); letter-spacing: .06em; text-transform: none; max-width: 94ch; }
.pult-werte b { color: #fff; font-weight: 500; }
.pult :focus-visible { outline: 2px solid #f3f2ee; outline-offset: 2px; }

/* Vorschau: nur die Bühne */
.vorschau body { overflow: hidden; }
.vorschau .h-randlos, .vorschau .h-inset { height: 100vh; min-height: 0; }

/* ── Breiten ── */
@media (max-width: 1100px) {
  .r-kopf nav, .i-kopf nav, .p-kopf nav { display: none; }
  .r-tel { margin-left: auto; }
  .i-kopf { grid-template-columns: auto 1fr; }
  .i-marke { justify-self: start; }
  .p-status { margin-left: auto; }
  .s-kopf ul { display: none; }
  .r-objekt { display: none; }
  .r-text { grid-column: 1 / 10; }
  .i-text { width: min(35rem, 74%); }
  .i-preis { display: none; }
  .p-abzug { grid-column: 7 / 13; }
  .a-bild { grid-column: 4 / -1; }
  .a-bu { grid-column: 1 / 4; }
}
/* Telefon: Foto 4:5 oben, Satz darunter, Wege in voller Breite; nichts liegt auf dem Foto */
@media (max-width: 760px) {
  .h-randlos, .h-inset { height: auto; max-height: none; min-height: 0; }
  :root[data-v='randlos-unten-links'] .h-randlos { display: block; }
  .h-randlos { padding: 0; background: var(--grund); color: var(--text); }
  .r-bild { position: relative; aspect-ratio: 4 / 5; }
  .r-bild::after { display: none; }
  .r-kopf { position: absolute; top: 0; left: 0; right: 0; padding: 18px var(--rand); color: var(--hell); }
  .r-marke { font-size: 1.35rem; }
  .r-text { padding: 30px var(--rand) 28px; }
  .r-h1 { color: var(--marke); font-size: 2.25rem; }
  .r-lead { color: var(--text); }
  .r-wege { flex-direction: column; }
  .r-wege a { justify-content: center; }
  .r-primaer { background: var(--marke); color: var(--hell); }
  .r-primaer i { background: var(--hell); color: var(--marke); margin-right: 0; }
  .r-objekt { display: block; position: static; padding: 0 var(--rand) 40px; text-align: left; color: var(--leise); }
  .r-objekt b { color: var(--text); }
  .h-randlos :focus-visible { outline-color: var(--marke); }
  .r-kopf :focus-visible { outline-color: var(--hell); }

  :root[data-v='split-randabfallend'] .h-split { display: block; }
  .s-kopf { padding: 18px var(--rand); justify-content: space-between; }
  .s-bild { height: auto; min-height: 0; }
  .s-bild .foto { position: relative; aspect-ratio: 4 / 5; }
  .s-bild img { object-position: 62% 50%; }
  .s-bu { position: static; max-width: none; padding: 10px var(--rand); background: var(--flaeche); }
  .s-text { padding: 30px var(--rand) 24px; }
  .s-wege { flex-direction: column; }
  .s-wege a { justify-content: center; }
  .s-zeit { margin: 0 var(--rand); padding-bottom: 40px; }

  .h-inset { padding: 0 16px 16px; }
  .i-kopf { min-height: 64px; }
  .i-marke { font-size: 1.6rem; }
  .i-rechts .i-tel { display: none; }
  .i-bild { position: relative; aspect-ratio: 4 / 5; }
  .i-text { position: relative; left: auto; bottom: auto; width: auto; margin: -28px 12px 0; padding: 24px 22px 26px; }
  .i-h1 { font-size: 2.3rem; }
  .i-wege { flex-direction: column; align-items: stretch; }
  .i-primaer { justify-content: space-between; }
  .i-zweit { justify-content: center; }
  .i-preis { display: block; position: static; height: auto; padding: 16px 12px 4px; }

  :root[data-v='passepartout'] .h-passe { display: block; }
  .p-kopf { padding: 18px 0; }
  .p-marke { flex-direction: column; gap: 4px; }
  .p-abzug { width: min(84%, 22rem); margin: 0 auto; padding: 28px 0 32px; }
  .p-chip { bottom: 32px; white-space: normal; text-align: center; width: max-content; max-width: 100%; }
  .p-text { padding: 36px 0 48px; }
  .p-wege { flex-direction: column; }
  .p-wege a { justify-content: center; }

  :root[data-v='bildunterschrift'] .h-fig { display: block; }
  .a-kopf ul { gap: 18px; }
  .a-kopf li:nth-child(2) { display: none; }
  .a-fig { display: block; }
  .a-bild { width: 100%; min-width: 0; aspect-ratio: 4 / 5; }
  .a-bu { padding-top: 14px; }
  .a-nr::after { margin-right: 0; }
  .a-text { display: block; padding: 28px 0 48px; }
  .a-link { margin-top: 18px; }
}
@media (max-width: 360px) {
  .r-marke span, .s-marke span { display: none; }
  .i-rechts { gap: 14px; }
  .pult button { padding: 0 9px; }
}
@media (hover: none) {
  /* Kein Hover nötig: der Auftritt läuft beim Laden; Wege reagieren auf Druck */
  .r-wege a:active, .s-wege a:active, .i-primaer:active, .p-wege a:active { transform: scale(.98); }
  .pult button { height: 36px; }
}
@media (forced-colors: active) {
  button, [role=button], [role=tab], [role=switch] { border: 1px solid ButtonText !important; }
  .r-wege a, .s-wege a, .i-primaer, .p-wege a { border: 1px solid LinkText; }
}
</style>
</head>
<body>

<!-- ═════════ 1 · randlos-unten-links ═════════ -->
<section class="hero h-randlos" aria-labelledby="t-randlos">
  <figure class="r-bild foto auf">
    <picture>
      <source media="(max-width: 760px)" srcset="bilder/foto-hero-villa-hoch.webp" width="800" height="1000">
      <img src="bilder/foto-hero-villa.webp" width="1920" height="1080" loading="lazy" decoding="async" data-lcp alt="Flaches Haus aus zwei versetzten hellen Kuben auf einem Rasenhang in der Abenddämmerung, hinter den großen Glasflächen brennt warmes Licht, im Hintergrund Hügel über dem See">
    </picture>
  </figure>
  <header class="r-kopf nach" style="--d: 300ms">
    <a class="r-marke" href="#">Haldenwang <span>Immobilien</span></a>
    <nav aria-label="Hauptnavigation"><ul><li><a href="#">Angebote</a></li><li><a href="#">Verkaufen</a></li><li><a href="#">Vermieten</a></li><li><a href="#">Über uns</a></li></ul></nav>
    <a class="r-tel" href="tel:+497551093774">07551 093774</a>
  </header>
  <div class="r-text">
    <h1 class="r-h1" id="t-randlos"><span class="z"><span style="--i: 0">Häuser und Wohnungen</span></span><span class="z"><span style="--i: 1">am Überlinger See.</span></span></h1>
    <p class="r-lead nach" style="--d: 520ms">Verkauf und Vermietung zwischen Sipplingen und Meersburg. Ihre Immobilie schätzen wir vor Ort ein.</p>
    <div class="r-wege nach" style="--d: 620ms">
      <a class="r-primaer" href="#">Angebote ansehen <i aria-hidden="true">→</i></a>
      <a class="r-zweit" href="#">Was ist meine Immobilie wert?</a>
    </div>
  </div>
  <p class="r-objekt nach" style="--d: 720ms"><b>Haus am Hang, Überlingen-Hödingen</b>7 Zimmer · 248 m² Wohnfläche</p>
</section>

<!-- ═════════ 2 · split-randabfallend ═════════ -->
<section class="hero h-split" aria-labelledby="t-split">
  <header class="s-kopf nach" style="--d: 120ms">
    <a class="s-marke" href="#"><b>Stellmacher</b><span>Haustechnik · Höxter</span></a>
    <nav aria-label="Hauptnavigation"><ul><li><a href="#">Wärmepumpe</a></li><li><a href="#">Heizung</a></li><li><a href="#">Bad</a></li><li><a href="#">Betrieb</a></li><li><a href="#">Kontakt</a></li></ul></nav>
  </header>
  <figure class="s-bild">
    <div class="foto auf">
      <picture>
        <img src="bilder/handwerk-waermepumpe.webp" width="1200" height="800" loading="lazy" decoding="async" data-lcp alt="Weiße Luft-Wasser-Wärmepumpe auf einem Betonsockel vor einer hell verputzten Hauswand, davor ein Kiesstreifen und Rasen">
      </picture>
    </div>
    <figcaption class="s-bu nach" style="--d: 560ms">Luft-Wasser-Wärmepumpe <span>· Einfamilienhaus in Brakel · 2025</span></figcaption>
  </figure>
  <div class="s-text">
    <h1 class="s-h1" id="t-split"><span class="z"><span style="--i: 0">Wärmepumpen</span></span><span class="z"><span style="--i: 1">und Heizungen</span></span><span class="z"><span style="--i: 2">in Höxter.</span></span></h1>
    <p class="s-region nach" style="--d: 260ms">Planung, Einbau und Wartung für Höxter, Brakel und Beverungen.</p>
    <div class="s-wege nach" style="--d: 320ms">
      <a class="s-anfrage" href="#">Anfrage stellen</a>
      <a class="s-anrufen" href="tel:+495271039412"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M5 3h4l2 5-2.5 1.5a11 11 0 0 0 6 6L16 13l5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 5a2 2 0 0 1 2-2"/></svg>05271 039412</a>
    </div>
  </div>
  <dl class="s-zeit nach" style="--d: 380ms"><div><dt>Büro</dt><dd>Mo bis Fr 7 bis 17 Uhr</dd></div><div><dt>Einsatzgebiet</dt><dd>Kreis Höxter und Holzminden</dd></div></dl>
</section>

<!-- ═════════ 3 · inset-rahmen ═════════ -->
<section class="hero h-inset" aria-labelledby="t-inset">
  <header class="i-kopf nach" style="--d: 100ms">
    <nav aria-label="Hauptnavigation"><ul><li><a href="#">Zimmer</a></li><li><a href="#">Sauna &amp; See</a></li><li><a href="#">Stube</a></li><li><a href="#">Anreise</a></li></ul></nav>
    <a class="i-marke" href="#">Haus Löffelente</a>
    <div class="i-rechts"><a class="i-tel" href="tel:+4938457048120">038457 048120</a><a href="#" lang="en" hreflang="en">EN</a></div>
  </header>
  <div class="i-rahmen">
    <figure class="i-bild foto auf">
      <picture>
        <source media="(max-width: 760px)" srcset="bilder/hotel-haus-am-see-hoch.webp" width="900" height="1200">
        <img src="bilder/hotel-haus-am-see.webp" width="1920" height="1200" loading="lazy" decoding="async" data-lcp alt="Backsteinhaus mit erleuchteten Fenstern am Seeufer in der Abenddämmerung, daneben Bäume und eine kleine Holzsauna, alles spiegelt sich im stillen Wasser">
      </picture>
    </figure>
    <div class="i-text nach" style="--d: 120ms">
      <h1 class="i-h1" id="t-inset"><span class="z"><span style="--i: 0">Elf Zimmer und ein Steg</span></span><span class="z"><span style="--i: 1">am <em>Krakower See.</em></span></span></h1>
      <p class="i-lead nach" style="--d: 700ms">Backsteinhaus von 1911, Sauna am Wasser, Frühstück bis elf Uhr.</p>
      <div class="i-wege nach" style="--d: 820ms">
        <a class="i-primaer" href="#">Verfügbarkeit prüfen <i aria-hidden="true"><span>→</span></i></a>
        <a class="i-zweit" href="#">Zimmer und Preise</a>
      </div>
    </div>
    <p class="i-preis nach" style="--d: 940ms">Doppelzimmer ab 128 € pro Nacht mit Frühstück, November bis März</p>
  </div>
</section>

<!-- ═════════ 4 · passepartout ═════════ -->
<section class="hero h-passe" aria-labelledby="t-passe">
  <header class="p-kopf nach" style="--d: 100ms">
    <a class="p-marke" href="#"><b>Ottenbreit</b><span class="mono">Weingut · Brauneberg</span></a>
    <nav aria-label="Hauptnavigation"><ul class="mono"><li><a href="#">Weine</a></li><li><a href="#">Lagen</a></li><li><a href="#">Hofladen</a></li><li><a href="#">Weinprobe</a></li><li><a href="#">Zimmer</a></li></ul></nav>
    <p class="p-status mono" data-hofladen title="Beispielzeiten: Mo bis Fr 10 bis 18 Uhr, Sa 10 bis 16 Uhr"><i aria-hidden="true"></i><span>Hofladen Mo bis Fr 10–18, Sa 10–16 Uhr</span></p>
  </header>
  <figure class="p-abzug">
    <div class="p-papier auf">
      <div class="foto">
        <img src="bilder/foto-hero-weinberg-hoch.webp" width="800" height="1000" loading="lazy" decoding="async" data-lcp alt="Steiler Weinberg im Herbst mit gelb und rostrot gefärbten Rebzeilen in der Abendsonne, oben ein kleines Weinbergshäuschen aus Bruchstein mit Schieferdach und ein Walnussbaum vor dem Waldsaum">
      </div>
    </div>
    <figcaption class="p-chip mono nach" style="--d: 900ms">Kehrberg · Schiefer · Süd · 2025</figcaption>
  </figure>
  <div class="p-text">
    <h1 class="p-h1" id="t-passe"><span class="z"><span style="--i: 0">Riesling vom</span></span><span class="z"><span style="--i: 1"><em>Kehrberg</em> über</span></span><span class="z"><span style="--i: 2">der Mosel.</span></span></h1>
    <p class="p-lead nach" style="--d: 640ms">Vier Hektar Steillage in Brauneberg, von Hand gelesen und im Gewölbekeller ausgebaut.</p>
    <div class="p-wege nach" style="--d: 760ms">
      <a class="p-kauf" href="#">Weine entdecken</a>
      <a class="p-kontur" href="#">Weinprobe &amp; Hoffest</a>
    </div>
  </div>
</section>

<!-- ═════════ 5 · bildunterschrift ═════════ -->
<section class="hero h-fig" aria-labelledby="t-fig">
  <header class="a-kopf nach" style="--d: 100ms">
    <a class="a-marke" href="#">Vehrs Boie Architekten</a>
    <nav aria-label="Hauptnavigation"><ul><li><a href="#">Projekte</a></li><li><a href="#">Büro</a></li><li><a href="#">Kontakt</a></li></ul></nav>
  </header>
  <figure class="a-fig">
    <div class="a-bild foto auf">
      <picture>
        <source media="(max-width: 760px)" srcset="bilder/beton-treppe-hoch.jpg" width="800" height="1000">
        <img src="bilder/beton-treppe.jpg" width="1200" height="800" loading="lazy" decoding="async" data-lcp alt="Kragtreppe aus Sichtbeton an einer Wand mit Brettschalung, schräges Streiflicht, oben Schatten von Blättern an der Wand">
      </picture>
    </div>
    <figcaption class="a-bu">
      <span class="a-nr nach" style="--d: 620ms">Fig. 1 · Itzehoe · 2024</span>
      <span class="a-titel z"><span style="--i: 3">Treppenhaus im Störspeicher</span></span>
      <span class="a-art nach" style="--d: 900ms">Umbau eines Getreidespeichers zu Wohnungen und Ateliers</span>
    </figcaption>
  </figure>
  <div class="a-text">
    <h1 class="a-h1" id="t-fig"><span class="z"><span style="--i: 0">Wir planen Schulen, Wohnhäuser</span></span><span class="z"><span style="--i: 1">und Räume für Kultur im Norden.</span></span></h1>
    <a class="a-link nach" style="--d: 640ms" href="#"><span>Projekte</span><svg viewBox="0 0 22 12" fill="none" stroke="currentColor" stroke-width="1.4" aria-hidden="true"><path d="M0 6h20M15 1l5 5-5 5"/></svg></a>
  </div>
</section>

<script>/* LCP: Auf der echten Seite gibt es nur einen Hero, sein Bild steht ohne loading="lazy" und mit fetchpriority="high".
   Hier liegen fünf Bühnen in einer Datei: Das Bild der gewählten wird sofort geladen, die übrigen erst beim Umschalten. */
(function () {
  var img = document.querySelector('[data-v="' + document.documentElement.getAttribute('data-v') + '"] [data-lcp]') || null;
  var sel = { 'randlos-unten-links': '.h-randlos', 'split-randabfallend': '.h-split', 'inset-rahmen': '.h-inset', passepartout: '.h-passe', bildunterschrift: '.h-fig' };
  img = document.querySelector(sel[document.documentElement.getAttribute('data-v')] + ' [data-lcp]');
  if (img) { img.loading = 'eager'; img.fetchPriority = 'high'; }
})();</script>

<aside class="pult" aria-label="Demo-Steuerung">
  <div class="pult-zeile" role="group" aria-label="Variante">
    <button type="button" data-wahl="randlos-unten-links" aria-pressed="false">Randlos <b>Immobilien</b></button>
    <button type="button" data-wahl="split-randabfallend" aria-pressed="false">Split <b>Handwerk</b></button>
    <button type="button" data-wahl="inset-rahmen" aria-pressed="false">Rahmen <b>Hotel</b></button>
    <button type="button" data-wahl="passepartout" aria-pressed="false">Passepartout <b>Weingut</b></button>
    <button type="button" data-wahl="bildunterschrift" aria-pressed="false">Bildunterschrift <b>Architektur</b></button>
    <button type="button" class="nochmal" data-nochmal aria-label="Auftritt erneut abspielen">↻ Auftritt</button>
  </div>
  <p class="pult-werte" data-werte aria-live="polite"></p>
</aside>

<script>
(() => {
  const html = document.documentElement;
  const reduziert = () => html.classList.contains('reduziert');
  const SEL = { 'randlos-unten-links': '.h-randlos', 'split-randabfallend': '.h-split', 'inset-rahmen': '.h-inset', passepartout: '.h-passe', bildunterschrift: '.h-fig' };
  // Gesamtdauer des Auftritts je Variante in ms (passend zu den CSS-Variablen)
  const DAUER = { 'randlos-unten-links': 1320, 'split-randabfallend': 800, 'inset-rahmen': 1540, passepartout: 1600, bildunterschrift: 1400 };
  const WERTE = {
    'randlos-unten-links': 'Immobilien · Vollbild <b>100svh</b>, Text Spalte <b>1–6</b>, Abdunklung nur unten <b>36 %</b> · Bild <b>clip-path inset(98% 0 0 0) → 0</b>, <b>scale 1,1 → 1</b>, <b>1.100 ms</b> · Zeilen <b>900 ms</b> / <b>80 ms</b> · <b>cubic-bezier(0.16, 1, 0.3, 1)</b>',
    'split-randabfallend': 'Handwerk · Text Spalte <b>1–5</b>, Foto ab Spalte <b>6</b> bis an den Rand (<b>≈ 40/60</b>) · Bild <b>clip-path inset(0 0 0 98%) → 0</b>, <b>700 ms</b>, ohne Zoom · Zeilen <b>400 ms</b> / <b>60 ms</b> · Rest <b>8 px</b>, <b>240 ms</b> · <b>cubic-bezier(0, 0, 0.38, 0.9)</b>',
    'inset-rahmen': 'Hotel · Rand <b>clamp(24px, 2,8vw, 40px)</b> auf <b>#4D5443</b>, Radius <b>0</b> · Bild <b>clip-path inset(0 49% 0 49%) → 0</b>, <b>scale 1,08 → 1</b>, <b>1.200 ms</b> · Zeilen <b>1.000 ms</b> / <b>90 ms</b> · <b>cubic-bezier(0.37, 0, 0.63, 1)</b>',
    passepartout: 'Weingut · Abzug <b>4 von 12 Spalten</b> (≈ 30 %), <b>4:5</b>, Kalk-Rand <b>clamp(8px, 0,9vw, 14px)</b>, Chip <b>DM Mono</b> · Bild <b>clip-path inset(98% 0 0 0) → 0</b>, <b>1.200 ms</b>, <b>scale 1,08 → 1</b>, <b>1.600 ms</b> · <b>cubic-bezier(0.37, 0, 0.63, 1)</b>',
    bildunterschrift: 'Architektur · Bild <b>3:2</b> unbeschnitten, Spalte <b>5–12</b>, <b>figcaption</b> Spalte <b>1–4</b> · Bild <b>clip-path inset(0 0 98% 0) → 0</b>, <b>1.000 ms</b> · Haarlinie <b>scaleX 0 → 1</b>, <b>700 ms</b> · Zeilen <b>700 ms</b> / <b>60 ms</b> · <b>cubic-bezier(0.25, 1, 0.5, 1)</b>'
  };
  const knoepfe = [...document.querySelectorAll('[data-wahl]')];
  const werte = document.querySelector('[data-werte]');
  let v = html.getAttribute('data-v');

  function zeigeWerte() {
    werte.innerHTML = reduziert()
      ? '<b>Reduzierte Bewegung:</b> alles steht ab dem ersten Frame · ' + WERTE[v]
      : WERTE[v] + ' · Auftritt <b>nur beim ersten Aufruf</b> je Sitzung';
  }
  // Auftritt neu starten: Attribut kurz aus, Layout erzwingen, wieder an
  function abspielen() {
    if (reduziert()) return;
    html.setAttribute('data-intro', 'aus');
    void document.body.offsetWidth;
    html.setAttribute('data-intro', 'an');
  }
  function setzen(neu) {
    v = neu;
    html.setAttribute('data-v', v);
    try { sessionStorage.setItem('foto-hero:' + v, '1'); } catch (e) {}
    const img = document.querySelector(SEL[v] + ' [data-lcp]');
    if (img) { img.loading = 'eager'; img.fetchPriority = 'high'; }
    knoepfe.forEach(b => b.setAttribute('aria-pressed', String(b.dataset.wahl === v)));
    const q = new URLSearchParams(location.search); q.set('v', v);
    history.replaceState(null, '', location.pathname + '?' + q.toString() + location.hash);
    zeigeWerte();
  }
  knoepfe.forEach(b => b.addEventListener('click', () => { pause(); setzen(b.dataset.wahl); abspielen(); }));
  document.querySelector('[data-nochmal]').addEventListener('click', () => { pause(); abspielen(); });

  // Hofladen-Status aus festen Beispielzeiten (Europe/Berlin), ohne Feiertage
  (function hofladen() {
    const el = document.querySelector('[data-hofladen]'); if (!el) return;
    const ZEITEN = { 1: [10, 18], 2: [10, 18], 3: [10, 18], 4: [10, 18], 5: [10, 18], 6: [10, 16] };
    const TAGE = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
    const teile = new Intl.DateTimeFormat('de-DE', { timeZone: 'Europe/Berlin', weekday: 'short', hour: 'numeric', minute: 'numeric', hourCycle: 'h23' }).formatToParts(new Date());
    const wt = { So: 0, Mo: 1, Di: 2, Mi: 3, Do: 4, Fr: 5, Sa: 6 }[teile.find(t => t.type === 'weekday').value.slice(0, 2)];
    const std = +teile.find(t => t.type === 'hour').value + (+teile.find(t => t.type === 'minute').value) / 60;
    const heute = ZEITEN[wt];
    let text;
    if (heute && std >= heute[0] && std < heute[1]) { text = 'Hofladen offen bis ' + heute[1] + ' Uhr'; el.removeAttribute('data-zu'); }
    else {
      el.setAttribute('data-zu', '');
      if (heute && std < heute[0]) text = 'Hofladen öffnet um ' + heute[0] + ' Uhr';
      else { let n = 1; while (!ZEITEN[(wt + n) % 7]) n++; const t = (wt + n) % 7; text = 'Hofladen öffnet ' + (n === 1 ? 'morgen' : TAGE[t]) + ' um ' + ZEITEN[t][0] + ' Uhr'; }
    }
    el.querySelector('span').textContent = text;
  })();

  // Vorführung: der Auftritt der gewählten Variante in Schleife
  let schleife = null;
  function vorfuehren() {
    pause();
    abspielen();
    schleife = setTimeout(vorfuehren, DAUER[v] + 2600);
  }
  function pause() { clearTimeout(schleife); schleife = null; }
  function weiter() { if (!schleife) vorfuehren(); }
  function neustart() { pause(); abspielen(); }

  knoepfe.forEach(b => b.setAttribute('aria-pressed', String(b.dataset.wahl === v)));
  zeigeWerte();

})();
</script>
</body>
</html>