/* ===== Galerie ==========================================================
   Die Galerie waechst von unten in den Himmel: unten am Bildschirmrand die
   Dialogbox mit der Navigation, direkt darueber die erste Reihe Bilder, und
   von dort aus weiter nach oben. Wieviele Reihen das sind, steht als
   Konstante in index.php (GL_REIHEN) - eine Reihe heisst viele Seiten und
   kein Scrollen, sechs heissen wenig Seiten und ein langer Weg nach oben.

   Warum das so und nicht als eigener Abschnitt ueber der Welt: die
   Startposition der Seite ist die Oberwelt (js/parallax.js), und die
   Startansicht ist exakt der letzte Bildschirm des Dokuments. Ein Element,
   das hier mit "bottom" an #buehne haengt, sitzt dadurch IMMER an derselben
   Stelle der Startansicht - unabhaengig davon, wieviele Reihen darueber
   noch kommen. Genau deshalb landet man nach jedem Blaettern wieder vor
   Bildern und nicht vor leerem Himmel, ganz ohne Scroll-Korrektur.

   Masse durchgehend in Buehneneinheiten (--uw/--uh, siehe
   ../iv/js/buehne.js), nicht in vw/vh: die Galerie skaliert dadurch
   identisch mit der 1280x720-Buehne mit, auch bei Letterboxing. */

/* ----- Kennzahlen ------------------------------------------------------
   Stehen hier und nicht verstreut, weil sie voneinander abhaengen:
   --gl-sockel muss ueber die Dialogbox reichen, --gl-band ueber den
   hoechsten Rahmen plus --gl-spiel. index.php rechnet mit denselben Zahlen
   die Positionen aus (siehe dort: GL_BAND/GL_SPIEL) - wer hier etwas
   aendert, muss es dort mitaendern. */
:root {
    /* Unterkante der untersten Reihe, gemessen vom unteren Bildschirmrand
       der Startansicht. Die Dialogbox sitzt bei 4uh und ist rund 18uh hoch -
       25uh laesst also gut drei Einheiten Luft ueber ihr. */
    --gl-sockel: 25;
    /* Hoehe eines Reihen-Bandes. Der hoechste Rahmen misst rund 36uh, dazu
       das Hoehenspiel - benachbarte Reihen koennen sich dadurch nicht
       ueberlagern, ohne dass irgendwo Abstaende geprueft werden muessen.
       Muessen mit GL_BAND/GL_SPIEL in index.php uebereinstimmen. */
    --gl-band: 42;
    --gl-spiel: 5;
    --gl-rahmen-max: 36;
    /* Wieviel Himmel ueber der obersten Reihe noch scrollbar sein soll.
       Genug, dass die Bilder oben nicht an der Kante kleben - und wenig
       genug, dass man nicht ins Leere weiterscrollt. */
    --gl-luft: 10;
    /* --gl-reihen setzt index.php als Inline-Style an #buehne - der
       Platzhalter oben und die Ebene brauchen den Wert beide. */
}

.gl-galerie {
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(var(--gl-sockel) * var(--uh));
    /* Eigene Hoehe, obwohl alle Kinder absolut positioniert sind: die Seele
       braucht einen Bewegungsraum, und js/galerie.js schneidet ihn auf den
       sichtbaren Teil DIESER Box zu. Ohne Hoehe waere die Box 0 hoch, der
       sichtbare Ausschnitt leer und die Seele wuerde nie starten. Der Wert
       ist genau die Hoehe, die die oberste Reihe hoechstens erreicht. */
    height: calc(
        ((var(--gl-reihen, 1) - 1) * var(--gl-band) + var(--gl-spiel) + var(--gl-rahmen-max)) * var(--uh)
    );
    /* Ueber der Kulisse, aber unter Dialogbox (60) und Lichtbild (90). */
    z-index: 30;
    /* Die Ebene selbst faengt nichts ab - nur die Rahmen darin sind
       anklickbar. Sonst laege ein unsichtbares Rechteck ueber der halben
       Welt. */
    pointer-events: none;
}

/* Die Ebene ist absolut positioniert und macht das Dokument dadurch nicht
   hoeher. Reicht die Galerie hoeher als die Welt, muss das Dokument
   mitwachsen, sonst kaeme man an die obersten Reihen nicht heran. Genau das
   macht dieser leere Platzhalter, der VOR #welt-track steht: er schiebt die
   Welt nach unten und schafft Scrollweg nach oben.

   Die Rechnung: die Galerie-Ebene haengt mit "bottom: --gl-sockel" an
   #buehne, ihre Oberkante liegt also (Sockel + Ebenenhoehe) ueber dem
   Dokumentende. Genau soviel Dokument muss es geben, plus --gl-luft. Was
   #welt-track davon schon mitbringt (200uh minus --oberwelt-kuerzung), faellt
   weg - der Rest ist der Platzhalter.

   Wichtig ist das VOLLE Mass der Welt und nicht nur ihr Himmel-Anteil: hier
   stand frueher 100uh statt 200uh, und weil #welt-track in Wahrheit doppelt
   so hoch ist, blieb ueber der obersten Reihe genau ein Bildschirm leerer
   Himmel zum Weiterscrollen stehen.

   max(0px, ...) statt einer Fallunterscheidung: bei wenigen Reihen kommt
   schlicht 0 heraus und der Platzhalter nimmt keinen Raum ein. Ueber der
   obersten Reihe steht dann der Himmel der Welt selbst - der laesst sich
   nicht kuerzen, ohne die ganze Kulisse zu verschieben. */
.gl-platz-oben {
    height: max(0px, calc(
        (var(--gl-sockel) + (var(--gl-reihen, 1) - 1) * var(--gl-band)
            + var(--gl-spiel) + var(--gl-rahmen-max) + var(--gl-luft)) * var(--uh)
        - (200 * var(--uh) - var(--oberwelt-kuerzung))
    ));
}

/* ----- Ein gerahmtes Bild --------------------------------------------- */

.gl-bild {
    position: absolute;
    left: calc(var(--gl-x) * var(--uw));
    bottom: calc(var(--gl-y) * var(--uh));
    width: calc(var(--gl-b) * var(--uw));
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    display: block;
    cursor: pointer;
    /* Die Ebene darueber schaltet Zeigereignisse ab - hier wieder an. */
    pointer-events: auto;
    /* perspective steht schon im Ruhezustand, obwohl hier nichts gedreht
       wird: das Anstupsen unten kippt den Rahmen zusaetzlich um seine
       senkrechte Achse, und transform ist EINE Eigenschaft - fehlte die
       Perspektive hier, spraenge die Darstellung beim Start der Animation. */
    transform: perspective(800px) rotate(var(--gl-dreh));
    /* Der Rahmen dreht sich um seinen oberen Rand, nicht um die Mitte - so
       wirkt er wie an einem Punkt aufgehaengt und nicht wie schief
       hingelegt. Zugleich der Drehpunkt fuers Wippen weiter unten. */
    transform-origin: 50% 0;
    will-change: transform;
}

/* Aufhaengung: duenner Faden nach oben ins Dunkel. */
.gl-bild::before {
    content: '';
    position: absolute;
    left: 50%;
    bottom: 100%;
    width: 1px;
    height: calc(4 * var(--uh));
    background: linear-gradient(to top, rgba(210, 200, 180, 0.4), rgba(210, 200, 180, 0));
}

/* Der gezeichnete Rahmen. Einziges Element im normalen Fluss und damit das,
   was der Figur ihre Hoehe gibt.

   Der Schein ist hier keine Zierde, sondern die Sichtbarkeit selbst: die
   Rahmen sind schwarze Tusche auf schwarzem Himmel. drop-shadow legt den
   Hof um JEDEN Strich (nicht um das Rechteck des Bildes) - genau das laesst
   die Zeichnung im Dunkeln stehen.

   Zwei gestapelte Schatten, beide weiss: der enge zeichnet die Kontur
   scharf nach, der weite hebt den Rahmen vom Himmel ab. Bewusst neutral
   weiss und nicht in der Theme-Farbe - die Theme-Farbe traegt bereits die
   Ebene mit den Binnenformen darueber (.gl-binnen), und beides zusammen
   waere zuviel des Gleichen. Wieviel Schein, entscheidet --gl-schein-*
   weiter unten. */
.gl-rahmen {
    position: relative;
    display: block;
    width: 100%;
    height: auto;
    /* Reserviert die Box, bevor die SVG geladen ist - der Wert ist genau das
       Seitenverhaeltnis der Datei. Ohne ihn faellt die Figur bis dahin auf
       Nullhoehe zusammen und nimmt das Foto darin mit. */
    aspect-ratio: var(--gl-verh, 1);
    filter:
        drop-shadow(0 0 calc(var(--gl-schein-eng) * var(--uh)) rgba(255, 255, 255, var(--gl-schein-eng-deck)))
        drop-shadow(0 0 calc(var(--gl-schein-weit) * var(--uh)) rgba(255, 255, 255, var(--gl-schein-weit-deck)));
}

/* Drei Staerken zum Vergleichen - eingestellt ueber GL_SCHEIN in
   index.php, das die Klasse hier setzt. Schwarz auf Schwarz ist ein
   schmaler Grat: zu wenig und der Rahmen verschwindet, zu viel und er
   leuchtet wie eine Neonroehre. */
.gl-galerie--schein-leise {
    --gl-schein-eng: 0.5;
    --gl-schein-eng-deck: 0.5;
    --gl-schein-weit: 1.6;
    --gl-schein-weit-deck: 0.3;
}

.gl-galerie--schein-mittel {
    --gl-schein-eng: 0.7;
    --gl-schein-eng-deck: 0.75;
    --gl-schein-weit: 2.6;
    --gl-schein-weit-deck: 0.45;
}

.gl-galerie--schein-kraeftig {
    --gl-schein-eng: 1;
    --gl-schein-eng-deck: 0.95;
    --gl-schein-weit: 4;
    --gl-schein-weit-deck: 0.6;
}

/* Die Binnenformen der Zeichnung - Totenkopf-Augen, Geister-Augen,
   Kuerbisgesicht. Liegt als eigene Ebene UEBER der schwarzen Tusche und
   deckt sie genau dort ab, wo im Original das Weiss sass.

   Der Umweg ueber die Maske hat einen Grund: die Zeichnung kommt als <img>,
   und in eine per <img> geladene SVG reicht das CSS der Seite nicht hinein -
   ihre Farben liessen sich also nicht ans Theme haengen. Hier ist es
   umgekehrt: die Farbe steht im CSS (und damit im Theme), die SVG liefert
   nur die Form. Deckkraft ist alles, was von ihr gebraucht wird. */
.gl-binnen {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: var(--accent-bright);
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    transition: background var(--theme-transition);
}

/* Das Foto sitzt HINTER dem Rahmen, exakt in dessen Oeffnung. Die vier
   Prozentwerte kommen als Inline-Variablen vom Rahmen selbst (siehe
   ../includes/galerie-rahmen.php: 'oeffnung'), damit hier keine zweite,
   mitzupflegende Liste der Rahmenmasse entsteht.

   Bewusst OHNE Farbfilter: die Fotos sollen aus dem dunklen Rahmen heraus
   leuchten. Sie waren frueher entsaettigt und abgedunkelt, damit sie sich
   in den Nachthimmel einfuegen - das half der Kulisse und machte die
   Erinnerungen matt. */
.gl-foto {
    position: absolute;
    left: calc(var(--gl-ol) * 1%);
    top: calc(var(--gl-ot) * 1%);
    width: calc(var(--gl-ow) * 1%);
    height: calc(var(--gl-oh) * 1%);
    object-fit: cover;
}

/* Zwei der vier Rahmen sind Ovale - dort wird das Foto auf dieselbe Ellipse
   beschnitten, die die Oeffnung beschreibt (sie fuellt die Oeffnungsbox
   vollstaendig aus, deshalb genuegen 50%/50%). */
.gl-bild--oval .gl-foto {
    clip-path: ellipse(50% 50% at 50% 50%);
}

/* Video: dieselbe Oeffnung, darueber der Play-Knopf. Vorher stand hier die
   Seele - in Rahmen voller Geister und Totenkoepfe war sie als Zeichen
   allerdings nicht zu erkennen, und dieselbe Seele fliegt ohnehin durch die
   Galerie. Ein Dreieck sagt ohne Umweg, was der Klick tut. */
.gl-video-zeichen {
    position: absolute;
    left: calc(var(--gl-ol) * 1%);
    top: calc(var(--gl-ot) * 1%);
    width: calc(var(--gl-ow) * 1%);
    height: calc(var(--gl-oh) * 1%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: calc(1.4 * var(--uh));
    pointer-events: none;
    background: radial-gradient(ellipse at center,
        rgba(4, 3, 10, 0.25) 0%,
        rgba(4, 3, 10, 0.7) 100%);
}

.gl-bild--oval .gl-video-zeichen {
    clip-path: ellipse(50% 50% at 50% 50%);
}

/* Der Knopf selbst. Die Farbe kommt ueber currentColor aus dem Theme
   (siehe ../sh/js/theme.js) - Lila, Orange, Grau und Weiss faerben ihn
   mit, ohne dass die Zeichnung davon etwas wissen muesste.

   crispEdges ist der Punkt, an dem aus einem Dreieck Pixel-Art wird: ohne
   das rechnet der Browser die Stufen weich aus und die Treppe verschwimmt
   zu einer schraegen Kante. */
.gl-play {
    /* Deutlich kleiner als das Dreieck allein sein muesste: zusammen mit
       der Schrift darunter ergibt beides das Zeichen, und ein Dreieck, das
       die halbe Oeffnung fuellt, verdeckt mehr vom Standbild als noetig. */
    width: calc(2.8 * var(--uw));
    height: auto;
    color: var(--accent-bright);
    shape-rendering: crispEdges;
    filter: drop-shadow(0 0 calc(1.2 * var(--uh)) rgba(0, 0, 0, 0.85));
    transition: color 0.25s ease, transform 0.25s ease;
}

.gl-play-wort {
    font-family: 'Press Start 2P', monospace;
    font-size: clamp(0.5rem, calc(1.1 * var(--uw)), 0.7rem);
    letter-spacing: 0.12em;
    color: var(--accent-bright);
    text-shadow: 0 0 calc(1.2 * var(--uh)) rgba(0, 0, 0, 0.9);
    transition: color 0.25s ease;
}

/* Der ganze Rahmen ist der Knopf, nicht nur das Zeichen - deshalb haengt
   die Reaktion am <button> und nicht am Dreieck. */
.gl-bild:hover .gl-play,
.gl-bild:focus-visible .gl-play {
    color: var(--text);
    transform: scale(1.15);
}

.gl-bild:hover .gl-play-wort,
.gl-bild:focus-visible .gl-play-wort {
    color: var(--text);
}

/* Reaktion, wenn die Seele einen Rahmen streift (Klasse wird von
   js/galerie.js gesetzt und raeumt sich per animationend selbst wieder ab).
   Laeuft ausschliesslich auf transform - kein Layout, kein Paint der
   Umgebung. */
.gl-bild--angestupst {
    animation: gl-wippen 2.4s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}

/* Zwei Bewegungen in einer: das Schaukeln in der Bildebene (rotate) und ein
   Kippen um die senkrechte Achse (rotateY) - als haette der Rahmen einen
   Stoss von der Seite bekommen und pendelte sich wieder ein. Beides muss in
   DIESELBE transform-Angabe, sonst ueberschreibt die eine die andere.

   Das Kippen laeuft etwas nach dem Schaukeln aus (bei 82% steht das
   Schaukeln fast still, das Kippen schwingt noch) - zwei Pendel mit
   leicht verschiedener Dauer wirken lebendiger als ein gleichfoermiges. */
@keyframes gl-wippen {
    0%   { transform: perspective(800px) rotate(var(--gl-dreh)) rotateY(0deg); }
    14%  { transform: perspective(800px) rotate(calc(var(--gl-dreh) + 3.4deg)) rotateY(26deg); }
    34%  { transform: perspective(800px) rotate(calc(var(--gl-dreh) - 2.4deg)) rotateY(-19deg); }
    54%  { transform: perspective(800px) rotate(calc(var(--gl-dreh) + 1.3deg)) rotateY(12deg); }
    72%  { transform: perspective(800px) rotate(calc(var(--gl-dreh) - 0.6deg)) rotateY(-7deg); }
    88%  { transform: perspective(800px) rotate(var(--gl-dreh)) rotateY(3deg); }
    100% { transform: perspective(800px) rotate(var(--gl-dreh)) rotateY(0deg); }
}

/* Beim Seitenwechsel blendet die alte Bestueckung weg und die neue wieder
   ein - ohne das wechselten die Bilder hart, was nach einem Ruckler
   aussieht statt nach einem Wechsel. */
.gl-galerie--wechselt .gl-bild {
    opacity: 0;
    transition: opacity 0.25s ease;
}

.gl-bild {
    transition: opacity 0.35s ease;
}

/* ----- Die Seele -------------------------------------------------------
   Fliegt frei durch den sichtbaren Ausschnitt der Galerie und stupst dabei
   Rahmen an. Bewegt wird sie von js/galerie.js ueber transform. */
.gl-seele {
    /* Absolut IN der Galerie-Ebene, nicht fixed am Bildschirm: js/galerie.js
       rechnet ihre Ziele in den Koordinaten dieser Ebene und beschneidet sie
       auf deren sichtbaren Ausschnitt. Waere sie am Bildschirm festgenagelt,
       klebte sie beim Scrollen an ihm - sie soll aber sanft nachziehen. */
    position: absolute;
    left: 0;
    top: 0;
    /* Exakt die Masse der SPRECHENDEN Seele aus der Einladung
       (../iv/js/verlorene-seele.js: SEELE_ZIEL_HOEHE = 125, mal
       Buehnenbreite / SEELE_REFERENZ_BREITE) - dieselbe Figur soll ueberall
       gleich gross sein, und das ist die Groesse, in der man sie kennt.
       125/1357 der Buehnenbreite sind 9.21 * --uw (--uw ist ein Hundertstel
       davon), also dieselbe Rechnung ohne JavaScript. Hier stand vorher die
       Groesse der TITEL-Seele (.seele-dauerhaft, 165px * --stage-scale =
       12.89 * --uw): die haengt dort im Hintergrund hinter der Ueberschrift
       und darf deshalb groesser sein - frei zwischen den Bildern wirkte sie
       zu gross. */
    height: calc(9.21 * var(--uw));
    width: auto;
    aspect-ratio: 577 / 852;
    z-index: 55;
    opacity: 0.9;
    pointer-events: none;
    /* Weiss, NICHT die Theme-Farbe: die Seele ist eine Figur dieser Welt und
       keine Bedienung. Farbe traegt hier, was man anfassen kann - der
       Play-Knopf, die Jahreszahlen, der Rahmen der Tafel. Bei orangem Theme
       sah sie sonst aus, als glimme sie selbst in Parteifarbe. Die Seele in
       der Einladung (../iv/css/verlorene-seele.css: .seele-dauerhaft) hat
       aus demselben Grund gar keinen farbigen Schein. */
    filter: drop-shadow(0 0 calc(1.2 * var(--uh)) rgba(255, 255, 255, 0.75));
    will-change: transform;
}

.gl-seele.hidden {
    display: none;
}

/* ----- Dialogbox mit der Navigation ------------------------------------
   Masse 1:1 wie die Story-Dialogbox der Einladung (../iv/css/dialog.css) -
   dieselbe Breite, dieselbe Mindesthoehe, dieselbe Optik. Bewusst als
   eigene Klasse und nicht als Wiederverwendung von .dialog-box: die dort
   haengt an js/dialog.js und dessen Zustaenden (tippen, betritt, verlaesst),
   die es hier alle nicht gibt.

   position:fixed statt absolute: die Box bleibt am unteren Bildschirmrand,
   auch wenn man zu den oberen Reihen hochscrollt. Damit braucht es keine
   zweite Navigation oben - es ist dieselbe, sie ist nur immer da. */
.gl-tafel {
    position: fixed;
    left: 50%;
    bottom: clamp(1.5rem, calc(4 * var(--uh)), 3rem);
    transform: translateX(-50%);
    width: min(82%, calc(70.3125 * var(--uw)));
    min-height: calc(18.0556 * var(--uh));
    z-index: 60;
    box-sizing: border-box;
    padding: calc(1.6 * var(--uh)) calc(2.4 * var(--uw));

    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: calc(1.4 * var(--uh));

    background: rgba(8, 6, 14, 0.85);
    border: 2px solid var(--accent-bright);
    border-radius: 6px;
    box-shadow:
        0 12px 40px rgba(0, 0, 0, 0.75),
        0 0 35px rgba(0, 0, 0, 0.5),
        inset 0 0 25px rgba(0, 0, 0, 0.5);
    transition: border-color var(--theme-transition);
}

/* Der Weg zur Einladung. Sitzt in der linken UNTEREN Ecke der Tafel, der
   Ton-Knopf in der rechten oberen - beide gehoeren zur Galerie als Ganzes
   und nicht zum Blaettern, deshalb stehen sie aus der Mitte heraus.

   Bewusst zurueckhaltender als die Pfeile: ein Ausgang, den man findet, wenn
   man ihn sucht, und der einem nicht staendig anbietet zu gehen. */
.gl-heim {
    position: absolute;
    bottom: calc(1.6 * var(--uh));
    left: calc(2 * var(--uw));
    font-family: 'Press Start 2P', monospace;
    font-size: clamp(0.45rem, calc(1 * var(--uw)), 0.6rem);
    letter-spacing: 0.04em;
    text-decoration: none;
    color: var(--text-dim);
    opacity: 0.75;
    transition: color 0.25s ease, opacity 0.25s ease;
}

.gl-heim:hover,
.gl-heim:focus-visible {
    color: var(--accent-bright);
    opacity: 1;
}

/* Jahrgang. Nur vorhanden, wenn mehr als ein Ordner ueberhaupt Bilder
   enthaelt - ein einzelner Jahresknopf, der auf sich selbst zeigt, waere
   nur Beiwerk. */
.gl-jahre {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: calc(2.4 * var(--uw));
}

.gl-jahr {
    font-family: 'Press Start 2P', monospace;
    font-size: clamp(0.55rem, calc(1.4 * var(--uw)), 0.75rem);
    text-decoration: none;
    color: var(--text-dim);
    transition: color 0.3s ease, text-shadow 0.3s ease;
}

.gl-jahr:hover,
.gl-jahr:focus-visible {
    color: var(--accent-bright);
}

.gl-jahr--hier {
    color: var(--accent-bright);
    text-shadow: 0 0 calc(1.6 * var(--uh)) var(--accent);
}

/* Pfeile und Seitenstand in einer Zeile. */
.gl-blaettern {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: calc(2.4 * var(--uw));
}

.gl-pfeil {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: calc(4.4 * var(--uw));
    height: calc(7 * var(--uh));
    font-family: 'Press Start 2P', monospace;
    font-size: clamp(0.7rem, calc(1.8 * var(--uw)), 1rem);
    line-height: 1;
    text-decoration: none;
    color: var(--text);
    background: rgba(8, 6, 14, 0.6);
    border: 2px solid var(--accent-bright);
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.2s ease, transform 0.15s ease;
}

.gl-pfeil:hover {
    background: var(--accent);
    transform: translateY(-2px);
}

.gl-pfeil:active {
    transform: translateY(0);
}

/* Am Anfang bzw. Ende bleibt der Pfeil stehen, statt zu verschwinden - die
   Box soll beim Blaettern nicht die Breite wechseln. */
.gl-pfeil--aus {
    opacity: 0.25;
    pointer-events: none;
    border-color: rgba(232, 223, 198, 0.3);
}

.gl-stand {
    font-family: 'Press Start 2P', monospace;
    font-size: clamp(0.55rem, calc(1.4 * var(--uw)), 0.75rem);
    line-height: 1.6;
    color: var(--text);
    text-align: center;
    min-width: calc(24 * var(--uw));
}

.gl-stand-klein {
    display: block;
    margin-top: calc(0.8 * var(--uh));
    font-size: 0.8em;
    color: var(--text-dim);
}

/* ----- Lichtbild: ein Bild gross --------------------------------------
   Ohne Rahmen. Der Rahmen ist Deko fuer die Wand - wer ein Bild ansieht,
   will das Bild. Fotos und Videos teilen sich dieselbe Huelle und dieselbe
   Reihenfolge: die Pfeile laufen durch ALLE Eintraege des Jahrgangs, nicht
   nur durch die neun der aktuellen Seite. Die Seiteneinteilung ist eine
   Eigenschaft der Wand, nicht der Bilder. */
.gl-lichtbild[hidden] {
    display: none;
}

.gl-lichtbild {
    position: fixed;
    inset: 0;
    z-index: 90;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(2, 2, 6, 0.94);
}

.gl-lichtbild-buehne {
    position: relative;
    width: calc(84 * var(--uw));
    height: calc(84 * var(--uh));
    display: flex;
    align-items: center;
    justify-content: center;
}

.gl-lichtbild-buehne img,
.gl-lichtbild-buehne video {
    max-width: 100%;
    max-height: 100%;
    box-shadow: 0 0 calc(4 * var(--uh)) rgba(0, 0, 0, 0.9);
}

.gl-lichtbild-buehne video {
    background: #000;
}

.gl-lb-knopf {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: calc(4.4 * var(--uw));
    height: calc(9 * var(--uh));
    font-family: 'Press Start 2P', monospace;
    font-size: clamp(0.7rem, calc(1.8 * var(--uw)), 1rem);
    line-height: 1;
    color: var(--text);
    background: rgba(8, 6, 14, 0.75);
    border: 2px solid var(--accent-bright);
    border-radius: 6px;
    cursor: pointer;
    z-index: 2;
    transition: background 0.2s ease;
}

.gl-lb-knopf:hover {
    background: var(--accent);
}

.gl-lb-zurueck { left: calc(2 * var(--uw)); }
.gl-lb-weiter  { right: calc(2 * var(--uw)); }

.gl-lb-zu {
    position: absolute;
    top: calc(2.4 * var(--uh));
    right: calc(2.4 * var(--uw));
    width: calc(4.4 * var(--uw));
    height: calc(7 * var(--uh));
    font-family: 'Press Start 2P', monospace;
    font-size: clamp(0.7rem, calc(1.8 * var(--uw)), 1rem);
    line-height: 1;
    color: var(--text);
    background: rgba(8, 6, 14, 0.75);
    border: 2px solid var(--accent-bright);
    border-radius: 6px;
    cursor: pointer;
    z-index: 2;
}

.gl-lb-zu:hover {
    background: var(--accent);
}

.gl-lb-stand {
    position: absolute;
    left: 50%;
    bottom: calc(1.6 * var(--uh));
    transform: translateX(-50%);
    font-family: 'Press Start 2P', monospace;
    font-size: clamp(0.5rem, calc(1.2 * var(--uw)), 0.7rem);
    color: var(--text-dim);
    z-index: 2;
}

/* ----- Bewegungsreduktion ---------------------------------------------
   Gleiche Haltung wie im Rest des Projekts: sichtbar und bedienbar bleibt
   alles, nur die Bewegung faellt weg. */
@media (prefers-reduced-motion: reduce) {
    .gl-seele {
        display: none;
    }

    .gl-bild--angestupst {
        animation: none;
    }

    .gl-bild,
    .gl-pfeil,
    .gl-jahr,
    .gl-play,
    .gl-lb-knopf {
        transition: none;
    }

    /* Der Knopf bleibt sichtbar und bedienbar, er waechst beim Zeigen nur
       nicht mehr. */
    .gl-bild:hover .gl-play,
    .gl-bild:focus-visible .gl-play {
        transform: none;
    }
}
