Zum Inhalt
← Navigation

Seitenrand- und Vier-Ecken-Navigation

Logo, Menü, Legende und Zähler stehen in den vier Ecken eines Architekturbüros, invertieren sich per difference über hellen und dunklen Tafeln und wechseln per View Transition zu drei Ecken oder zur Seitenleiste.

Die Navigation verteilt sich auf die Ränder statt auf eine Kopfleiste. Typisch: Logo oben links, Menü oben rechts, Projekt oder Kontakt unten links, Zähler oder Uhr unten rechts, alle fix positioniert. Alternativ trägt eine schmale Leiste links gedrehte Labels. Die Mitte bleibt frei für Bild und Inhalt, die Ränder bilden einen ruhigen Rahmen. Oft hält mix-blend-mode: difference die Ecktexte über hellen und dunklen Flächen lesbar.

Die Ecken rahmen den Inhalt wie ein Plakat oder eine Ausstellungswand. Das wirkt kuratiert und schweizerisch-editorial. Der Inhalt bekommt die ganze Fläche, die Navigation bleibt trotzdem immer erreichbar.

Wann einsetzen

Portfolios, Galerien, Fotografie, Architektur und immersive WebGL-Seiten. Überall, wo wenige Bereiche auf große Bilder treffen.

Wann nicht

Informationsreiche Seiten mit vielen Menüpunkten. Mobile-first-Projekte, die keinen eigenen Umbau für kleine Bildschirme bekommen.

Varianten

  • Vier Ecken: Logo, Menü, Legende, Zähler oder Uhr (Playermaker, Alpha Blue Ocean laut Speckyboy)
  • Drei Ecken, minimal: Logo, Menü-Knopf, Legende (Oropress)
  • Vertikale Seitenleiste mit gedrehten Labels
  • Zweigeteilte Seitenleiste: Bereiche oben, Steuerungen unten (Paul Hanaoka laut Navbar Gallery)

Umsetzung

Vier fixe Container mit 16 bis 32 px Randabstand oder ein fixes Grid über dem Viewport: pointer-events: none auf dem Grid, pointer-events: auto auf den Links. Vertikale Labels per writing-mode: vertical-rl, für Lesart von unten nach oben zusätzlich transform: rotate(180deg). Nicht nur mit rotate drehen, sonst stimmen Layout und Textauswahl nicht. Lesbarkeit über wechselnden Flächen: color: white mit mix-blend-mode: difference. Oder die Farbe je Ecke aus dem data-theme der Sektion darunter setzen. Wechselnde Labels wie das aktuelle Projekt kurz aus- und wieder einblenden; Goodgrowth nutzt dafür 250 ms ease. Fallstrick: Fixe Ecken verdecken auf kleinen Screens Inhalt. Mobil zu einer Leiste zusammenfassen.

Robust umsetzen

Telefon. Ecken zu einer Kopfzeile mit Logo und Menü-Knopf zusammenfassen, das Menü öffnet als Overlay. Untere Ecken und vertikale Labels entfallen. Ihre Angaben wandern als Bildunterschrift in den Inhalt.

Ohne Bewegung. Das Muster selbst ist statisch. Wechselnde Labels, Menü-Overlay und Layoutwechsel ohne Gleiten zeigen: kurz überblenden oder sofort tauschen, View Transitions abschalten.

Barrierefrei. DOM-Reihenfolge logisch halten (Logo, Navigation, Inhalt, Kontakt), unabhängig von der Position am Rand. Landmarken wie <header> und <nav> trotz Verteilung setzen. mix-blend-mode macht Kontraste unvorhersehbar: Über mittleren Grautönen wird der Text selbst grau. Solche Flächen testen oder auf Farbe je Sektion ausweichen. Den aktuellen Bereich mit aria-current markieren, eine wechselnde Legende mit aria-live="polite" ansagen. Menü-Overlay per Escape schließen und den Fokus zurückgeben.

Code

<!DOCTYPE html>
<!--
  Seitenrand- und Vier-Ecken-Navigation
  Fundus · Navigation · https://cecodesign.de/lab/fundus/navigation/seitenrand-und-ecken-navigation/
  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>Seitenrand- und Vier-Ecken-Navigation · 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: '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; }
@font-face { font-family: 'Hanken Grotesk'; src: url('https://cdn.jsdelivr.net/fontsource/fonts/hanken-grotesk:vf@latest/latin-wght-italic.woff2') format('woff2-variations'); font-weight: 100 900; font-style: italic; font-display: swap; }
@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; }

/* Welt: Rezept „Architektur: ruhiges Raster“ – Rautenberg Aydin Architekten, Wiesbaden */
:root {
  --weiss: #ffffff; --flaeche: #e1e3e3; --text: #231f20; --meta: #626266; --dunkel: #1f2323; --hell: #f4f4f2;
  --fokus: #0022ff;
  --rand: 28px;                                  /* Randabstand der Ecken (gemessen: bottom 28px) */
  --leiste: 88px;                                /* Variante Seitenleiste: Breite bis zur Linie */
  --ecke-kurve: cubic-bezier(0.25, 0.1, 0.25, 1); /* ease, 250 ms: Ecken blenden aus (gemessen) */
  --kurve: cubic-bezier(0.1, 0.6, 0.4, 1);       /* Default-Token des Rezepts: Schließen, Gleiten */
  --oeffnen: cubic-bezier(0.1, 0.9, 0.3, 1);     /* Ausklang-Token: Öffnen, Einblenden */
}
* { box-sizing: border-box; margin: 0; }
html { background: var(--weiss); color: var(--text); font-family: 'Hanken Grotesk', system-ui, sans-serif; font-weight: 400; letter-spacing: -0.012em; -webkit-font-smoothing: antialiased; }
body { height: 100svh; display: flex; flex-direction: column; overflow: hidden; }
em { font-style: italic; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--fokus); outline-offset: 3px; }
.mono { font: 500 11px/1.3 'Geist Mono', ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; }

/* ---------- Bühne: Inhalt rollt, die Ecken stehen ---------- */
.buehne { position: relative; flex: 1; min-height: 0; isolation: isolate; overflow: hidden; background: var(--weiss); }
.rollbahn { position: absolute; inset: 0; overflow-y: auto; overflow-x: hidden; scrollbar-width: none; }
.rollbahn::-webkit-scrollbar { display: none; }
.tafel { position: relative; min-height: 100%; }

/* ---------- Die Ecken ---------- */
.ecke {
  position: absolute; z-index: 2;
  font: 450 1rem/1.2 'Hanken Grotesk', system-ui, sans-serif; letter-spacing: .06em; text-transform: uppercase;
  color: #fff; mix-blend-mode: difference;   /* weiß minus Grund: über Weiß schwarz, über Dunkel hell */
  transition: opacity 250ms var(--ecke-kurve), color 125ms var(--kurve);
}
.ecke a { text-decoration: none; }
.ecke--ol { top: var(--rand); left: var(--rand); }
.ecke--or { top: var(--rand); right: var(--rand); }
.ecke--ul { bottom: var(--rand); left: var(--rand); }
.ecke--ur { bottom: var(--rand); right: var(--rand); text-align: right; }

.marke { display: block; font-size: 1.25rem; font-weight: 500; letter-spacing: -0.02em; line-height: 1.08; text-transform: none; }
.marke em { display: block; font-weight: 400; }
.navi ul { display: flex; gap: 1.25em; list-style: none; padding: 0; }
.navi a, .menueknopf { text-decoration: underline; text-decoration-thickness: .08em; text-underline-offset: .35ex; text-decoration-color: transparent; transition: text-decoration-color 125ms var(--kurve); }
.navi a:hover, .navi a[aria-current], .menueknopf:hover { text-decoration-color: currentColor; }
.menueknopf { background: none; border: 0; padding: 0; cursor: pointer; display: none; }
.legende { white-space: nowrap; }
.legende.aus { opacity: 0; }
.zaehler { display: grid; gap: 4px; font-variant-numeric: tabular-nums; }
.zaehler span + span { opacity: .62; }
.linie { position: absolute; z-index: 2; top: 0; bottom: 0; left: var(--leiste); width: 1px; background: #fff; mix-blend-mode: difference; display: none; }

/* Variante: drei Ecken – Menü statt Liste, kein Zähler */
[data-variante='drei'] .navi, [data-variante='drei'] .zaehler { display: none; }
[data-variante='drei'] .menueknopf { display: block; }

/* Variante: Seitenleiste – gedrehte Labels per writing-mode, Bereiche oben, Liste unten */
[data-variante='seite'] .marke { writing-mode: vertical-rl; transform: rotate(180deg); }
[data-variante='seite'] .navi { top: auto; bottom: var(--rand); left: var(--rand); right: auto; }
[data-variante='seite'] .navi ul { writing-mode: vertical-rl; transform: rotate(180deg); gap: 1.5em; }
[data-variante='seite'] .legende { left: auto; right: var(--rand); }
[data-variante='seite'] .zaehler { bottom: auto; top: var(--rand); }
[data-variante='seite'] .linie { display: block; }

/* Lesbarkeit „Sektion“: keine Mischung, Farbe je Untergrund (data-ton, per JS je Ecke ermittelt).
   Während eines Variantenwechsels (.vt) gilt dasselbe, weil Schnappschüsse nicht mischen. */
:is([data-modus='sektion'], .vt) :is(.ecke, .linie) { mix-blend-mode: normal; }
:is([data-modus='sektion'], .vt) .ecke[data-ton='hell'] { color: var(--text); }
:is([data-modus='sektion'], .vt) .ecke[data-ton='dunkel'] { color: var(--hell); }
:is([data-modus='sektion'], .vt) .linie { background: rgba(118, 118, 122, .5); }

/* Variantenwechsel als same-document View Transition */
.vt .marke { view-transition-name: marke; }
.vt[data-variante='seite'] .marke { view-transition-name: marke-hoch; }
.vt .navi { view-transition-name: navi; }
.vt[data-variante='seite'] .navi { view-transition-name: navi-hoch; }
.vt .legende { view-transition-name: legende; }
.vt .zaehler { view-transition-name: zaehler; }
.vt .menueknopf { view-transition-name: menueknopf; }
.vt .linie { view-transition-name: linie; }
::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation-duration: 500ms; animation-timing-function: var(--kurve); }
::view-transition-old(root), ::view-transition-new(root) { animation: none; }

/* ---------- Menü-Overlay (Drei Ecken, Telefon) ---------- */
.menue {
  position: absolute; inset: 0; z-index: 3; background: var(--weiss); color: var(--text);
  display: grid; grid-template-rows: 1fr auto; padding: calc(var(--rand) + 96px) var(--rand) var(--rand) clamp(var(--rand), 22vw, 320px);
  opacity: 0; visibility: hidden;
  transition: opacity 250ms var(--kurve), visibility 0s linear 250ms;
}
.menue ol { list-style: none; padding: 0; align-self: center; display: grid; gap: .1em; font-size: clamp(1.953rem, 1.2rem + 2.4vw, 3.052rem); font-weight: 450; letter-spacing: -0.02em; line-height: 1.15;
  translate: 0 16px; transition: translate 250ms var(--kurve); }
.menue a { display: inline-flex; align-items: baseline; gap: .6em; text-decoration: none; }
.menue a .nr { font-size: .8rem; letter-spacing: .06em; color: var(--meta); width: 2.2em; }
.menue a sup { font-size: .8rem; letter-spacing: 0; color: var(--meta); vertical-align: super; }
.menue a:hover em, .menue a:focus-visible em { text-decoration: underline; text-decoration-thickness: .06em; text-underline-offset: .2em; }
.menue a em { font-style: normal; }
.menue__fuss { display: flex; flex-wrap: wrap; gap: 6px 40px; font-size: .8rem; color: var(--meta); }
.offen .menue { opacity: 1; visibility: visible; transition: opacity 500ms var(--oeffnen), visibility 0s; }
.offen .menue ol { translate: 0 0; transition: translate 500ms var(--oeffnen); }
.offen :is(.navi, .legende, .zaehler, .linie) { opacity: 0; pointer-events: none; }  /* gemessen: 250 ms ease */
.offen .ecke--ol, .offen .menueknopf { z-index: 4; }

/* ---------- Tafeln: die Website darunter ---------- */
.bild { display: block; width: 100%; height: 100%; }
.meta { font-size: .8rem; color: var(--meta); letter-spacing: 0; }
.bu { display: none; }

/* 1 Haus am Neroberg: kleines Bild auf viel Weiß */
.t1 { background: var(--weiss); display: grid; place-items: center; padding: 96px var(--rand); }
.t1 figure { width: min(46vw, 640px, calc((100svh - 260px) * 4 / 3)); }
.t1 .rahmenbild { aspect-ratio: 4 / 3; background: var(--flaeche); overflow: hidden; }
.t1 figcaption { display: flex; justify-content: space-between; gap: 16px; padding-top: 12px; font-size: .8rem; }
.t1 figcaption span:last-child { color: var(--meta); }

/* 2 Kolonnadenfoyer: Vollbild, dunkel */
.t2 { background: #121617; }
.t2 .bild { position: absolute; inset: 0; }

/* 3 Grundschule: Plan auf Hellgrau */
.t3 { background: var(--flaeche); display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); align-items: center; gap: clamp(28px, 4vw, 64px); padding: 112px clamp(28px, 6vw, 96px) 112px clamp(112px, 9vw, 160px); }
.t3 svg { width: 100%; height: auto; max-height: calc(100svh - 280px); }
.text h2 { font-size: clamp(1.563rem, 1rem + 1.6vw, 2.441rem); font-weight: 450; letter-spacing: -0.02em; line-height: 1.1; text-wrap: balance; }
.text h2 em { font-weight: 400; }
.text p { font-size: 1.0625rem; line-height: 1.45; max-width: 50ch; text-wrap: pretty; }
.text > * + * { margin-top: 18px; }
.text dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 20px; font-size: .8rem; padding-top: 6px; }
.text dt { color: var(--meta); }

/* 4 Kelterhaus: halb Bild, halb Text */
.t4 { display: grid; grid-template-columns: 1fr 1fr; background: var(--weiss); }
.t4 .links { position: relative; background: #2b2f2c; }
.t4 .links .bild { position: absolute; inset: 0; }
.t4 .text { align-self: center; padding: 112px clamp(28px, 6vw, 96px); }

/* 5 Büro: dunkle Visitenkarte */
.t5 { background: var(--dunkel); color: var(--hell); display: grid; align-content: space-between; gap: 56px; padding: 132px clamp(28px, 6vw, 96px) 120px clamp(112px, 9vw, 160px); }
.t5 h2 { font-size: clamp(1.953rem, 1.2rem + 2.4vw, 3.052rem); font-weight: 450; letter-spacing: -0.02em; line-height: 1.08; max-width: 18ch; text-wrap: balance; }
.t5 h2 em { font-weight: 400; color: #a9abab; }
.karte { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; font-size: .9375rem; line-height: 1.5; max-width: 980px; }
.karte h3 { font-size: .8rem; font-weight: 400; color: #8f9393; margin-bottom: 8px; letter-spacing: 0; }
.karte a { text-decoration: none; }
.karte a:hover { text-decoration: underline; text-underline-offset: .35ex; }

/* ---------- Pult: Varianten und Werte (gehört nicht zum Muster) ---------- */
.pult { flex: none; display: flex; align-items: center; gap: 10px 22px; padding: 8px 16px; background: var(--weiss); border-top: 1px solid var(--flaeche); color: var(--meta); }
.pult__gruppe { display: flex; gap: 2px; }
.pult button { flex: none; white-space: nowrap; font: inherit; letter-spacing: inherit; text-transform: inherit; color: var(--meta); background: none; border: 0; border-radius: 999px; height: 28px; padding: 0 11px; cursor: pointer; transition: background-color 150ms linear, color 150ms linear; }
.pult button:hover { color: var(--text); }
.pult button[aria-pressed='true'] { background: var(--flaeche); color: var(--text); }
.pult__trenner { width: 1px; height: 18px; background: var(--flaeche); }
.pult__werte { margin-left: auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* Vorschau: nur die Bühne */
.vorschau body { overflow: hidden; }
.vorschau .pult { display: none; }

/* Reduzierte Bewegung: kein Gleiten, keine View Transition, nur kurzes Überblenden */
.reduziert .ecke { transition: opacity 150ms linear; }
.reduziert .menue, .reduziert .offen .menue { transition: opacity 150ms linear, visibility 0s linear 150ms; }
.reduziert .offen .menue { transition: opacity 150ms linear, visibility 0s; }
.reduziert .menue ol, .reduziert .offen .menue ol { translate: none; transition: none; }

/* Touch: kein Hover-Unterstrich, Tippen genügt */
@media (hover: none) {
  .navi a:hover:not([aria-current]), .menueknopf:hover { text-decoration-color: transparent; }
}

@media (max-width: 1080px) {
  .t3 { grid-template-columns: 1fr; padding-top: 104px; }
  .t3 svg { max-height: 46svh; }
  .t3 .text { max-width: 54ch; }
}

/* Telefon: Ecken fassen sich zu Kopfzeile + Menü zusammen, Labels unten wandern in den Inhalt */
@media (max-width: 720px) {
  :root { --rand: 20px; }
  .buehne .navi, .buehne .legende, .buehne .zaehler, .buehne .linie { display: none; }
  .buehne .menueknopf { display: block; }
  .buehne .marke { writing-mode: horizontal-tb; transform: none; font-size: 1.0625rem; }
  .menue { padding: 120px var(--rand) var(--rand); }
  .bu { display: block; position: absolute; left: var(--rand); bottom: var(--rand); font-size: .8rem; color: var(--hell); }
  .t1 { padding: 112px var(--rand) 72px; }
  .t1 figure { width: 100%; }
  .t3 { padding: 104px var(--rand) 64px; gap: 28px; }
  .t3 svg { max-height: none; }
  .t4 { grid-template-columns: 1fr; }
  .t4 .links { min-height: 60svh; }
  .t4 .text { padding: 48px var(--rand) 64px; }
  .t5 { padding: 112px var(--rand) 56px; gap: 40px; }
  .karte { grid-template-columns: 1fr; gap: 22px; }
  .pult { flex-wrap: wrap; padding: 8px 10px; gap: 6px 12px; }
  .pult__gruppe { flex-wrap: wrap; min-width: 0; }
  .pult__trenner { display: none; }
  .pult__werte { flex-basis: 100%; margin-left: 4px; font-size: 10px; letter-spacing: .1em; white-space: normal; }
  .pult button { padding: 0 9px; }
}
@media (forced-colors: active) { button, [role=button], [role=tab], [role=switch] { border: 1px solid ButtonText !important; } }
</style>
</head>
<body>
<div class="buehne" data-buehne data-variante="vier" data-modus="differenz">

  <header class="ecke ecke--ol" data-ecke>
    <a class="marke" href="#t1" data-ziel="t1" aria-label="Rautenberg Aydin Architekten, Startseite">Rautenberg Aydin <em>Architekten</em></a>
  </header>

  <nav class="ecke ecke--or navi" data-ecke aria-label="Hauptnavigation">
    <ul>
      <li><a href="#t1" data-ziel="t1" data-bereich="projekte">Projekte</a></li>
      <li><a href="#t5" data-ziel="t5" data-bereich="buero">Büro</a></li>
      <li><a href="#t5" data-ziel="t5" data-bereich="team">Team</a></li>
      <li><a href="#t3" data-ziel="t3" data-bereich="aktuelles">Aktuelles</a></li>
      <li><a href="#t5" data-ziel="t5" data-bereich="kontakt">Kontakt</a></li>
    </ul>
  </nav>
  <button class="ecke ecke--or menueknopf" type="button" data-ecke data-menueknopf aria-expanded="false" aria-controls="menue">Menü</button>

  <main class="rollbahn" data-rollbahn id="inhalt">
    <section class="tafel t1" id="t1" data-ton="hell" data-titel="Haus am Neroberg" data-ort="Wiesbaden • 2025" data-bereich="projekte">
      <figure>
        <div class="rahmenbild">
          <svg class="bild" viewBox="0 0 1200 900" role="img" aria-label="Haus am Neroberg: zwei versetzte Betonkörper mit Fensterband in der Abenddämmerung">
            <defs>
              <linearGradient id="a-himmel" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#aab3b9"/><stop offset=".5" stop-color="#d3d4d0"/><stop offset=".68" stop-color="#e9dfd2"/></linearGradient>
              <linearGradient id="a-wiese" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#868b82"/><stop offset="1" stop-color="#555a53"/></linearGradient>
              <linearGradient id="a-glas" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#6f797f"/><stop offset=".45" stop-color="#3a4043"/><stop offset="1" stop-color="#25292b"/></linearGradient>
              <linearGradient id="a-glas2" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#2a2e30"/><stop offset=".55" stop-color="#33383a"/><stop offset="1" stop-color="#2a2e30"/></linearGradient>
              <filter id="a-korn"><feTurbulence type="fractalNoise" baseFrequency=".85" numOctaves="2" stitchTiles="stitch"/><feColorMatrix type="saturate" values="0"/><feComponentTransfer><feFuncA type="linear" slope=".09"/></feComponentTransfer></filter>
            </defs>
            <rect width="1200" height="900" fill="url(#a-himmel)"/>
            <path d="M0 560C180 522 320 540 460 524S760 498 900 526 1100 540 1200 518V660H0Z" fill="#aab0b2"/>
            <path d="M0 602C200 584 380 598 600 588S1000 592 1200 580V670H0Z" fill="#959b99"/>
            <rect y="622" width="1200" height="278" fill="url(#a-wiese)"/>
            <g fill="#575d58"><circle cx="1012" cy="512" r="70"/><circle cx="1068" cy="556" r="58"/><circle cx="962" cy="560" r="52"/><circle cx="1110" cy="606" r="40"/></g>
            <rect x="1030" y="560" width="8" height="70" fill="#3f443f"/>
            <g fill="#4b514c"><ellipse cx="206" cy="468" rx="24" ry="124"/><ellipse cx="252" cy="500" rx="20" ry="98"/><ellipse cx="160" cy="512" rx="17" ry="82"/></g>
            <g stroke="#383d39" stroke-width="5"><path d="M206 580V636M252 584V634M160 584V632"/></g>
            <ellipse cx="640" cy="654" rx="380" ry="15" fill="#3c403c" opacity=".38"/>
            <rect x="300" y="642" width="640" height="9" fill="#aeaca5"/>
            <rect x="330" y="540" width="500" height="104" fill="#cecbc4"/>
            <rect x="330" y="540" width="130" height="3" fill="#e2e0da"/>
            <rect x="352" y="562" width="320" height="72" fill="url(#a-glas)"/>
            <rect x="420" y="594" width="128" height="40" fill="#d9bb8e" opacity=".55"/>
            <circle cx="482" cy="584" r="5" fill="#f3e3c4"/>
            <g stroke="#1c1f21" stroke-width="3"><path d="M416 562V634M480 562V634M544 562V634M608 562V634"/></g>
            <rect x="694" y="566" width="114" height="78" fill="#b7b4ad"/>
            <rect x="742" y="578" width="40" height="66" fill="#56554f"/>
            <rect x="460" y="448" width="500" height="94" fill="#e4e2dc"/>
            <rect x="460" y="448" width="500" height="4" fill="#f3f2ee"/>
            <rect x="490" y="472" width="440" height="46" fill="url(#a-glas2)"/>
            <rect x="490" y="472" width="440" height="14" fill="#7d878c" opacity=".55"/>
            <g stroke="#1e2123" stroke-width="3"><path d="M578 472V518M666 472V518M754 472V518M842 472V518"/></g>
            <rect x="460" y="536" width="500" height="8" fill="#8e8c86"/>
            <rect x="830" y="544" width="130" height="10" fill="#6a6964" opacity=".5"/>
            <rect width="1200" height="900" filter="url(#a-korn)"/>
          </svg>
        </div>
        <figcaption><span>Haus am Neroberg</span><span>Wohnhaus • Wiesbaden • 2025</span></figcaption>
      </figure>
    </section>

    <section class="tafel t2" id="t2" data-ton="dunkel" data-titel="Kolonnadenfoyer" data-ort="Wiesbaden • 2023" data-bereich="projekte">
      <svg class="bild" viewBox="0 0 1600 1000" preserveAspectRatio="xMidYMid slice" role="img" aria-label="Kolonnadenfoyer bei Nacht: erleuchtete Halle hinter einer Reihe schlanker Stützen, Spiegelung auf nassem Pflaster">
        <defs>
          <linearGradient id="b-himmel" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#0e1214"/><stop offset="1" stop-color="#283034"/></linearGradient>
          <linearGradient id="b-licht" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#f2d9aa"/><stop offset=".6" stop-color="#d6ae74"/><stop offset="1" stop-color="#a77d47"/></linearGradient>
          <linearGradient id="b-spiegel" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#c79c62" stop-opacity=".42"/><stop offset="1" stop-color="#c79c62" stop-opacity="0"/></linearGradient>
          <pattern id="b-stuetzen" width="120" height="400" patternUnits="userSpaceOnUse" x="20"><rect x="0" width="26" height="400" fill="#2c3336"/><rect x="0" width="5" height="400" fill="#3d4549"/></pattern>
          <pattern id="b-lampen" width="148" height="80" patternUnits="userSpaceOnUse" x="40"><circle cx="74" cy="40" r="26" fill="#fff1d4" opacity=".22"/><circle cx="74" cy="40" r="6" fill="#fff7e6"/></pattern>
          <filter id="b-korn"><feTurbulence type="fractalNoise" baseFrequency=".8" numOctaves="2" stitchTiles="stitch"/><feColorMatrix type="saturate" values="0"/><feComponentTransfer><feFuncA type="linear" slope=".08"/></feComponentTransfer></filter>
        </defs>
        <rect width="1600" height="1000" fill="url(#b-himmel)"/>
        <rect x="-10" y="300" width="1620" height="470" fill="#1b2022"/>
        <rect x="-10" y="300" width="1620" height="58" fill="#2a3033"/>
        <rect x="-10" y="358" width="1620" height="6" fill="#121718"/>
        <rect x="60" y="392" width="1480" height="338" fill="url(#b-licht)"/>
        <rect x="60" y="400" width="1480" height="80" fill="url(#b-lampen)"/>
        <rect x="60" y="560" width="1480" height="4" fill="#8a6537" opacity=".5"/>
        <g fill="#4a3824" opacity=".75">
          <rect x="300" y="628" width="16" height="102" rx="7"/><circle cx="308" cy="616" r="11"/>
          <rect x="336" y="640" width="15" height="90" rx="7"/><circle cx="343" cy="629" r="10"/>
          <rect x="868" y="634" width="16" height="96" rx="7"/><circle cx="876" cy="622" r="11"/>
          <rect x="1214" y="626" width="16" height="104" rx="7"/><circle cx="1222" cy="614" r="11"/>
        </g>
        <rect x="640" y="600" width="300" height="130" fill="#b88d55" opacity=".35"/>
        <rect x="0" y="362" width="1600" height="390" fill="url(#b-stuetzen)"/>
        <rect x="-10" y="750" width="1620" height="20" fill="#293033"/>
        <rect x="-10" y="770" width="1620" height="230" fill="#0c1011"/>
        <rect x="60" y="772" width="1480" height="170" fill="url(#b-spiegel)"/>
        <rect x="0" y="772" width="1600" height="150" fill="url(#b-stuetzen)" opacity=".55"/>
        <g fill="#090c0d"><circle cx="-10" cy="500" r="96"/><circle cx="58" cy="560" r="64"/><circle cx="1610" cy="510" r="100"/><circle cx="1548" cy="576" r="58"/></g>
        <rect x="34" y="580" width="9" height="190" fill="#090c0d"/><rect x="1572" y="590" width="9" height="180" fill="#090c0d"/>
        <rect width="1600" height="1000" filter="url(#b-korn)"/>
      </svg>
      <p class="bu">Kolonnadenfoyer • Wiesbaden • 2023</p>
    </section>

    <section class="tafel t3" id="t3" data-ton="hell" data-titel="Grundschule Biebrich" data-ort="Wiesbaden-Biebrich • 2026" data-bereich="aktuelles">
      <svg viewBox="0 0 900 640" role="img" aria-label="Grundriss Erdgeschoss: Bestandsbau von 1911 links, Neubau mit drei Klassen, Lernlandschaft und Mensa rechts">
        <defs>
          <pattern id="c-schraffur" width="9" height="9" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><path d="M0 0V9" stroke="#231f20" stroke-width="1" opacity=".38"/></pattern>
        </defs>
        <g stroke="#76767a" stroke-width="1" stroke-dasharray="14 4 2 4" opacity=".7">
          <path d="M400 40V600M546 40V600M693 40V600M840 40V600M20 80H880M20 300H880M20 560H880"/>
        </g>
        <g font-family="Hanken Grotesk, sans-serif" font-size="12" fill="#76767a" text-anchor="middle">
          <text x="400" y="30">A</text><text x="546" y="30">B</text><text x="693" y="30">C</text><text x="840" y="30">D</text>
          <text x="10" y="84">1</text><text x="10" y="304">2</text><text x="10" y="564">3</text>
        </g>
        <rect x="60" y="80" width="300" height="480" fill="url(#c-schraffur)" stroke="#231f20" stroke-width="9"/>
        <g stroke="#231f20" stroke-width="4" fill="none"><path d="M60 250H230M290 250H360M60 400H170M230 400H360M200 80V180M200 220V250"/></g>
        <rect x="400" y="80" width="440" height="220" fill="#fff" stroke="#231f20" stroke-width="9"/>
        <rect x="400" y="300" width="200" height="260" fill="#fff" stroke="#231f20" stroke-width="9"/>
        <g stroke="#231f20" stroke-width="3" fill="none">
          <path d="M546 80V200M693 80V200M400 200H470M520 200H600M650 200H740M790 200H840"/>
          <path d="M470 200A50 50 0 0 1 520 250M600 200A50 50 0 0 0 650 250M740 200A50 50 0 0 1 790 250"/>
          <path d="M360 220H400M360 340H400"/>
          <path d="M600 470H640M600 520H640"/>
        </g>
        <g stroke="#231f20" stroke-width="1.4">
          <path d="M430 80H520M570 80H670M716 80H816M840 110V180M400 340V420M400 460V530"/>
          <path d="M430 76H520M570 76H670M716 76H816M844 110V180M396 340V420M396 460V530"/>
        </g>
        <g fill="#fff" stroke="#231f20" stroke-width="1.4"><rect x="640" y="440" width="180" height="120"/></g>
        <g font-family="Hanken Grotesk, sans-serif" font-size="13" fill="#231f20">
          <text x="420" y="130">Klasse 1a</text><text x="420" y="148" fill="#76767a" font-size="11">62 m²</text>
          <text x="566" y="130">Klasse 1b</text><text x="566" y="148" fill="#76767a" font-size="11">62 m²</text>
          <text x="713" y="130">Klasse 2a</text><text x="713" y="148" fill="#76767a" font-size="11">64 m²</text>
          <text x="660" y="276">Lernlandschaft</text>
          <text x="440" y="400">Mensa</text><text x="440" y="418" fill="#76767a" font-size="11">118 m²</text>
          <text x="658" y="480">Schulhof</text>
          <text x="96" y="160" font-style="italic">Bestand 1911</text>
        </g>
        <g transform="translate(400 600)" stroke="#231f20" stroke-width="2" fill="none"><path d="M0 0H120M0 -6V6M60 -4V4M120 -6V6"/></g>
        <g font-family="Hanken Grotesk, sans-serif" font-size="11" fill="#76767a"><text x="396" y="624">0</text><text x="452" y="624">5</text><text x="510" y="624">10 m</text></g>
        <g transform="translate(860 600)"><circle r="16" fill="none" stroke="#231f20" stroke-width="1.4"/><path d="M0 -13L6 8L0 4L-6 8Z" fill="#231f20"/></g>
      </svg>
      <div class="text">
        <p class="meta">Erweiterung • im Bau</p>
        <h2>Grundschule Biebrich: sechs Klassen <em>und eine Mensa</em></h2>
        <p>Der Neubau in Holzbauweise nimmt die Traufhöhe des Altbaus von 1911 auf. Eine Lernlandschaft verbindet die Klassen und öffnet sich zum Schulhof.</p>
        <dl><dt>Fläche</dt><dd>2.150 m² BGF</dd><dt>Leistung</dt><dd>LPH 1–8</dd><dt>Fertig</dt><dd>Sommer 2026</dd></dl>
      </div>
    </section>

    <section class="tafel t4" id="t4" data-ton="hell" data-titel="Kelterhaus Frauenstein" data-ort="Wiesbaden-Frauenstein • 2024" data-bereich="projekte">
      <div class="links" data-ton="dunkel">
        <svg class="bild" viewBox="0 0 800 1000" preserveAspectRatio="xMidYMid slice" role="img" aria-label="Kelterhaus aus Stampflehm mit Satteldach am Hang, Rebzeilen in der Dämmerung">
          <defs>
            <linearGradient id="d-himmel" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#8f989e"/><stop offset=".42" stop-color="#cbc6be"/></linearGradient>
            <linearGradient id="d-hang" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#4a504a"/><stop offset="1" stop-color="#1d211e"/></linearGradient>
            <clipPath id="d-flaeche"><path d="M0 400L800 540V1000H0Z"/></clipPath>
            <filter id="d-korn"><feTurbulence type="fractalNoise" baseFrequency=".85" numOctaves="2" stitchTiles="stitch"/><feColorMatrix type="saturate" values="0"/><feComponentTransfer><feFuncA type="linear" slope=".09"/></feComponentTransfer></filter>
          </defs>
          <rect width="800" height="1000" fill="url(#d-himmel)"/>
          <path d="M0 360C200 340 420 372 800 420V560H0Z" fill="#7d8486" opacity=".6"/>
          <path d="M0 400L800 540V1000H0Z" fill="url(#d-hang)"/>
          <g clip-path="url(#d-flaeche)" stroke="#262a27" stroke-width="7">
            <path d="M-500 1000L140 330M-380 1000L140 330M-260 1000L140 330M-140 1000L140 330M-20 1000L140 330M100 1000L140 330M220 1000L140 330M340 1000L140 330M460 1000L140 330M580 1000L140 330M700 1000L140 330M820 1000L140 330M940 1000L140 330M1060 1000L140 330M1180 1000L140 330M1300 1000L140 330"/>
          </g>
          <g clip-path="url(#d-flaeche)" stroke="#5d645d" stroke-width="2" opacity=".55">
            <path d="M-440 1000L140 330M-320 1000L140 330M-200 1000L140 330M-80 1000L140 330M40 1000L140 330M160 1000L140 330M280 1000L140 330M400 1000L140 330M520 1000L140 330M640 1000L140 330M760 1000L140 330M880 1000L140 330M1000 1000L140 330M1120 1000L140 330M1240 1000L140 330"/>
          </g>
          <ellipse cx="575" cy="530" rx="140" ry="10" fill="#161917" opacity=".5"/>
          <rect x="470" y="438" width="210" height="92" fill="#cdc4b6"/>
          <g stroke="#b3a998" stroke-width="2" opacity=".8"><path d="M470 452H680M470 467H680M470 483H680M470 498H680M470 514H680"/></g>
          <path d="M458 440L575 384L692 440Z" fill="#2a2d2b"/>
          <rect x="566" y="456" width="18" height="64" fill="#e3c38e"/>
          <rect x="626" y="470" width="30" height="12" fill="#3b3a35"/>
          <rect width="800" height="1000" filter="url(#d-korn)"/>
        </svg>
      </div>
      <div class="text" data-ton="hell">
        <p class="meta">Kelterhaus • Wiesbaden-Frauenstein • 2024</p>
        <h2>Stampflehm aus <em>dem eigenen Weinberg</em></h2>
        <p>Die Wände bestehen aus dem Löss, der beim Aushub des Kellers anfiel. Sechzig Zentimeter Lehm halten den Gärraum ohne Technik zwischen 12 und 16 Grad.</p>
        <dl><dt>Fläche</dt><dd>640 m² BGF</dd><dt>Leistung</dt><dd>LPH 1–9</dd><dt>Bauherr</dt><dd>privat</dd></dl>
      </div>
      <p class="bu" style="top:calc(60svh - 40px);bottom:auto">Kelterhaus • Frauenstein • 2024</p>
    </section>

    <section class="tafel t5" id="t5" data-ton="dunkel" data-titel="Büro" data-ort="Adolfsallee 27 • Wiesbaden" data-bereich="kontakt">
      <h2>Wir planen ruhige Häuser <em>für lange Zeiträume.</em></h2>
      <div class="karte">
        <div><h3>Büro</h3><p>Rautenberg Aydin Architekten PartG mbB<br>Adolfsallee 27<br>65185 Wiesbaden</p></div>
        <div><h3>Kontakt</h3><p><a href="#t5">0611 / 41 80 27-0</a><br><a href="#t5">buero@rautenberg-aydin.example</a></p></div>
        <div><h3>Kammer</h3><p>Jana Rautenberg, Deniz Aydin<br>Mitglieder der Architekten- und Stadtplanerkammer Hessen</p></div>
      </div>
    </section>
  </main>

  <p class="ecke ecke--ul legende" data-ecke data-legende aria-live="polite">Haus am Neroberg • Wiesbaden • 2025</p>
  <p class="ecke ecke--ur zaehler" data-ecke><span data-zahl>01 / 05</span><span data-uhr>Wiesbaden 14:32</span></p>
  <span class="linie" aria-hidden="true"></span>

  <div class="menue" id="menue" data-menue data-ton="hell" inert>
    <nav aria-label="Menü">
      <ol>
        <li><a href="#t1" data-ziel="t1"><span class="nr">01</span><em>Projekte</em><sup>24</sup></a></li>
        <li><a href="#t5" data-ziel="t5"><span class="nr">02</span><em>Büro</em></a></li>
        <li><a href="#t5" data-ziel="t5"><span class="nr">03</span><em>Team</em><sup>11</sup></a></li>
        <li><a href="#t3" data-ziel="t3"><span class="nr">04</span><em>Aktuelles</em></a></li>
        <li><a href="#t5" data-ziel="t5"><span class="nr">05</span><em>Kontakt</em></a></li>
      </ol>
    </nav>
    <div class="menue__fuss"><p>Adolfsallee 27, 65185 Wiesbaden</p><p>0611 / 41 80 27-0</p><p>buero@rautenberg-aydin.example</p></div>
  </div>
</div>

<div class="pult mono" aria-label="Demo-Steuerung">
  <div class="pult__gruppe" role="group" aria-label="Variante">
    <button type="button" data-v="vier" aria-pressed="true">Vier Ecken</button>
    <button type="button" data-v="drei" aria-pressed="false">Drei Ecken</button>
    <button type="button" data-v="seite" aria-pressed="false">Seitenleiste</button>
  </div>
  <span class="pult__trenner" aria-hidden="true"></span>
  <div class="pult__gruppe" role="group" aria-label="Lesbarkeit">
    <button type="button" data-m="differenz" aria-pressed="true">Differenz</button>
    <button type="button" data-m="sektion" aria-pressed="false">Sektion</button>
  </div>
  <p class="pult__werte" data-werte></p>
</div>

<script>
(() => {
  const html = document.documentElement;
  const reduziert = () => html.classList.contains('reduziert');
  const telefon = matchMedia('(max-width: 720px)');
  const buehne = document.querySelector('[data-buehne]');
  const bahn = document.querySelector('[data-rollbahn]');
  const tafeln = [...bahn.querySelectorAll('.tafel')];
  const ecken = [...buehne.querySelectorAll('[data-ecke]')];
  const legende = document.querySelector('[data-legende]');
  const zahl = document.querySelector('[data-zahl]');
  const uhr = document.querySelector('[data-uhr]');
  const menue = document.querySelector('[data-menue]');
  const knopf = document.querySelector('[data-menueknopf]');
  const naviLinks = [...buehne.querySelectorAll('.navi a')];
  const werteText = document.querySelector('[data-werte]');

  const WERTE = {
    vier: 'Rand 28 px · 1 rem versal · .06em · Legende 250 ms ease',
    drei: 'Menü auf 500 ms cubic-bezier(.1,.9,.3,1) · zu 250 ms · Ecken aus 250 ms ease',
    seite: 'writing-mode: vertical-rl + rotate(180deg) · Linie bei 88 px · Wechsel 500 ms',
  };
  const MODUS = { differenz: 'mix-blend-mode: difference', sektion: 'Farbe je Untergrund · 125 ms' };

  // ---------- Uhr (Ortszeit Wiesbaden) ----------
  const zeit = new Intl.DateTimeFormat('de-DE', { timeZone: 'Europe/Berlin', hour: '2-digit', minute: '2-digit' });
  const ticken = () => { uhr.textContent = 'Wiesbaden ' + zeit.format(new Date()); };
  ticken(); setInterval(ticken, 20000);

  // ---------- Scrollspy: Legende, Zähler, aktiver Bereich ----------
  let aktuell = -1, legendeUhr = null;
  function legendeSetzen(t) {
    const text = t.dataset.titel + ' • ' + t.dataset.ort;
    if (legende.textContent === text) return;
    clearTimeout(legendeUhr);
    if (reduziert()) { legende.textContent = text; return; }
    legende.classList.add('aus');                       // 250 ms ease aus, Text tauschen, wieder ein
    legendeUhr = setTimeout(() => { legende.textContent = text; legende.classList.remove('aus'); }, 250);
  }
  function tonErmitteln() {
    // Je Ecke: was liegt in ihrer Mitte darunter? Nächstes [data-ton] gewinnt (auch halbe Tafeln, Menü).
    for (const e of ecken) {
      const r = e.getBoundingClientRect();
      if (!r.width) continue;
      const unter = document.elementsFromPoint(r.left + r.width / 2, r.top + r.height / 2).find(x => !x.closest('[data-ecke]') && x.closest('[data-ton]'));
      const ton = unter ? unter.closest('[data-ton]').dataset.ton : 'hell';
      if (e.dataset.ton !== ton) e.dataset.ton = ton;
    }
  }
  function aktualisieren() {
    const mitte = bahn.scrollTop + bahn.clientHeight / 2;
    let i = 0;
    tafeln.forEach((t, j) => { if (t.offsetTop <= mitte) i = j; });
    if (i !== aktuell) {
      aktuell = i;
      const t = tafeln[i];
      legendeSetzen(t);
      zahl.textContent = String(i + 1).padStart(2, '0') + ' / ' + String(tafeln.length).padStart(2, '0');
      naviLinks.forEach(a => { if (a.dataset.bereich === t.dataset.bereich) a.setAttribute('aria-current', 'location'); else a.removeAttribute('aria-current'); });
    }
    tonErmitteln();
  }
  let geplant = false;
  bahn.addEventListener('scroll', () => { if (!geplant) { geplant = true; requestAnimationFrame(() => { geplant = false; aktualisieren(); }); } }, { passive: true });
  addEventListener('resize', aktualisieren);

  // ---------- Rollen zu einer Tafel (Klick und Vorführung) ----------
  function kurve(x1, y1, x2, y2) {           // cubic-bezier als Funktion
    const b = (t, a, c) => 3 * a * t * (1 - t) ** 2 + 3 * c * t * t * (1 - t) + t ** 3;
    const db = (t, a, c) => 3 * a * (1 - t) ** 2 + 6 * (c - a) * t * (1 - t) + 3 * (1 - c) * t * t;
    return x => { let t = x; for (let k = 0; k < 8; k++) { const d = b(t, x1, x2) - x; if (Math.abs(d) < 1e-5) break; t -= d / (db(t, x1, x2) || 1); } return b(t, y1, y2); };
  }
  const gleiten = kurve(0.1, 0.6, 0.4, 1);
  let rollFrame = 0;
  function rollen(ziel, dauer = 1000) {
    cancelAnimationFrame(rollFrame);
    const y = typeof ziel === 'number' ? ziel : ziel.offsetTop;
    const von = bahn.scrollTop, nach = Math.max(0, Math.min(y, bahn.scrollHeight - bahn.clientHeight));
    if (reduziert() || Math.abs(nach - von) < 2) { bahn.scrollTop = nach; aktualisieren(); return; }
    const start = performance.now();
    const schritt = t => {
      const p = Math.min(1, (t - start) / dauer);
      bahn.scrollTop = von + (nach - von) * gleiten(p);
      if (p < 1) rollFrame = requestAnimationFrame(schritt);
    };
    rollFrame = requestAnimationFrame(schritt);
  }
  buehne.addEventListener('click', e => {
    const a = e.target.closest('a[data-ziel]');
    if (!a) return;
    e.preventDefault();
    if (buehne.classList.contains('offen')) menueSetzen(false);
    rollen(document.getElementById(a.dataset.ziel));
  });
  bahn.addEventListener('click', e => { if (e.target.closest('a[href="#t5"]')) e.preventDefault(); });

  // ---------- Menü ----------
  function menueSetzen(auf) {
    buehne.classList.toggle('offen', auf);
    menue.inert = !auf;
    bahn.inert = auf;
    knopf.setAttribute('aria-expanded', String(auf));
    knopf.textContent = auf ? 'Schließen' : 'Menü';
    if (auf && !html.classList.contains('vorfuehrung')) setTimeout(() => menue.querySelector('a').focus({ preventScroll: true }), 60);
    tonErmitteln();
    setTimeout(tonErmitteln, 520);
  }
  knopf.addEventListener('click', () => menueSetzen(!buehne.classList.contains('offen')));
  addEventListener('keydown', e => { if (e.key === 'Escape' && buehne.classList.contains('offen')) { menueSetzen(false); knopf.focus(); } });

  // ---------- Varianten (same-document View Transition) ----------
  function werteZeigen() {
    werteText.textContent = telefon.matches
      ? 'Unter 720 px: Kopfzeile + Menü · Rand 20 px · ' + MODUS[buehne.dataset.modus]
      : WERTE[buehne.dataset.variante] + ' · ' + MODUS[buehne.dataset.modus];
  }
  function varianteSetzen(v) {
    if (buehne.dataset.variante === v) return;
    const wechseln = () => {
      if (buehne.classList.contains('offen') && v !== 'drei') menueSetzen(false);
      buehne.dataset.variante = v;
      document.querySelectorAll('[data-v]').forEach(b => b.setAttribute('aria-pressed', String(b.dataset.v === v)));
      werteZeigen();
      tonErmitteln();
    };
    if (reduziert() || !document.startViewTransition || telefon.matches) { wechseln(); return; }
    tonErmitteln();
    buehne.classList.add('vt');                 // Namen nur für die Dauer des Wechsels: blend bleibt sonst intakt
    const vt = document.startViewTransition(wechseln);
    vt.finished.finally(() => { buehne.classList.remove('vt'); tonErmitteln(); });
  }
  function modusSetzen(m) {
    buehne.dataset.modus = m;
    document.querySelectorAll('[data-m]').forEach(b => b.setAttribute('aria-pressed', String(b.dataset.m === m)));
    werteZeigen();
  }
  document.querySelectorAll('[data-v]').forEach(b => b.addEventListener('click', () => { pause(); varianteSetzen(b.dataset.v); }));
  document.querySelectorAll('[data-m]').forEach(b => b.addEventListener('click', () => modusSetzen(b.dataset.m)));
  telefon.addEventListener('change', () => { werteZeigen(); aktualisieren(); });

  // ---------- Vorführung: rollt durch die Tafeln, wechselt die Varianten, öffnet das Menü ----------
  const T = id => document.getElementById(id);
  const DREHBUCH = [
    [900, () => rollen(T('t2').offsetTop - bahn.clientHeight * 0.6)],   // Grenze hell/dunkel mitten im Bild: oben schwarz, unten hell
    [2300, () => rollen(T('t2'))],
    [1700, () => rollen(T('t3'))],
    [1800, () => rollen(T('t4'))],
    [1900, () => varianteSetzen('seite')],
    [2000, () => rollen(T('t5'))],
    [1700, () => varianteSetzen('drei')],
    [1300, () => menueSetzen(true)],
    [1900, () => menueSetzen(false)],
    [900, () => { rollen(T('t1')); varianteSetzen('vier'); }],
    [1500, null],
  ];
  let schrittNr = 0, uhrVor = null, laeuft = false;
  function naechster() {
    const [warte, tun] = DREHBUCH[schrittNr];
    uhrVor = setTimeout(() => {
      if (tun) tun();
      schrittNr = (schrittNr + 1) % DREHBUCH.length;
      naechster();
    }, warte);
  }
  function neustart() {
    pause();
    html.classList.remove('vorfuehrung');
    if (buehne.classList.contains('offen')) menueSetzen(false);
    buehne.dataset.variante = 'vier';
    document.querySelectorAll('[data-v]').forEach(b => b.setAttribute('aria-pressed', String(b.dataset.v === 'vier')));
    cancelAnimationFrame(rollFrame);
    bahn.scrollTop = 0;
    schrittNr = 0;
    werteZeigen();
    aktualisieren();
  }
  function vorfuehren() {
    neustart();
    html.classList.add('vorfuehrung');
    laeuft = true;
    naechster();
  }
  function pause() { clearTimeout(uhrVor); uhrVor = null; laeuft = false; }
  function weiter() { if (!laeuft && html.classList.contains('vorfuehrung')) { laeuft = true; naechster(); } }

  werteZeigen();
  aktualisieren();
  if (document.fonts) document.fonts.ready.then(aktualisieren);

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