@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-sans-latin-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-sans-latin-ext-500-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-sans-latin-500-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-sans-latin-ext-600-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --ground: #161819;
  --ink: #f2f2e7;
  --ground-lift: #33393f;
  /* Farbton 25° (aus dem fruehen #875939) erhalten, Helligkeit/Saettigung so
     gewaehlt, dass BEIDE Kontraste gleichzeitig halten: Knopfflaeche gegen
     --ground 3,16:1 (>= 3:1), --ink-Beschriftung auf der Flaeche 5,00:1
     (>= 4.5:1). Ausschliesslich am CTA zur Detailansicht verwendet. */
  --accent-warm: #8b5d3c;
  /* Gemessen aus den Uferbewuchs-Gruens in site/assets/stream/*.webp (siehe
     tools/build.py-Nachbarwerkzeug), Farbton 84° erhalten, Saettigung und
     Helligkeit angehoben (Auftraggeber: "zu dezent, sollte Farbe sein"),
     bis der Kontrast gegen --ground 6,19:1 erreicht. */
  --accent-green: #7fa446;
  /* Gemessen aus den roten Kisten/Zurrgurten in site/assets/stream/gen-04.webp
     (Einkaufskorb, Pixelwerte um #e14041), Farbton 359,3° und Saettigung 73,6%
     erhalten, Helligkeit von 0,555 auf 0,60 angehoben, bis der Kontrast gegen
     --ground 4,67:1 erreicht (>= 4.5:1, siehe Auftrag "Fehlschlag statt
     Schweigen"). Ausschliesslich fuer den Status "Fehlschlag" verwendet. */
  --accent-red: #e44e50;
  --muted: #a9afa9;
  --section-gap: 48px;
}

:root { color-scheme: dark; }
* { box-sizing: border-box; }
[hidden] { display: none !important; }

html {
  overflow-x: clip;
  background: var(--ground);
  color: var(--ink);
  font-family: "IBM Plex Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 16px;
  scroll-behavior: smooth;
}

body {
  display: flex;
  flex-direction: column;
  min-width: 320px;
  min-height: 100vh;
  margin: 0;
  overflow-x: clip;
  background: var(--ground);
  color: var(--ink);
  font-size: 16px;
  line-height: 24px;
}

a {
  color: var(--ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
a:visited { color: var(--muted); }

a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

button,
input { font: inherit; }

button {
  min-width: 44px;
  min-height: 44px;
  padding: 8px 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  appearance: none;
}

button:hover,
a:hover { text-decoration: underline; }
button:disabled { cursor: wait; opacity: .55; }

img,
svg { display: block; max-width: 100%; }

figure,
p,
h1,
h2,
h3,
dl,
ol,
ul { margin: 0; }

ol,
ul { padding: 0; list-style: none; }

h1,
h2,
h3 {
  color: var(--ink);
  font-weight: 600;
  letter-spacing: -.035em;
}
h1 { font-size: clamp(2.25rem, 4vw, 4rem); line-height: .95; }
h2 { font-size: 28px; line-height: 32px; }
h3 { font-size: 24px; line-height: 28px; }

time,
.eyebrow,
.image-mark,
.track-status,
.detail-meta dt,
.detail-meta dd,
.component-help,
.track-disclosure,
.site-nav-label,
.carousel-evidence,
.carousel-slide-label,
.source-time,
.source-note {
  font-size: 14px;
  line-height: 20px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.site-header { position: relative; background: var(--ground); }
/* Punkt 1: die Übersicht deckelt ihren Inhalt nicht mehr auf 1280px - sie nutzt
   die volle Fensterbreite abzüglich eines maßvollen Seitenrandes. Der Kopf geht
   mit (Punkt 9: das neue, große Logo braucht die Breite), Detailseiten und der
   Fuß bleiben auf Lesebreite gedeckelt. */
.site-header__inner,
.overview {
  width: calc(100% - 96px);
  margin-right: auto;
  margin-left: auto;
}
.detail-article,
.site-footer__inner {
  width: min(1280px, calc(100% - 96px));
  margin-right: auto;
  margin-left: auto;
}

.detail-article { width: min(1344px, calc(100% - 96px)); }

/* Punkt 2/6 (Zielbild): Titel+Unterschrift und Logo bilden zusammen den
   Kopfbereich - EIN Bereich, kein separater Titelblock mehr darunter. Beide
   beginnen ganz oben (rund 2% der Fensterhöhe), Titelgruppe links, Logo
   rechts, auf einer Höhe. space-between plus je eigener max-width verhindert
   Überschneidung, ohne dass sich Titel und Logo je berühren müssen. */
.site-header__inner {
  display: flex;
  padding-top: 2vh;
  padding-bottom: 8px;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
}

.site-title-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  max-width: 62%;
}
.site-title-link { display: block; text-decoration: none; }
.site-title-link:hover { text-decoration: none; }
.site-title { margin: 0; }
.site-tagline { margin: 0; color: var(--ink); font-size: 18px; line-height: 24px; font-weight: 500; }

.channel-wordmark {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  min-width: 44px;
  min-height: 44px;
}
/* Punkt 9: brudi-floss-ozean.jpg ersetzt das alte Wortzeichen, rechts oben,
   deutlich größer als die bisherigen 170px. Über vw an die Fensterbreite
   gekoppelt (Auftraggeber-Screenshot: rund ein Drittel), aber gedeckelt, damit
   der Kopf auf 1920x1080/1440x900 nicht so viel Höhe frisst, dass die
   Übersicht darunter scrollen müsste (Randbedingung: kein Scrollen). */
/* Hoehe fuehrt, Breite folgt. Mit width + max-height zusammen staucht der
   Browser das Bild, weil die Breite gesetzt bleibt und nur die Hoehe gekappt
   wird - genau das sah verzerrt aus. */
/* NUR die Hoehe wird gesetzt, die Breite folgt. Eine Breitenschranke daneben
   (max-width) staucht das Bild, weil sie die Breite kappt und die Hoehe stehen
   laesst - derselbe Fehler, nur andersherum. Die Breitengrenze steckt deshalb
   in der Hoehe selbst: das Wortzeichen ist 3:1 (2448x816), also entsprechen
   33vw Breite genau 11vw Hoehe. */
.channel-wordmark img {
  height: min(12vh, 11vw);
  width: auto;
}
/* Das Logo soll nicht als Kachel im Eck kleben, sondern in den Grund
   uebergehen: es laeuft oben und rechts aus dem Satzspiegel heraus bis an die
   Blattkante, und seine beiden Innenkanten (links und unten) verlaufen weich
   in den dunklen Grund. Der Verlauf liegt auf dem LOGO, nie auf einer
   Originalaufnahme - der Fotoschutz bleibt davon unberuehrt. */
/* Doppelte Groesse ohne Verschiebung: das Wortzeichen liegt absolut in der
   oberen rechten Ecke und traegt damit nichts mehr zur Hoehe des Kopfes bei.
   Im Fluss wuerde es den Titel und alles darunter nach unten druecken. */
.channel-wordmark {
  position: absolute;
  top: 0;
  right: 0;
  -webkit-mask-image:
    linear-gradient(to right, transparent 0, #000 34%),
    linear-gradient(to top, transparent 0, #000 42%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent 0, #000 34%),
    linear-gradient(to top, transparent 0, #000 42%);
  mask-composite: intersect;
}
/* Doppelte Groesse nur auf der Uebersicht: dort ist die obere rechte Ecke frei.
   Auf den Detailseiten reicht die rechte Spalte bis nach oben, ein 24vh grosses
   Wortzeichen wuerde Titel und Register verdecken. */
/* 20vh statt 24vh: bei 24vh beginnt das Wortzeichen bei x 1286 und ragt damit
   11px in die rechte obere Ecke der grossen Aufnahme (Kante 1297). */
body:has(.overview) .channel-wordmark img { height: min(20vh, 11vw); }
/* Detailseiten: groesser als die bisherigen 12vh, aber begrenzt, weil die
   rechte Spalte dort bis nach oben reicht. 18vh laesst Exponatnummer, Titel
   und Registerzeile frei - nachgemessen, kein Rechteck schneidet sich. */
body:has(.detail-article) .channel-wordmark img { height: min(18vh, 11vw); }

main { width: 100%; flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }

/* Übersicht: eine Bühne, sechs echte Streamaufnahmen, links nach rechts 01 → 05b.
   main ist jetzt Teil der Flex-Spalte aus body (Kopf, main, Fuß), .overview
   bekommt darüber die tatsächlich verbleibende Höhe statt einer geschätzten
   calc(100vh - Kopfhöhe) - die Kopf- und Fußhöhe schwankt (Wortmarke,
   Zeilenumbruch), ein fester Abzug driftet sonst wieder auseinander. */
.overview {
  flex: 1 1 auto;
  min-height: 0;
  padding-top: 16px;
  padding-bottom: 12px;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto auto;
  /* Die Bühne bekommt den verfügbaren Raum; Umschalter und Zielbildblock
     bleiben echte, inhaltsgetriebene Zonen darunter. So beginnt Zone 3 auf
     beiden Zielhöhen ungefähr im unteren Viertel, ohne die Bildgröße künstlich
     über Leerraum zu finanzieren. */
  align-content: stretch;
  gap: 12px;
}

.overview-carousel {
  display: grid;
  min-width: 0;
  min-height: 0;
  grid-template-rows: minmax(0, 1fr) auto;
  align-content: stretch;
  gap: 6px;
}
.carousel-stage {
  display: grid;
  min-width: 0;
  min-height: 0;
  height: 100%;
  grid-template-columns: 44px minmax(0, 1fr) 44px;
  align-items: center;
  gap: 12px;
}
/* Feste Spalten fuer alle drei Kinder. Ohne das rutscht beim ersten Exponat,
   wo der Zurueck-Pfeil ausgeblendet ist, die automatische Platzierung eine
   Spalte nach links: der Viewport landet in der 44px-Pfeilspalte und die
   Bildreihe ist zerstoert. Ausgeblendet heisst hier weiterhin display:none,
   der Platz bleibt trotzdem reserviert, weil die Spalte fest steht. */
.carousel-arrow--prev { grid-column: 1; }
.carousel-viewport { grid-column: 2; }
.carousel-arrow--next { grid-column: 3; }
.carousel-arrow {
  justify-self: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  outline: 1px solid var(--ground-lift);
  outline-offset: -1px;
  color: var(--ink);
  font-size: 20px;
  line-height: 1;
  transition: outline-color 160ms ease;
}
.carousel-arrow:hover { outline-color: var(--ink); text-decoration: none; }
.carousel-viewport {
  display: flex;
  height: 100%;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  padding: 4px 0 8px;
  align-items: center;
}
/* Maske liegt auf dem Viewport, nie auf einer Fotoregel, und verlaeuft nur dort,
   wo laut data-overflow (von updatePosition() gesetzt) wirklich Inhalt hinausragt. */
.overview-carousel[data-overflow="both"] .carousel-viewport {
  mask: linear-gradient(to right, transparent 0, black 32px, black calc(100% - 32px), transparent 100%) no-repeat;
  -webkit-mask: linear-gradient(to right, transparent 0, black 32px, black calc(100% - 32px), transparent 100%) no-repeat;
}
.overview-carousel[data-overflow="left"] .carousel-viewport {
  mask: linear-gradient(to right, transparent 0, black 32px, black 100%) no-repeat;
  -webkit-mask: linear-gradient(to right, transparent 0, black 32px, black 100%) no-repeat;
}
.overview-carousel[data-overflow="right"] .carousel-viewport {
  mask: linear-gradient(to right, black 0, black calc(100% - 32px), transparent 100%) no-repeat;
  -webkit-mask: linear-gradient(to right, black 0, black calc(100% - 32px), transparent 100%) no-repeat;
}
.carousel-track {
  display: flex;
  width: max-content;
  min-height: 0;
  /* Punkt 2: kleinerer Abstand zwischen den Aufnahmen, der gewonnene Platz geht
     in die Bildgröße statt in Zwischenraum. */
  gap: clamp(8px, 1vw, 16px);
  align-items: start;
  transform: translate3d(0, 0, 0);
  will-change: transform;
}
.overview-carousel.is-ready .carousel-track { transition: transform 650ms cubic-bezier(.2, .8, .2, 1); }
.carousel-slide {
  position: relative;
  display: block;
  /* Punkt 1/6 (Zielbild): die aktive Aufnahme selbst ist rund 47vw breit. Die
     Fassung trägt 20px je Seite, deshalb ist die Folienbreite um 40px größer;
     die benachbarten Folien bleiben links und rechts als halbe Anschnitte
     lesbar. Die verfügbare Bühnenhöhe wird über die umgebende Zone begrenzt,
     nicht durch eine zweite, zu kleine Breitenklemme. */
  /* Die Folienbreite folgt der gedeckelten BILDHOEHE (38vh bei 16:9 = 67.6vh),
     sonst ist die Folie breiter als das Foto und es steht Grund daneben, was
     wie ein Kasten um das Bild aussieht. */
  flex: 0 0 clamp(320px, min(47vw, 67.6vh), 980px);
  min-width: 0;
  transform: scale(.7);
}
/* Die ganze Folie skaliert (Nummer + Bild gemeinsam), transform-origin: center
   (Default), damit die Nummer buendig an der linken Kante ihrer eigenen
   Aufnahme bleibt statt an der Position der ungeschrumpften Folie haengen
   zu bleiben. Inaktive Nummern werden dabei etwas kleiner, das ist gewollt. */
.overview-carousel.is-ready .carousel-slide { transition: transform 650ms cubic-bezier(.2, .8, .2, 1); }
.carousel-slide[data-active="true"] { transform: scale(1); }
.carousel-slide-label {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding-bottom: 6px;
  color: var(--muted);
  font-size: 16px;
  line-height: 22px;
  pointer-events: none;
}
.carousel-slide-number { color: var(--ink); font-size: 26px; line-height: 28px; font-weight: 600; letter-spacing: -.02em; }

/* Originalaufnahmen bleiben vollständig und unverändert. Kein Zuschneiden,
   kein Filter, keine feste aspect-ratio, kein Verlauf und keine Umfärbung auf
   dem Bild. Belegmarken (Kennzeichnung, Status-Badge) duerfen an der
   Aufnahme sitzen - in einer Ecke, so klein wie moeglich -, die Bildflaeche
   selbst bleibt aber unangetastet: kein filter, kein backdrop-filter, kein
   mix-blend-mode, kein zuschneidendes object-fit, keine feste aspect-ratio,
   keine Auf-/Abdunklung. */
.visual-frame { position: relative; min-width: 0; }
.source-visual { background: var(--ground); }
/* Hoehendeckel: die Folienbreite kommt aus 47vw, bei 16:9 ergaebe das eine
   Bildhoehe, die zusammen mit Kopf, Umschalter und Zone 3 ueber die
   Fensterhoehe hinauslaeuft. Der Deckel begrenzt die Hoehe, die Breite folgt
   proportional - kein Zuschnitt, keine Verzerrung. */
.source-image { display: block; width: 100%; height: auto; max-height: 38vh; object-fit: contain; }
/* Punkt 7: Passepartout statt Vertragsverbot "keine Rahmen, keine Kästen" -
   Originalaufnahmen UND Renderings bekommen etwas Luft und eine ruhige, helle
   Kante, gedacht als Fassung eines Ausstellungsstücks, nicht als UI-Box. Die
   Fassung liegt NEBEN dem Foto (Padding), nie darauf: kein filter, kein
   backdrop-filter, kein mix-blend-mode auf der Bildfläche selbst.
   .frame reicht für Originalaufnahmen (fixe 16:9-Quellen, contentgetrieben).
   .frame--fit ist zusätzlich für Renderings: Punkt 5 verlangt, dass der Grund
   eng am tatsächlichen Bildinhalt liegt statt an der vollen Spaltenbreite -
   build.py schneidet dafür die freigestellten PNGs vorab auf ihre
   Bounding-Box zu (siehe crop_transparent_border) und trägt das Ergebnis als
   inline aspect-ratio ein (player.js hält sie beim Schritt-/Ansichtswechsel
   nach); zusammen mit max-width/max-height:100% im übergeordneten
   .rendering-visual/.companion-visual (display:grid;place-items:center)
   umschließt die Fassung dadurch immer nur das tatsächlich sichtbare Objekt
   plus 20px Rand, egal wie stark sich der Bildausschnitt je Schritt
   unterscheidet. */
.frame--fit {
  padding: 20px;
  background: var(--ground-lift);
  outline: 1px solid rgba(242, 242, 231, .14);
  outline-offset: -1px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .35);
}
.frame { display: block; }
/* Die Originalaufnahme traegt bewusst keine Fassung: der Rahmen gehoert allein
   zum Rendering, das sonst ohne Grund im Dunkeln schwebt. */
.slide-frame { padding: 0; background: none; outline: none; box-shadow: none; }
/* Die Fassung legt sich um das Bild, statt selbst bemasst zu werden. Das
   zugeschnittene WebP bringt sein Seitenverhaeltnis mit; begrenzt wird die
   BILDHOEHE, die Fassung schrumpft darauf zusammen (inline-block = shrink-wrap).

   Warum kein inline aspect-ratio mehr: die Fassung war ein Block mit
   width:auto, fuellte also zuerst die Breite (677px), und aspect-ratio leitete
   daraus die Hoehe ab (677 / 1.474 = 459px) - dreimal so hoch wie ihre Buehne.
   Die vorgesehene Begrenzung height/max-height:calc(100% - 40px) griff nicht,
   weil die Prozenthoehe gegen die Grid-Flaeche unaufgeloest blieb (Chrome gibt
   sie als calc(100% - 40px) statt als px zurueck). Deshalb hier ausschliesslich
   Viewport-Einheiten, die immer aufloesen. */
.frame--fit {
  display: inline-block;
  width: auto;
  height: auto;
  max-width: 100%;
}
.frame--fit img {
  /* Setzt bewusst KEINE Hoehe: '.frame--fit img' ist spezifischer als
     '.companion-image' bzw. '.rendering-image' und wuerde deren Hoehenvorgabe
     sonst wieder auf auto zurueckdrehen. */
  display: block;
  max-width: 100%;
  object-fit: contain;
}
/* Punkt 8: ruhiger Übergang beim Umschalten Aufnahme/Rendering. Betrifft nur
   die eigene Bildfläche (opacity, kein Verlauf/Filter über dem Bild), nicht die
   Originalaufnahme selbst - reines Laufzeitverhalten des <img>-Elements.
   Global unter prefers-reduced-motion: reduce abgeschaltet. */
.source-image,
.companion-image { transition: opacity 220ms ease; }
.source-image.is-swapping,
.companion-image.is-swapping { opacity: 0; }
.image-mark { display: block; color: var(--ink); }
.source-visual .image-mark { padding-top: 4px; text-align: right; }
.image-fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--ink);
  font-size: 16px;
  line-height: 24px;
}
.carousel-slide-image {
  position: relative;
  display: block;
  width: 100%;
  min-height: 44px;
  padding: 0;
  background: var(--ground);
  color: var(--ink);
  text-align: left;
}
.carousel-slide-image:hover { text-decoration: none; }
.slide-frame { position: relative; }
/* Punkt 3/4: Aufkleber statt Kreis, für beide Zustände - grün mit Haken heißt
   "funktioniert", rot mit X heißt "Fehlschlag" (nie umgekehrt, siehe
   Randbedingungen). Flächig in der jeweiligen Farbe statt Kontur, Symbol UND
   Beschriftung in --ground (dunkel) darauf statt ausgespart: --ground hält auf
   Grün wie auf Rot einen AA-Kontrast über 4,6:1 (siehe Farbwerte oben), heller
   Text auf diesen Mitteltönen tut das nicht. Beschriftung steht mit auf dem
   Etikett - bei einer nur ~4-6 Zeichen kurzen Fläche liest sich "Fehlschlag"
   sofort mit, ohne dass das Etikett dafür wachsen müsste. Schlagschatten und
   helle Innenkontur gehören zum Etikett (eigenes Element, position:absolute
   neben dem Bild), nie zum Foto: kein filter/backdrop-filter/mix-blend-mode
   und kein Hintergrund auf der Bildfläche selbst. */
.exhibit-stamp {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px 5px 8px;
  border-radius: 4px;
  outline: 1.5px solid rgba(242, 242, 231, .6);
  outline-offset: -3px;
  box-shadow: 0 3px 8px rgba(0, 0, 0, .45);
  color: var(--ground);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .01em;
  white-space: nowrap;
  transform: rotate(-6deg);
  pointer-events: none;
}
.exhibit-stamp-icon { font-size: 15px; }
.exhibit-stamp--worked { background: var(--accent-green); }
.exhibit-stamp--failed { background: var(--accent-red); }
.carousel-flow-arrow {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translate(50%, -50%);
  color: var(--muted);
  opacity: .5;
  font-size: 18px;
  line-height: 1;
  pointer-events: none;
}
.carousel-caption { min-width: 0; }
.js .carousel-captions { display: grid; }
.js .carousel-caption {
  grid-column: 1;
  grid-row: 1;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transform: translateY(6px);
  transition: opacity 260ms ease, transform 260ms ease, visibility 260ms;
}
.js .carousel-caption[data-active="true"] {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transform: none;
}
.carousel-slide-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  align-items: baseline;
  color: var(--muted);
}
/* Punkt 6 (Zielbild): "Textblock unten links darf größer gesetzt werden" -
   Exponattitel und Unterschied wachsen, der CTA bleibt der einzige Knopf. */
.carousel-number { color: var(--ink); font-size: 32px; line-height: 34px; font-weight: 600; }
.carousel-number small { font-size: .6em; }
.carousel-caption h2 { margin-top: 4px; font-size: 30px; line-height: 34px; }
.carousel-difference { max-width: 70ch; margin-top: 8px; color: var(--ink); font-size: 17px; line-height: 24px; }
.carousel-evidence { margin-top: 8px; color: var(--muted); }
.carousel-slide-links { display: flex; flex-wrap: wrap; gap: 12px 20px; align-items: center; margin-top: 6px; }
.cta-button {
  display: inline-flex;
  min-height: 44px;
  padding: 0 20px;
  align-items: center;
  justify-content: center;
  background: var(--accent-warm);
  color: var(--ink);
  font-size: 16px;
  line-height: 20px;
  font-weight: 600;
  text-decoration: none;
}
.cta-button:hover { text-decoration: underline; }
.carousel-secondary-link { display: inline-flex; min-height: 44px; align-items: center; color: var(--muted); font-size: 14px; line-height: 20px; }

/* Punkt 8: Umschalter zwischen Aufnahme- und Rendering-Karussell, sitzt zwischen
   Bühne und Rendering (unterhalb des Karussells, oberhalb der zweispaltigen
   Zeile). Grafisch (Pfeil-Symbol) plus lesbare Zustandswörter, role=switch mit
   aria-checked trägt den Zustand am Element. */
.view-switch-row { display: flex; justify-content: flex-end; margin-bottom: 6px; }
.view-switch {
  display: inline-flex;
  min-height: 44px;
  min-width: 44px;
  align-items: center;
  gap: 10px;
  padding: 4px 12px;
  outline: 1px solid var(--ground-lift);
  outline-offset: -1px;
  color: var(--muted);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  transition: outline-color 160ms ease;
}
.view-switch:hover { outline-color: var(--ink); text-decoration: none; }
.view-switch-icon { font-size: 18px; line-height: 1; transition: transform 260ms ease; }
.view-switch[aria-checked="true"] .view-switch-icon { transform: rotate(180deg); }
.view-switch-text { display: inline-flex; gap: 8px; align-items: baseline; }
.view-switch-text span { color: var(--muted); }
.view-switch-text span + span::before { content: "/"; margin-right: 8px; color: var(--muted); }
.view-switch[aria-checked="false"] [data-view-switch-state="source"],
.view-switch[aria-checked="true"] [data-view-switch-state="rendering"] {
  color: var(--ink);
  font-weight: 600;
}

/* Punkt 6: zweispaltige Zeile unter Bühne+Umschalter - links der Textblock zum
   aktiven Exponat samt CTA, rechts das Rendering desselben Exponats. */
/* Der Textblock braucht nur seine Lesebreite; alles Uebrige gehoert dem
   Rendering, das vorher in einer schmalen Spalte klein blieb. */
.overview-below {
  display: grid;
  grid-template-columns: minmax(0, 58ch) minmax(0, 1fr);
  gap: 16px 48px;
  align-items: center;
  min-width: 0;
}
.overview-companion { min-width: 0; margin: 0; }
/* Punkt 5: Grund umschließt das Rendering eng (siehe .frame--fit oben) statt
   die volle Spaltenbreite zu füllen. .companion-visual ist nur noch die
   BÜHNE: definierte Höhe, zentriert die Fassung (.frame--fit), trägt selbst
   keinen Hintergrund mehr. */
/* justify-items zentriert die Fassung waagerecht; die definierte Bühnenhöhe
   hält das Rendering klein genug für Zone 3. Das inline gesetzte
   aspect-ratio folgt dem tatsächlich zugeschnittenen Inhalt. */
.companion-visual {
  height: 28vh;
  display: grid;
  place-items: center end;
  min-height: 0;
}
/* Die Bildhoehe ist die einzige Vorgabe: Buehnenhoehe minus die 20px Rand der
   Fassung auf beiden Seiten. Breite und Fassung folgen daraus von selbst. */
.companion-image { height: calc(28vh - 40px); width: auto; max-width: 100%; }
.overview-companion .image-mark { padding-top: 4px; text-align: right; }

.site-footer { margin-top: 4px; padding: 4px 0; color: var(--muted); }

/* Detailseiten: links zuerst der große Beleg, rechts Titel, Feldraster und
   Rekonstruktion. Punkt 10: die Seite lief bei 1440x900 um ~175px und bei
   1920x1080 um ~11px über - unter anderem, weil clamp(6rem, 10vw, 10rem) bei
   1440px (10vw=144px=9rem) noch fast am Maximum lag und die Exponatziffer bei
   kleineren Breiten anders umbrach. Kleinerer Clamp plus knapperer Kopf-/
   Layoutabstand bringen die Seite ohne Kürzung wieder auf einen Bildschirm. */
.detail-article { padding-top: 8px; }
.detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(320px, .88fr);
  grid-template-rows: auto auto;
  gap: 8px 28px;
  align-items: start;
}
.detail-source { grid-column: 1; grid-row: 1 / span 2; min-width: 0; }
.detail-source-figure { margin: 0; }
.detail-source-copy { display: grid; gap: 4px; margin-top: 6px; color: var(--muted); }
.detail-source-copy a { display: inline-flex; align-items: center; min-height: 44px; width: fit-content; color: var(--ink); }
.detail-heading { grid-column: 2; grid-row: 1; min-width: 0; }
.detail-number {
  display: block;
  color: var(--ink);
  font-size: clamp(3rem, min(6vw, 9vh), 7rem);
  font-weight: 500;
  line-height: .74;
  letter-spacing: -.12em;
  white-space: nowrap;
}
.detail-number small { font-size: .42em; }
.detail-title-block { margin-top: 4px; }
.eyebrow { color: var(--muted); letter-spacing: .03em; }
.detail-title-block h1 { margin-top: 4px; font-size: clamp(2rem, 3vw, 3rem); line-height: 1; }
.detail-difference { max-width: 42ch; margin-top: 4px; font-size: 14px; line-height: 20px; }
.detail-meta {
  display: grid;
  grid-template-columns: minmax(104px, max-content) minmax(0, 1fr);
  gap: 4px 12px;
  margin-top: 8px;
}
.detail-meta__row { display: contents; }
.detail-meta dt { color: var(--muted); }
.detail-meta dd { min-width: 0; color: var(--ink); }
.detail-meta ul { display: flex; flex-wrap: wrap; gap: 0 12px; }
.detail-meta li + li::before { content: "·"; margin-right: 12px; color: var(--muted); }
.status--worked { color: var(--accent-green); }
.status--failed { color: var(--accent-red); }

.detail-workspace { grid-column: 2; grid-row: 2; min-width: 0; }
.player { width: 100%; }
.player-modes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 4px; }
.player-surfaces { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; min-width: 0; }
.track-panel:not([data-active="true"]) { display: none; }
.player[data-mode="schema"] .track-panel--schema,
.player[data-mode="blueprint"] .blueprint-panel { grid-column: 1 / -1; }
.player-figure { margin: 0; }
/* Punkt 10: schlankeres Seitenverhältnis (3/1 statt 18/10) hält die Detailseite
   auf 1440x900 ohne Scrollen - betrifft nur die Bauschema-/Rendering-Fläche
   (Diagramme, keine Fotografie, object-fit: contain zeigt sie unbeschnitten
   und ggf. kleiner statt verzerrt), keine Originalaufnahme. */
.schema-visual,
.rendering-visual,
.blueprint-visual { position: relative; width: 100%; aspect-ratio: 2 / 1; }
.schema-visual,
.rendering-visual,
.blueprint-visual { display: grid; grid-template-rows: minmax(0, 1fr) auto; }
.schema-visual > [data-schema-stack] { position: relative; width: 100%; height: 100%; min-height: 0; background: var(--ground); }
.schema-visual .schema-step { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; object-fit: contain; transition: opacity 400ms ease; }
.schema-visual .schema-step:first-child { opacity: 1; }
.schema-visual .schema-step:not(:first-child) [data-component] > * { opacity: .28; }
.schema-visual .schema-step:not(:first-child) [data-component] [data-new="true"] { opacity: 1; }
.schema-visual .schema-step:first-child [data-component] > * { opacity: 1; }
.schema-visual .image-mark { padding: 4px 0; color: var(--muted); text-align: right; }
.blueprint-visual .image-mark { padding: 4px 0; color: var(--muted); text-align: right; }
/* B1/Punkt 7: die Kennzeichnung des Renderings sitzt als eigenes Element unter der
   Fläche (direktes Kind von .player-figure). Die Fläche trägt seit dem Wegfall
   des weißen Rendering-Grunds trägt die Fläche --ground-lift; die freigestellten
   Renderings (Alphakanal, siehe tools/build.py RENDERING_CWEBP_ARGS) stehen auf
   einer minimal abgesetzten dunklen Stufe statt auf Weiß. */
.player-figure > .image-mark { padding-top: 4px; color: var(--muted); text-align: right; }
/* Punkt 5: .rendering-visual ist nur noch die BÜHNE (feste Fläche, s.o.), die
   Fassung (.frame--fit) zentriert sich darin und umschließt nur den
   tatsächlichen Bildinhalt statt der vollen Fläche. */
/* Gleiche Begründung wie bei .companion-visual oben: align-items bleibt
   stretch, damit die Fassung eine definierte Höhe bekommt und ihre Breite
   über aspect-ratio ableitet, statt über max-width auf volle Breite gezogen
   zu werden. */
/* Die Rendering-Buehne bekommt KEIN festes Seitenverhaeltnis mehr: ihre Hoehe
   folgt der Fassung. Vorher war die Buehne 143px hoch und die Fassung 169px,
   sie ragte oben heraus und ueberdeckte die Registerzeile um 9px. Eine in
   Fensterprozent gesetzte Bildhoehe kann einem breitenabhaengigen
   Seitenverhaeltnis grundsaetzlich nicht folgen. */
.rendering-visual { aspect-ratio: auto; place-items: center; }
.rendering-image { height: calc(17vh - 40px); width: auto; max-width: 100%; min-height: 0; }
.blueprint-visual { background: var(--ground); }
.blueprint-svg { width: 100%; height: 100%; min-height: 0; }
.blueprint-svg .component-group { cursor: pointer; transform-box: fill-box; transform-origin: center; transition: opacity 160ms ease; }
.blueprint-svg.is-interactive .component-group:not([data-active="true"]) { opacity: .35; }
.blueprint-svg.is-interactive .component-group[data-active="true"] { opacity: 1; }
.blueprint-svg .component-group:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.schema-step-limit { margin-top: 4px; color: var(--muted); font-size: 14px; line-height: 20px; }
.component-active { margin-top: 4px; color: var(--ink); font-size: 14px; line-height: 20px; font-weight: 600; }
.schema-legend { margin-top: 4px; color: var(--ink); }
.schema-legend-title { display: block; color: var(--muted); font-size: 14px; line-height: 20px; }
.schema-legend ul { display: flex; flex-wrap: wrap; gap: 0 12px; margin-top: 2px; }
.component-switch { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; color: var(--muted); font-size: 14px; line-height: 20px; text-align: left; }
.component-switch[aria-pressed="true"] { color: var(--ink); font-weight: 600; text-decoration: underline; text-decoration-thickness: 1px; }
.component-color { width: 12px; height: 12px; flex: 0 0 12px; background: var(--component-color); }

.player-controls { margin: 4px 0 0; padding: 0; border: 0; }
.player-controls legend { padding: 0; margin-bottom: 2px; color: var(--muted); font-size: 14px; line-height: 20px; font-weight: 500; }
.step-markers { position: relative; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; min-width: 0; }
.step-markers::before { content: ""; position: absolute; top: 36px; right: 20px; left: 20px; height: 2px; background: var(--ground-lift); pointer-events: none; }
.step-markers::after {
  content: "";
  position: absolute;
  top: 36px;
  left: 20px;
  height: 2px;
  width: calc((100% - 40px) * var(--step-progress, 0));
  background: var(--ink);
  pointer-events: none;
}
.step-marker {
  position: relative;
  z-index: 1;
  display: grid;
  min-width: 44px;
  min-height: 48px;
  padding: 4px;
  align-content: start;
  background: transparent;
  color: var(--muted);
  font-size: 13px;
  line-height: 18px;
  text-align: left;
  transition: color 180ms ease;
}
.step-marker:hover { color: var(--ink); text-decoration: none; }
/* Feste Hoehe fuer die Ziffer, damit die Beschriftung IMMER auf derselben
   Linie beginnt. Vorher rutschte sie bei zweizeiligen Beschriftungen nach
   oben und die Schiene lief mitten durch den Text. */
.step-marker__number { display: block; height: 28px; color: inherit; font-size: 24px; line-height: 28px; font-weight: 600; }
.step-marker span:last-child { padding-top: 14px; overflow-wrap: anywhere; }
.step-marker[aria-current="step"] { color: var(--ink); font-weight: 600; }
.player-copy { margin-top: 4px; }
.step-caption { display: block; max-width: 72ch; color: var(--ink); font-size: 14px; line-height: 20px; }
.step-caption [data-caption-evidence] { color: var(--muted); }
.track-disclosure { margin-top: 2px; color: var(--muted); font-size: 13px; line-height: 18px; }
.live-region { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.track-status { margin-top: 2px; color: var(--muted); }
.fallback-button { margin-top: 2px; color: var(--ink); font-size: 14px; line-height: 20px; }
.no-js-rendering { margin-top: 12px; color: var(--ink); font-size: 16px; line-height: 24px; }
.no-js-rendering summary { min-height: 44px; padding: 8px 0; color: var(--ink); cursor: pointer; }
.no-js-rendering ol { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }
.no-js-rendering a { display: grid; gap: 4px; color: var(--ink); }
.no-js-rendering-image { width: 100%; background: var(--ground-lift); }
noscript { display: block; }

.neighbour-nav { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; }
.neighbour-link { display: grid; min-height: 44px; padding: 2px 0; color: var(--ink); font-size: 16px; line-height: 24px; text-decoration: none; }
.neighbour-link--newer { text-align: right; }
.neighbour-link strong { color: var(--ink); font-weight: 500; }
.detail-footer { margin-top: 8px; padding: 2px 0; }

/* Unter 1600px bricht der rechte Textblock der Detailseiten staerker um und
   schiebt die Seite ueber die Fensterhoehe. Hier wird ausschliesslich an
   Flaechen und Abstaenden gespart, nie an der Schriftgroesse des Fliesstexts
   und nie am Inhalt. */
@media (max-width: 1600px) {
  /* Schmalere Fenster: die Rendering-Buehne gibt Hoehe ab, damit die
     Uebersicht auf einen Schirm passt. */
  .companion-visual { height: 25vh; }
  .companion-image { height: calc(25vh - 40px); }
  /* .rendering-visual bleibt bewusst ohne festes Seitenverhaeltnis, sonst
     ragt die Fassung wieder ueber die Buehne und ueberdeckt das Register. */
  .schema-visual,
  .blueprint-visual { aspect-ratio: 22 / 10; }
  .step-marker { min-height: 44px; }
  .detail-number { font-size: clamp(3rem, min(5vw, 8vh), 6rem); }
  .rendering-image { height: calc(14vh - 40px); }
}

@media (max-width: 959px) {
  :root { --section-gap: 32px; }
  .site-header__inner,
  .overview,
  .detail-article,
  .site-footer__inner { width: auto; margin-right: 20px; margin-left: 20px; }
  .site-header__inner { flex-direction: column; align-items: flex-start; padding-top: 16px; padding-bottom: 8px; gap: 8px; }
  .site-title-group { max-width: 100%; }
  .site-title { max-width: 12ch; font-size: 40px; line-height: 44px; }
  .site-tagline { font-size: 17px; line-height: 23px; }
  .channel-wordmark img { height: auto; width: min(48vw, 260px); }
  .overview {
    padding-top: 20px;
    grid-template-rows: auto auto auto;
    align-content: start;
  }
  .overview-carousel { grid-template-rows: auto auto; }
  .carousel-stage,
  .carousel-viewport { height: auto; }
  .carousel-stage { grid-template-columns: 44px minmax(0, 1fr) 44px; gap: 8px; }
  .carousel-slide { flex-basis: calc(100vw - 152px); transform: scale(.86); }
  .carousel-slide[data-active="true"] { transform: scale(1); }
  .carousel-caption h2 { font-size: 24px; line-height: 28px; }
  .overview-below { grid-template-columns: minmax(0, 1fr); }
  .companion-image { max-height: 24vh; }
  .detail-article { padding-top: 20px; }
  .detail-layout { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; gap: 28px; }
  .detail-source,
  .detail-heading,
  .detail-workspace { grid-column: 1; grid-row: auto; }
  .detail-number { font-size: min(38vw, 9rem); }
  .detail-title-block { margin-top: 16px; }
  .detail-title-block h1 { font-size: 32px; line-height: 36px; }
  .detail-meta { grid-template-columns: minmax(96px, max-content) minmax(0, 1fr); }
  .player-surfaces { grid-template-columns: minmax(0, 1fr); }
  .player[data-mode="schema"] .track-panel--schema,
  .player[data-mode="blueprint"] .blueprint-panel { grid-column: 1; }
  .step-markers { gap: 4px; }
  .step-marker { padding-right: 5px; padding-left: 5px; }
  .carousel-controls { margin-top: 4px; }
  .neighbour-nav { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .neighbour-link--newer { text-align: left; }
  .detail-footer { margin-top: var(--section-gap); padding: 24px 0; }
}

/* Punkt 10: die Detailseite lief bei 1440x900 über, obwohl das Zweispaltenlayout
   bei 1920x1080 genau passt - der Inhalt ist bei beiden Fensterbreiten (>= 960px)
   IDENTISCH groß, nur die verfügbare Höhe unterscheidet sich. Statt die Breite
   (und damit ungewollt den Zeilenumbruch von Titel/Fließtext) anzutasten, greift
   diese Höhen-Media-Query nur unterhalb von 960px Fensterhöhe und verkleinert
   gezielt die Elemente, die am meisten Höhe kosten: Exponatnummer und die
   Bauschema-/Rendering-Fläche (Diagramme, keine Fotografie - object-fit: contain
   zeigt sie dadurch kleiner, nicht zugeschnitten oder verzerrt). min-width:960px
   grenzt gegen das Stapel-Layout der Mobilbreakpoint-Regel oben ab. */
@media (min-width: 960px) and (max-height: 960px) {
  .detail-article { padding-top: 4px; }
  .detail-layout { gap: 4px 28px; }
  .detail-number { font-size: clamp(2.6rem, 4vw, 3.8rem); }
  .detail-title-block { margin-top: 2px; }
  .detail-meta { margin-top: 4px; }
  /* .rendering-visual auch hier ohne festes Seitenverhaeltnis, siehe oben. */
  .schema-visual,
  .blueprint-visual { aspect-ratio: 3 / 1; }
  .player-controls { margin-top: 2px; }
  .player-copy { margin-top: 2px; }
  .detail-footer { margin-top: 4px; padding: 4px 0; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* Twitch-Knopf: die offizielle Markenfarbe #9146FF. Weisse Schrift darauf
   4.64:1, Flaeche gegen den Grund 3.84:1 - beide Schwellen erfuellt. Die
   cremefarbene --ink laege bei 4.12 und damit darunter, deshalb hier
   ausnahmsweise reines Weiss. */
a.twitch-button,
.twitch-button {
  display: inline-flex;
  min-height: 44px;
  gap: 8px;
  align-items: center;
  padding: 0 16px;
  background: #9146ff;
  color: #ffffff;
  text-decoration: none;
  font-size: 15px;
  line-height: 20px;
  font-weight: 600;
}
.twitch-button:hover { background: #a970ff; text-decoration: none; }
.twitch-button:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.twitch-icon { flex: 0 0 auto; }

/* Die Registerzeile sah aus wie Text: unterstrichen wie ein Link, ohne
   erkennbare Flaeche. Jetzt echte Schaltflaechen mit Kontur, die aktive
   gefuellt. */
.player-modes button {
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--ground-lift);
  color: var(--muted);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  text-align: center;
}
.player-modes button:hover { border-color: var(--ink); color: var(--ink); text-decoration: none; }
.player-modes button[aria-selected="true"] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--ground);
  font-weight: 600;
  text-decoration: none;
}

/* Das grosse Beleg-Foto fuehrt zum VOD; der Zeiger und die Fokusmarke machen
   das sichtbar, das Foto selbst bleibt unveraendert. */
.source-link { display: block; cursor: pointer; }
.source-link:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }
/* Die aktive Aufnahme im Karussell fuehrt ebenfalls zur Detailseite. */
.carousel-slide[data-active="true"] .carousel-slide-image { cursor: pointer; }

/* Auffaelliger Rueckweg auf der Detailseite. Bewusst NICHT im warmen Braun:
   das ist die Farbe des einen Wegs zum Exponat. Hier eine kraeftige Kontur in
   Textfarbe - auf dunklem Grund gut sichtbar, ohne eine Bedeutungsfarbe zu
   verbrauchen. */
.back-button {
  display: inline-flex;
  min-height: 44px;
  gap: 10px;
  align-items: center;
  margin-bottom: 8px;
  padding: 0 18px;
  border: 2px solid var(--ink);
  color: var(--ink);
  font-size: 15px;
  line-height: 20px;
  font-weight: 600;
  text-decoration: none;
}
.back-button:hover { background: var(--ink); color: var(--ground); text-decoration: none; }
.back-button:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.back-button-arrow { font-size: 18px; line-height: 1; }
