/* =========================================================================
   fango – Kulturforum Cottbus e.V.
   Design-Tokens 1:1 aus stage.froodmat.com uebernommen (Bricks-Theme-Styles).
   Basis: root = 10px, damit die rem-Werte der fluiden Scale stimmen.
   ========================================================================= */

@font-face{font-family:Delight;src:url(/assets/fonts/Delight-Regular.woff2)format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Delight;src:url(/assets/fonts/Delight-Black.woff2)format("woff2");
  font-weight:900;font-style:normal;font-display:swap}
@font-face{font-family:"IBM Plex";src:url(/assets/fonts/IBMPlexSans-Regular.woff2)format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"IBM Plex";src:url(/assets/fonts/IBMPlexSans-Bold.woff2)format("woff2");
  font-weight:700;font-style:normal;font-display:swap}

/* ---------- Belichtung ----------
   Die Bar meldet, ob ihr Licht an ist. Die Seite zeigt das nicht an einer Stelle,
   sondern als Belichtung des ganzen Raums: `--belichtung` ist eine Zahl zwischen
   0 und 1, und jede Flaeche, jede Linie, jedes Weiss und jede Kategoriefarbe wird
   daraus abgeleitet. Es gibt keinen zweiten Satz Farbwerte - es gibt eine Skala.

   Zwei Belichtungen, drei Zustaende: "dunkel" und "unbekannt" sind optisch
   identisch (Belichtung 0), weil die Seite im zweiten Fall nichts weiss und
   deshalb nichts behaupten darf. Der Unterschied steht im Satz, nicht im Licht.

   Gerechnet wird in OKLCH, weil hier Helligkeit tatsaechlich Helligkeit ist:
   dieselbe Rechnung auf sechs verschiedene Farbtoene angewandt hebt sie
   wahrnehmbar gleich weit an. In sRGB waere die Rechnung dieselbe und das
   Ergebnis sechsmal verschieden.

   Alle Paarungen sind fuer beide Belichtungen nachgerechnet und liegen ueber
   4,5:1 - der engste Fall ist Ausstellungsgrau auf der hellen Wand mit 4,64. */
@property --licht{syntax:"<number>";inherits:true;initial-value:0}
@property --nah{syntax:"<number>";inherits:true;initial-value:1}
@property --belichtung{syntax:"<number>";inherits:true;initial-value:0}
/* Die Lampe haengt am Kabel: --lampe-dehnung streckt ihr Feld zur Zugrichtung
   hin, --lampe-drehung dreht diese Richtung ins Bild. In Ruhe: rund und gerade. */
@property --lampe-dehnung{syntax:"<number>";inherits:true;initial-value:1}
@property --lampe-drehung{syntax:"<angle>";inherits:true;initial-value:0deg}
@property --koernung{syntax:"<number>";inherits:true;initial-value:.42}
/* Getypt, damit zeiger.js die beiden Ringmasse als Pixel auslesen kann und
   die Zahlen dort bleiben, wo alle anderen Masse stehen. */
@property --ring-weit{syntax:"<length>";inherits:true;initial-value:36px}
@property --ring-eng{syntax:"<length>";inherits:true;initial-value:22px}

:root{
  /* --licht ist der Zustand des Raums: brennt das Barlicht oder nicht.
     --nah ist der Anteil davon, der an dieser Stelle ankommt.
     --belichtung ist das Produkt - und bleibt damit die eine Zahl, aus der
     jede Farbe abgeleitet wird. Wer --nah nicht anfasst, sieht genau das
     Verhalten von vorher. */
  --licht:0;
  --nah:1;
  --belichtung:calc(var(--licht) * var(--nah));

  /* Der Ort der Lampe. Ihre Ruhelage ist kein runder Wert, sondern eine
     Stelle in der Marke: der Mittelpunkt der Spirale im Affenlogo. Von dort
     kommt das Licht, und dorthin geht es zurueck, wenn es niemand mitnimmt.
     Die beiden Anteile sind an der Logoflaeche gemessen; zeiger.js liest sie
     hier aus und rechnet sie bei jedem Umbruch in Fensterkoordinaten um.
     Ohne Skript - und auf groben Zeigern, die keinen haben - bleibt der
     statische Ersatz stehen: dieselbe Stelle bei 21rem Logohoehe. */
  --spirale-x:33%;
  --spirale-y:50%;
  --logo-hoehe:21rem;
  --lampe-x:calc(50vw - var(--logo-hoehe) * 488 / 1053 * .17);
  --kopf-oben:var(--takt-zeile);
  --lampe-y:calc(var(--kopf-oben) + var(--logo-hoehe) / 2);

  /* Groesse des Lichtfeldes. Sie steht hier als Zahl, weil nicht nur der
     Verlauf sie braucht, sondern auch die Lage, die ihn traegt. */
  --lampe-weite:122rem;
  --lampe-hoehe:82rem;
  --koernung:.42;

  /* Die eine Handschrift fuer jede Rueckmeldung auf eine Handlung: 180 ms,
     ease-out-cubic. Das eingebaute ease startet traege und endet traege - bei
     dieser Dauer kaum sichtbar, aber spuerbar weicher, als es sein muesste.
     Die Kurve steht hier einmal, damit sie nicht an sechs Stellen driftet. */
  --takt-hover:.18s;
  --kurve-hover:cubic-bezier(.33,1,.68,1);

  /* Der zweite Takt, und der letzte: der Weg. Er gilt allem, was von einer
     Stelle an eine andere geht - der wandernde Titel, der Jahressprung, das
     Bild auf dem Weg in die Nahsicht, die Spalte, die sich aufhaengt. Eine
     Verzoegerungskurve, keine Feder: ein Plakat federt nicht.

     Zwei Dauern, eine Bewegung. Der Hinweg nimmt sich Zeit, der Rueckweg
     nicht - wer zurueckkommt, war schon da. Die Zahlen standen bis hierher
     als Literale an vier Stellen; jetzt stehen sie einmal. */
  --takt-weg:.42s;
  --takt-rueckweg:.28s;
  --kurve-weg:cubic-bezier(.16,1,.3,1);

  /* Farben - die Werte hier sind der Rueckfall fuer Browser ohne oklch();
     dort bleibt die Seite dunkel, und das ist der richtige Rueckfall:
     im Zweifel nichts behaupten. */
  --background:#1A1A1A;
  /* Der Grund traegt kein Licht mehr - das Licht liegt als eigenes Feld
     darueber. Beide Werte sind der Rueckfall fuer Browser ohne oklch(). */
  --wand:#1A1A1A;
  --wand-hell:#37322C;
  --sandlicht:#2F2A24;
  /* Der Gluehton: die Farbe der Quelle selbst. Er steht hier und nicht in
     bar.css, obwohl ihn beide Blaetter brauchen - genau deshalb. Auf der
     Seite traegt ihn das Zeichen im Kopf, in der Bar der Kern des Scheins
     und dasselbe Zeichen an der Lampe. Es ist eine Lampe, von zwei Seiten
     gesehen; sie hat eine Farbe und nicht zwei. */
  --gluehton:#FFCE91;
  --textfarbe:#FFFFFF;
  --titelfarbe:#F5F5F5;
  --primary:#C40909;        /* Flaeche: Punkt, Ticket-Hover, Auswahl, Zitatstrich */
  --primary-hell:#F54747;   /* Text auf dem Grund: 4,87:1. Gleicher Farbton, nur hell genug. */
  --dunkel:#212121;
  --linie:rgba(255,255,255,.25);          /* jede Trennung im System */
  --text-gedaempft:rgba(255,255,255,.75); /* Unterstuetzer-Angaben */
  --text-still:rgba(255,255,255,.55);     /* Leermeldungen */
  --trennpunkt:rgba(255,255,255,.35);     /* Punkte zwischen Metaangaben */

  /* Kategoriefarben. Neun statt sechs, seit das Programm aus Mobilizon kommt -
     die Liste ist die des Hauses, nicht die der Instanz. Reihenfolge nach
     Gewicht: was oft stattfindet, steht oben. */
  --farbe-konzert:#FFA0D3;
  --farbe-kunst:#FFC767;
  --farbe-workshop:#E9E46F;
  --farbe-ausstellung:#AC9B8B;
  --farbe-treffen:#97A5C2;
  --farbe-party:#AF87F1;
  --farbe-wort:#8DF67B;
  --farbe-politisches:#7EC0B3;
  --farbe-kino:#81D4FA;
  --farbe-default:#F5F5F5;

  /* Fluide Typo-Scale (Originalwerte der Live-Seite) */
  --title:clamp(5.88rem, 4.25cqi + 4.52rem, 7.47rem);
  /* Auf der Detailseite gilt dieselbe Rechnung wie unten bei --h2, nur mit
     einem anderen Boden: die beiden zu langen Woerter passen dort (Spalte
     341px) ab 28.9px bzw. 26.2px - und darunter waere der Titel der
     Einzelseite kleiner als derselbe Titel in der Liste (--h2, 31.6px). */
  --h1:clamp(3.91rem, 1.21vi + 3.52rem, 5.21rem);
  /* --h2 bleibt am Telefon, wie es ist - nachgerechnet, nicht vermutet.
     Seit die automatische Trennung aus ist, wird ein Wort, das breiter ist als
     seine Spalte, strichlos mitten durchgeschnitten. Bei 375px trifft das genau
     zwei von 33 Titeln im Rueckblick. Damit sie ganz auf die Zeile kommen,
     muesste --h2 auf 24px (»Performancebuehne«) bzw. 21px (»Grenzueber-
     schreitung«, 20 Zeichen) - und --text-xl haelt das Datum eine Zeile
     darueber bei 375px auf 26px fest. Der Titel wuerde also kleiner als sein
     eigenes Datum, um zwei Woerter zu retten. Ein geschnittenes Wort ist
     billiger als eine umgedrehte Rangfolge. */
  --h2:clamp(3.13rem, 0.73vi + 2.89rem, 3.91rem);
  --h3:clamp(2.5rem, 0.4vi + 2.37rem, 2.93rem);
  --h4:clamp(2rem, 0.19vi + 1.94rem, 2.2rem);
  --h5:clamp(1.6rem, 0.05vi + 1.59rem, 1.65rem);
  --h6:clamp(1.28rem, -0.04vi + 1.29rem, 1.24rem);
  --text-xxl:clamp(2.6rem, 0.79vi + 1.77rem, 5.0rem);
  --text-xl:clamp(2.6rem, 0.79vi + 1.77rem, 4.0rem);
  --text-l:clamp(1.8rem, 0.56vi + 1.62rem, 2.4rem);
  --text-m:clamp(1.6rem, 0.37vi + 1.48rem, 2rem);
  --text-s:clamp(1.42rem, 0.23vi + 1.35rem, 1.67rem);
  --text-xs:clamp(1.26rem, 0.12vi + 1.23rem, 1.39rem);

  --grid-gap:clamp(16px, calc(10.182px + 1.818vw), 50px);

  /* Die Breite einer Randspur der Reihe. Sie ist ein Rand der Wand und kein
     Aufsatz darauf: der Artikel rueckt ab 1180px um diesen Wert von beiden
     Waenden ab, und genau dort haengen die beiden Nachbartermine. */
  --spur:11rem;

  /* Der senkrechte Takt. Vier Schritte, und nur diese vier. Vorher standen
     sieben im Stylesheet, von denen vier - 25, 30, 34, 35, 40 px - so dicht
     beieinander lagen, dass kein Auge sie auseinanderhaelt. Ein Takt, den man
     nicht unterscheiden kann, ist keiner: er kostet die Kadenz und bringt
     nichts dafuer. Auf dem Telefon faellt allein --takt-block auf 30 px, und
     alles, was daran haengt, faellt mit. */
  --takt-eng:1.2rem;    /* zwischen zwei Zeilen derselben Leiste */
  --takt-zeile:2.6rem;  /* in der Zeile, und zwischen Leiste und Liste */
  --takt-block:5rem;    /* zwischen Bloecken */
  --takt-fuss:6rem;     /* vor dem Fuss */
}

/* Licht an: die einzige Stelle, an der der Raumzustand gesetzt wird. */
:root[data-licht=an]{--licht:1}

@supports (color:oklch(0 0 0)){
  /* Die Skala der Seite. Sie wird einmal gerechnet.

     Bis hierher stand die Programmzeile im selben Selektor und leitete jede
     dieser Farben ein zweites Mal ab - neun Kategoriefarben darunter, von denen
     eine Zeile hoechstens eine benutzt. Weil --nah waehrend des Scrollens in
     jedem Bild einen neuen Wert bekommt, hing daran die vollstaendige
     Neuberechnung jeder sichtbaren Zeile samt ihrem Teilbaum, im Hauptthread,
     waehrend der Finger zieht. Auf dem Schreibtisch faellt das nicht auf; auf
     einem aelteren Telefon war es die teuerste Stelle der Seite.

     Die Zeile rechnet jetzt nur noch, was sie zeigt, und nur dann, wenn Licht
     da ist - siehe die beiden Regeln unter dieser hier. Gerechnet wird
     dieselbe Skala mit denselben Zahlen; es faellt nichts weg als die Arbeit,
     die niemand gesehen hat. */
  :root{
    --belichtung:calc(var(--licht) * var(--nah));

    /* Der Warmton des Barlichts. 72 Grad ist Gluehlicht; das Chroma bleibt so
       niedrig, dass die Wand heller wird, statt in einen Erdton zu kippen. */
    --lichtton:72;
    --kat-heller:calc(.065 * var(--belichtung));
    --kat-satter:calc(1 + .08 * var(--belichtung));

    /* Licht faellt auch auf die Schrift: die beiden Weiss nehmen den Warmton
       auf, statt kalt vor einer warmen Wand zu stehen. */
    --textfarbe:oklch(calc(1 - .005 * var(--belichtung))
                      calc(.005 * var(--belichtung)) var(--lichtton));
    --titelfarbe:oklch(.9702 calc(.006 * var(--belichtung)) var(--lichtton));

    /* Ein beleuchteter Raum zeigt seine Kanten deutlicher. */
    --linie:rgba(255,255,255,calc(.25 + .07 * var(--belichtung)));
    --trennpunkt:rgba(255,255,255,calc(.35 + .07 * var(--belichtung)));
    --text-gedaempft:rgba(255,255,255,calc(.75 + .05 * var(--belichtung)));
    --text-still:rgba(255,255,255,calc(.55 + .07 * var(--belichtung)));

    /* Die neun Kategoriefarben, dieselbe Rechnung neunmal: etwas heller und
       etwas satter, Farbton unangetastet. Farbe existiert erst im Licht.

       Die Sattheit erzaehlt das Gewicht. Konzert traegt volles Chroma, weil das
       Haus vor allem Konzerte macht; Treffen und Ausstellung liegen knapp
       ueber Grau, weil sie den Alltag beschreiben und nicht den Anlass. Eine
       Ausstellung ist der Normalzustand einer Galerie - sie ist die Wand.
       Deshalb steht sie auf dem Sandton der Wand (Farbton 66) und nicht auf
       einer eigenen Farbe.

       Alle neun liegen ueber 6:1 gegen den unbelichteten Grund; Licht hebt sie,
       es senkt sie nie. Die Hexwerte oben sind dieselben Farben ohne Licht.

       --kat-heller steht auf 0.065 statt 0.020, seit der Lichtkern auf 0.320
       liegt: die Farben steigen mit der Wand, statt von ihr eingeholt zu
       werden. Sie steigen sogar etwas schneller als sie - deshalb ist der
       Aufschlag mehr als das Dreifache des alten, und deshalb gewinnt jede
       Paarung auf der belichteten Wand gegenueber vorher.

       Im Kern selbst - der hellsten Stelle der ganzen Seite - liegt die
       schwaechste Paarung (Party) bei 5,7:1 und Ausstellung bei 6,0:1; auf
       der belichteten Wand stehen alle neun zwischen 6,8:1 und 14,0:1, auf
       dem unbelichteten Grund zwischen 6,3:1 und 13,2:1. */
    /* Die Zahlen stehen ab hier als Zahlen da und nicht mehr nur in den neun
       Farben. Das ist keine Umsortierung, sondern die Voraussetzung dafuer,
       dass eine Programmzeile ihre eine Farbe selbst ausrechnen kann, ohne
       dass die Tabelle ein zweites Mal im Stylesheet steht. Wer einen Wert
       aendert, aendert ihn weiterhin an genau einer Stelle - und die
       nachgerechneten Kontraste oben gelten fuer beide Wege, weil beide
       dieselbe Rechnung sind. */
    --l-konzert:.8160;     --c-konzert:.1280;     --h-konzert:346.9;
    --l-kunst:.8613;       --c-kunst:.1300;       --h-kunst:79.1;
    --l-workshop:.9000;    --c-workshop:.1400;    --h-workshop:107;
    --l-ausstellung:.7000; --c-ausstellung:.0300; --h-ausstellung:66;
    --l-treffen:.7200;     --c-treffen:.0450;     --h-treffen:265;
    --l-party:.7050;       --c-party:.1550;       --h-party:300;
    --l-wort:.8822;        --c-wort:.1883;        --h-wort:140.8;
    --l-politisches:.7600; --c-politisches:.0700; --h-politisches:180;
    --l-kino:.8308;        --c-kino:.0969;        --h-kino:229.1;

    --farbe-konzert:oklch(calc(var(--l-konzert) + var(--kat-heller)) calc(var(--c-konzert) * var(--kat-satter)) var(--h-konzert));
    --farbe-kunst:oklch(calc(var(--l-kunst) + var(--kat-heller)) calc(var(--c-kunst) * var(--kat-satter)) var(--h-kunst));
    --farbe-workshop:oklch(calc(var(--l-workshop) + var(--kat-heller)) calc(var(--c-workshop) * var(--kat-satter)) var(--h-workshop));
    --farbe-ausstellung:oklch(calc(var(--l-ausstellung) + var(--kat-heller)) calc(var(--c-ausstellung) * var(--kat-satter)) var(--h-ausstellung));
    --farbe-treffen:oklch(calc(var(--l-treffen) + var(--kat-heller)) calc(var(--c-treffen) * var(--kat-satter)) var(--h-treffen));
    --farbe-party:oklch(calc(var(--l-party) + var(--kat-heller)) calc(var(--c-party) * var(--kat-satter)) var(--h-party));
    --farbe-wort:oklch(calc(var(--l-wort) + var(--kat-heller)) calc(var(--c-wort) * var(--kat-satter)) var(--h-wort));
    --farbe-politisches:oklch(calc(var(--l-politisches) + var(--kat-heller)) calc(var(--c-politisches) * var(--kat-satter)) var(--h-politisches));
    --farbe-kino:oklch(calc(var(--l-kino) + var(--kat-heller)) calc(var(--c-kino) * var(--kat-satter)) var(--h-kino));
    --farbe-default:var(--titelfarbe);
  }

  /* ---------- Was eine Zeile davon selbst rechnet ----------

     Erstens: ihre eine Kategoriefarbe. Die Klasse kommt aus dem Markup
     (eventzeile.php) und traegt nur die drei Zahlen ihrer Kategorie herein;
     die Rechnung darunter ist wortgleich die von oben. Eine Zeile ohne
     Kategorieklasse - eine Kategorie mit eigener Farbe aus dem Panel - laesst
     var(--kat-l) ins Leere laufen, --akzent wird damit ungueltig, und
     var(--akzent, var(--farbe-default)) greift wie bisher auf den Rueckfall
     zurueck. Genau dort steht dann die fertige Farbe aus dem style-Attribut,
     und die gewinnt als Inline-Wert ohnehin.

     Diese Regel steht ausserhalb der Lichtabfrage: die Kategoriefarbe gilt
     auch im dunklen Raum. Ohne Licht ist --kat-heller null und --kat-satter
     eins, beide von der Wurzel und beide unveraenderlich - dann rechnet die
     Zeile diese Farbe genau einmal und nie wieder. */
  .kat-konzert{--kat-l:var(--l-konzert);--kat-c:var(--c-konzert);--kat-h:var(--h-konzert)}
  .kat-kunst{--kat-l:var(--l-kunst);--kat-c:var(--c-kunst);--kat-h:var(--h-kunst)}
  .kat-workshop{--kat-l:var(--l-workshop);--kat-c:var(--c-workshop);--kat-h:var(--h-workshop)}
  .kat-ausstellung{--kat-l:var(--l-ausstellung);--kat-c:var(--c-ausstellung);--kat-h:var(--h-ausstellung)}
  .kat-treffen{--kat-l:var(--l-treffen);--kat-c:var(--c-treffen);--kat-h:var(--h-treffen)}
  .kat-party{--kat-l:var(--l-party);--kat-c:var(--c-party);--kat-h:var(--h-party)}
  .kat-wort{--kat-l:var(--l-wort);--kat-c:var(--c-wort);--kat-h:var(--h-wort)}
  .kat-politisches{--kat-l:var(--l-politisches);--kat-c:var(--c-politisches);--kat-h:var(--h-politisches)}
  .kat-kino{--kat-l:var(--l-kino);--kat-c:var(--c-kino);--kat-h:var(--h-kino)}

  /* `.art` steht mit hier und nicht ein zweites Mal in bewerbung.css: die drei
     Arten der Bewerbung sind zwei Kategorien des Hauses und eine, die keine
     ist, und ihr Punkt ist dasselbe Zeichen wie auf der Achse des Rueckblicks.
     Die neun Zahlen liegen oben; wer sie ein zweites Mal ausrechnet, hat sie
     ein zweites Mal. Die Belichtungs-Regel darunter fasst `.art` nicht an -
     die Bewerbungsflaechen stehen fest auf `data-licht="aus"`, dort waere sie
     eine Rechnung ohne Ergebnis. */
  /* Die Randspuren und die Nachbarn am Fuss stehen mit hier: sie zeigen die
     Kategorie ihres Nachbartermins und tragen dessen Klasse. Was sie *nicht*
     mitbekommen, ist der Lichtabfall der Liste - sie sind keine Zeile in
     einem Strom, sondern zwei Stellen am Rand einer Seite. Sie rechnen darum
     mit --kat-heller und --kat-satter der Wurzel, also mit der Belichtung des
     Raums, und nicht mit einem eigenen --nah. */
  .zeile,.achsenzeile,.art,.reihe-spur,.reihe-nachbar{
    --akzent:oklch(calc(var(--kat-l) + var(--kat-heller))
                   calc(var(--kat-c) * var(--kat-satter)) var(--kat-h));
  }

  /* Zweitens: alles, was tatsaechlich auf Licht reagiert - aber nur, wenn
     welches da ist. Bei --licht:0 ist --belichtung null, ganz gleich wo --nah
     gerade steht; jede dieser Zeilen ergaebe dann Wert fuer Wert dasselbe wie
     die Wurzel, aus der sie sonst geerbt wird. Die Abfrage nimmt also keine
     Farbe weg, sie nimmt eine Rechnung weg, deren Ergebnis feststeht.

     Was hier steht, ist genau das, was eine Zeile zeigt: den Titel, die
     Haarlinie unter ihr, die Punkte zwischen den Metaangaben und den Rueckfall
     ihrer Kategoriefarbe. Die neun Farben, die Wandfarben und der Rest der
     Skala bleiben oben an der Wurzel, wo sie einmal gerechnet werden. */
  :root[data-licht=an] .zeile,
  :root[data-licht=an] .achsenzeile{
    --belichtung:calc(var(--licht) * var(--nah));
    --kat-heller:calc(.065 * var(--belichtung));
    --kat-satter:calc(1 + .08 * var(--belichtung));
    --textfarbe:oklch(calc(1 - .005 * var(--belichtung))
                      calc(.005 * var(--belichtung)) var(--lichtton));
    --titelfarbe:oklch(.9702 calc(.006 * var(--belichtung)) var(--lichtton));
    --linie:rgba(255,255,255,calc(.25 + .07 * var(--belichtung)));
    --trennpunkt:rgba(255,255,255,calc(.35 + .07 * var(--belichtung)));
    --farbe-default:var(--titelfarbe);
  }

  /* Der Rest der Skala haengt an der Seite, nicht an der einzelnen Zeile. */
  :root{
    /* Die Wand als Flaechenfarbe fuer Bedienelemente. 0.216 ist #1A1A1A;
       bei voller Belichtung steht sie auf 0.266. Der Seitengrund nimmt sie
       nicht mehr - der traegt --wand und bekommt sein Licht aus dem Lichtfeld.

       --wand-hell ist der Kern dieses Feldes und steht seit der helleren
       Lampe auf 0.320, nicht mehr auf 0.266: der Abstand zur unbelichteten
       Wand ist damit 0.104 statt 0.050 - die Lampe wirft gut das Doppelte.
       Der Kern liegt oben am Zeichen; was dort noch Schrift traegt, ist
       unten in den Kontrasten nachgerechnet. */
    --background:oklch(calc(.216 + .050 * var(--belichtung))
                       calc(.009 * var(--belichtung)) var(--lichtton));
    --wand:oklch(.216 0 var(--lichtton));
    --wand-hell:oklch(.320 .013 var(--lichtton));

    /* Der Sandboden wirft zurueck, was auf ihn faellt. Er ist nicht heller als
       die belichtete Wand - er ist waermer: die Helligkeit bleibt bei 0.285,
       damit der Kontrastboden auch am Fussende gilt, das Chroma steigt dafuer
       auf mehr als das Dreifache der Wand. Sand ist kein Weiss. */
    --sandlicht:oklch(.285 .032 66);

    /* Farbton 72 wie alles Licht hier, und .88 .095 ist die aeusserste Kante
       von sRGB bei diesem Farbton: heller ginge nur blasser, und eine
       blassere Quelle ist keine hellere. */
    --gluehton:oklch(.88 .095 72);

    /* Rot als Schrift auf dem Grund verliert Kontrast, sobald die Wand steigt -
       #F54747 faellt dort auf 4,27:1. Es steigt darum mit. Die Flaechenfarbe
       --primary bleibt, wo sie ist: eine Flaeche wird nicht mitbelichtet.

       Der Aufschlag ist 0.100 statt 0.030, seit der Lichtkern auf 0.320 liegt:
       mit 0.030 waere Rot im Kern auf 4,0:1 gefallen und damit unter AA.
       Jetzt steht es dort auf 4,55:1 und auf der belichteten Wand auf 5,4:1;
       unbelichtet bleibt es unveraendert #F54747. */
    --primary-hell:oklch(calc(.650 + .100 * var(--belichtung)) .2108 25.2);
  }
}

*{box-sizing:border-box}

/* ---------- Kein Wort schiebt die Wand zur Seite ----------
   Die Redaktion traegt deutsche Komposita ein und sieht beim Eintragen nicht,
   was daraus auf einem 375er Telefon wird: ein Ortsname wie
   »Veranstaltungsraumbewirtschaftungsgesellschaft« schob die ganze Seite
   seitlich hinaus, und mit ihr Logo, Liste und Fuss. Gemessen waren 854 px
   Inhalt in einem 375 px breiten Bild.

   Es sind zwei Regeln, und beide werden gebraucht:

   `overflow-wrap:anywhere` trennt notfalls mitten im Wort - aber wirklich nur
   dann, wenn es keine andere Trennstelle mehr gibt. Anders als break-word
   zaehlt es dabei auch fuer die Mindestbreite, die ein Element seinem Raster
   meldet; genau darauf kommt es hier an.

   `min-width:0` nimmt Raster- und Reihenkindern die Mindestbreite, die sie
   sonst von ihrem Inhalt erben. Ohne sie dehnt ein einziges langes Wort seine
   Spalte, statt in ihr umzubrechen - die Trennregel darueber kaeme nie zum Zug.

   Beides steht hier oben und nicht an sechs Stellen weiter unten: es ist keine
   Eigenschaft der Programmzeile oder der Termindaten, sondern der Wand. */
.zeile>div,.event-daten,.event-bilder,.filter>*,.fuss>*,.fuss nav{min-width:0}
.zeile .wann,.zeile .meta,.zeile .kat,.zeile .preis,
.event-daten,.event-daten p,.event-kopf .kat,
.body,.leer,.support,.gruppe,.tor-satz,
.hauptmenue a,.fuss nav a{overflow-wrap:anywhere}

/* ---------- Und keiner davon setzt einen Trennstrich ----------
   Die Regel darueber sorgt dafuer, dass ein langes Wort umbricht. Sie sagt
   nicht, WIE es umbricht - und der Browser hat dazu eine eigene Meinung:
   `hyphens:auto` stand auf den Titeln und machte auf einem 375er Telefon aus
   »CONCERTO FANGO« ein »CONCERTO FAN-GO«. In 39px Delight, Versalien, als
   erste Zeile eines Termins. Der Strich sieht dabei nicht wie eine Trennung
   aus, sondern wie ein Bindestrich, der zum Namen gehoert - der Titel liest
   sich falsch, bevor er zu Ende gelesen ist. Gemessen: acht von 33 Titeln im
   Rueckblick waren bei 375px getrennt.

   Automatische Trennung ist deshalb ueberall aus, an der Wurzel und in einer
   Zeile: sie ist keine Eigenschaft einzelner Ueberschriften, sondern des
   Hauses. Was bleibt, ist der Notumbruch von oben - der trennt mitten im
   Wort, aber ohne Strich, und nur wenn sonst die Wand wandert. Lieber eine
   Zeile mehr als ein Strich, der nicht dasteht, um gelesen zu werden.

   Das Praefix ist nicht nachlaessig stehengeblieben: unpraefixiert kennt
   Safari `hyphens` erst ab 17, und das Telefon, um das es hier geht, ist
   haeufiger ein aelteres iPhone als ein neues. */
:root{-webkit-hyphens:none;hyphens:none}

/* Fuer Inhalte, die vorgelesen, aber nicht gezeigt werden - die Startseite ist
   ein reines Typo-Menue und braucht trotzdem eine Ueberschrift. */
.nur-vorlesen{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
/* Der Grund ist die unbeleuchtete Wand und bleibt es. Alles Licht liegt als
   eigene Lage darueber - sonst wuerde die Wand zweimal aufgehellt: einmal
   flaechig und einmal vom Lichtfeld. body traegt darum keine Flaeche mehr. */
html{font-size:10px;background:var(--wand);-webkit-text-size-adjust:100%}
body{margin:0;position:relative;color:var(--textfarbe);
  font-family:"IBM Plex",system-ui,sans-serif;font-size:var(--text-m);line-height:1.7;
  -webkit-font-smoothing:antialiased}

/* ---------- Der Raum ----------
   Die Belichtung ist keine Flaechenfarbe mehr, sondern ein Ort: die Lampe haengt
   bei --lampe-x/--lampe-y im Fenster und das Licht faellt von dort ab. Drei Lagen,
   alle hinter dem Inhalt (negatives z), alle mit opacity:var(--licht) - bei
   dunklem oder unbekanntem Zustand ist der ganze Abschnitt schlicht nicht da,
   und die Seite sieht aus wie zuvor.

   Warum das erlaubt ist, obwohl das System keine Verlaufsflaechen kennt: dies
   ist keine Flaeche, sondern Licht auf einer. Es traegt keinen Inhalt, es hat
   keinen Rand, und es verschwindet vollstaendig, sobald die Bar dunkel ist. */
:root{
  --lichtfeld:radial-gradient(var(--lampe-weite) var(--lampe-hoehe) at 50% 50%,
    var(--wand-hell) 0%,
    color-mix(in oklab, var(--wand-hell) 72%, transparent) 22%,
    color-mix(in oklab, var(--wand-hell) 40%, transparent) 45%,
    color-mix(in oklab, var(--wand-hell) 17%, transparent) 68%,
    color-mix(in oklab, var(--wand-hell) 0%, transparent) 100%);

  /* Die Wand ist ungeputzt. Man sieht das nur im Licht - deshalb steht die
     Struktur nicht im Grund, sondern in der Lage, die das Licht traegt. */
  --staub:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='k'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23k)'/%3E%3C/svg%3E");
}

/* Die beiden Lichtlagen sind seit der Zeigerschleife echte Elemente und keine
   Pseudo-Elemente mehr. Der Grund ist nicht Gestaltung, sondern Kosten: ein
   Pseudo-Element laesst sich von einem Skript nur ueber eine Variable an einem
   Vorfahren bewegen, und jede Aenderung an einer geerbten Variable auf <html>
   entwertet den geerbten Wert im ganzen Dokument - je Bild. Ein echtes Element
   nimmt seinen transform direkt entgegen und kostet den Rest der Seite nichts.

   Ohne Skript aendert sich dadurch nichts: die Ruhelage steht unveraendert hier
   im Stylesheet, und die Lagen stehen im Markup, nicht im Skript. */
.huelle::after{content:"";pointer-events:none}
.lichtlage{pointer-events:none}

/* Beide Lichtlagen sind genau so gross wie das Feld, das sie tragen, und liegen
   mit ihrer Mitte auf der Lampe. Der Verlauf steht darin fest bei 50%/50%;
   bewegt wird die Lage, nicht der Verlauf. Das ist der Unterschied zwischen
   einer Transformation und einem Neuzeichnen der ganzen Wand in jedem Bild -
   und erst dadurch kann der Zeiger das Licht ueberhaupt hinter sich herziehen.

   Der Rueckstand der Lampe dreht und dehnt die Lage: sie schwingt am Kabel.
   In Ruhe ist --lampe-dehnung 1 und --lampe-drehung 0deg, also steht hier
   dasselbe Bild wie vorher. */
.lichtlage{position:fixed;left:50%;top:50%;
  width:calc(var(--lampe-weite) * 2);height:calc(var(--lampe-hoehe) * 2);
  margin-left:calc(var(--lampe-weite) * -1);margin-top:calc(var(--lampe-hoehe) * -1);
  transform:translate3d(calc(var(--lampe-x) - 50vw), calc(var(--lampe-y) - 50vh), 0)
            rotate(var(--lampe-drehung)) scaleX(var(--lampe-dehnung))}

/* Nur solange die Lampe unterwegs ist. Zwei fensterfuellende Lagen dauerhaft
   in den Compositor zu heben, kostet Speicher fuer nichts. */
:root.lampe-bewegt .lichtlage{will-change:transform}

/* Das Licht selbst. */
.lichtlage.licht{z-index:-2;background-image:var(--lichtfeld);opacity:var(--licht)}

/* Die Struktur der Wand, mit demselben Feld ausmaskiert: Putz wird nur dort
   sichtbar, wo Licht hinkommt. overlay statt einer Deckkraft, damit die Koernung
   die Wand ebenso vertieft wie aufhellt - eine aufgehellte Koernung waere Dunst.
   Der Zug an der Lampe hebt sie kurz an: schnelles Ziehen streift den Putz. */
.lichtlage.staub{z-index:-1;
  background-image:var(--staub);background-size:200px 200px;
  mix-blend-mode:overlay;opacity:calc(var(--koernung) * var(--licht));
  -webkit-mask-image:var(--lichtfeld);mask-image:var(--lichtfeld)}

/* Der Sandboden. Er haengt am Dokumentende, nicht am Fensterrand: man sieht ihn,
   wenn man unten angekommen ist, so wie man ihn im Raum sieht, wenn man
   hinuntersieht. Im Dunkeln gibt es keinen Boden - da sieht man ihn nicht. */
/* Die Wand reicht mindestens bis an den unteren Bildschirmrand, und der Fuss
   wird von der wachsenden Mitte dorthin geschoben. Sonst endet die Wand mit dem
   Inhalt: auf einer kurzen Seite - dem Tor, der Startseite auf einem hohen
   Schirm - haengen Fuss und Sandboden dann mitten im Bild, mit toter Wand
   darunter. Ein Boden, unter dem noch Raum ist, ist kein Boden.

   Geschoben, nicht festgeklebt: auf einer langen Seite laeuft beides wie bisher
   am Dokumentende mit und kommt erst in Sicht, wenn man unten angekommen ist. */
.huelle{position:relative;min-height:100dvh;display:flex;flex-direction:column}
.huelle>main{flex:1 0 auto}
/* Im Spaltenfluss wuerde der Sprunglink sonst ueber die ganze Breite gedehnt -
   und mit ihm sein Fokusring. */
.huelle>.skip{align-self:flex-start}
.huelle::after{position:absolute;left:0;right:0;bottom:0;height:34rem;z-index:-1;
  background-image:linear-gradient(to top,
    var(--sandlicht) 0%,
    color-mix(in oklab, var(--sandlicht) 45%, transparent) 30%,
    color-mix(in oklab, var(--sandlicht) 15%, transparent) 62%,
    color-mix(in oklab, var(--sandlicht) 0%, transparent) 100%);
  opacity:calc(.85 * var(--licht))}
/* ---------- Der Schleier: die Lampe als Flaeche hinter der Seite ----------
   Es gab ihn schon, aber nur als Zutat an einer einzelnen Veranstaltung, von
   propaganda gesetzt (»Der Schleier«, weiter unten). Hier ist er eine Regel des
   Hauses: eine Seite kann sagen, dass hinter ihr die Lampe haengt.

   **Als Maske, nicht als Bild** - dieselbe Begruendung wie ueberall sonst: nur
   so folgt die Farbe der Tinte, und nur so kehrt der Schleier auf hellem Grund
   mit um. Ein eingefaerbtes Bild bliebe weiss.

   **Er liegt fest im Fenster und nicht im Dokument**, wie die beiden
   Lichtlagen. Er ist die Wand, und die Wand scrollt nicht mit; ein
   mitlaufendes Wasserzeichen waere ein Bild auf der Seite und kein Grund
   dahinter.

   **Er liegt zwischen Licht und Putz.** z-index -2 wie das Lichtfeld, aber
   spaeter im Dokument - damit liegt er darueber und wird vom Licht nicht
   verdeckt. Der Putz (-1) liegt seinerseits ueber ihm und koernt ihn mit:
   ein Zeichen auf der Wand traegt die Struktur der Wand.

   **Die ganze Lampe, nicht ein Streifen davon.** Der erste Versuch schnitt sie
   an der Kante an, wie das Blatt es tut - im Bild stand dann ein Block aus
   zwanzig Strichen, also die Textur der Lampe und nicht die Lampe. Ein
   Wasserzeichen, an dem man das Zeichen nicht mehr erkennt, ist ein Muster,
   und ein Muster hat dieses Haus nicht. Sie haengt jetzt ganz an der Wand:
   Kabel, Saeule, Spirale, Affe. **Es ist kein Doppel zum Zeichen im Kopf,
   sondern derselbe Gegenstand aus einer anderen Entfernung** - im Kopf steht
   er sechs- bis achtmal kleiner, und genau das ist der Unterschied zwischen
   einer Marke und einem Raum.

   **Zwei Lagen, und sie heissen so.** Ein freier Wert waere eine Stelle, die
   niemand nachgerechnet hat - und der Schleier liegt unter dem Text.

   - `rand` haengt links neben der Lesespalte einer Textseite. Er faellt weg,
     sobald die Spalte die Wand fuellt: dann gibt es keinen Rand mehr, an dem
     er haengen koennte.
   - `wand` haengt rechts und gross auf den beiden Flaechen, auf denen sonst
     ein Satz steht und sonst nichts: die 404 ohne kommendes Programm und das
     leere Programm selbst. Er sagt dasselbe wie der Satz daneben - hier
     haengt gerade nichts -, nur sieht die Wand dabei aus wie eine Wand und
     nicht wie ein Fehler.

   **Die Deckkraft ist gerechnet und nicht gewaehlt.** Sie ist keine zweite
   Belichtung: fest, kein Verlauf, sie dimmt nicht mit dem Barlicht. Gerechnet
   wird gegen den hellsten Grund, den das Haus kennt - die belichtete Wand im
   Lichtkern, #37322C -, und gegen die duennste Schrift, die darauf stehen
   darf: --text-still, 55 % Weiss.

   Auf dieser Wand steht sie ohne Schleier auf 5,03:1. Ein Schleier hebt den
   Grund an und nimmt ihr davon:

     .055  ->  Grund #423D37,  still 4,51:1   <- die Grenze
     .07   ->  Grund #454038,  still 4,37:1   <- darunter

   .055 ist deshalb kein Geschmack, sondern der letzte Wert, bei dem die
   duennste Schrift des Hauses ueber der hellsten Stelle der Wand noch
   4,5:1 haelt. Wer ihn hochsetzt, setzt den Kontrastboden herunter - und
   zwar an der Stelle, an der er ohnehin am duennsten ist. */
:root[data-schleier] .huelle::before{
  content:"";position:fixed;inset:0;z-index:-2;pointer-events:none;
  background:currentColor;opacity:var(--schleier-kraft);
  -webkit-mask:url("../img/logo.svg") no-repeat var(--schleier-ort) / var(--schleier-mass);
          mask:url("../img/logo.svg") no-repeat var(--schleier-ort) / var(--schleier-mass)}

/* Sie haengt am Rand und ueber dem Fuss - nicht mittig: die Spalte dieser
   beiden Seiten steht links, und eine Lampe in der Spaltenmitte laege unter
   dem einzigen Satz, den sie tragen.

   **Und unter 62rem haengt sie gar nicht.** Das ist keine neue Regel, sondern
   dieselbe, die drei Absaetze weiter unten fuer `rand` steht - sie war
   geschrieben und nur auf eine der beiden Lagen angewandt. Unter 62rem ist die
   Spalte die ganze Wand, und dann gibt es keinen Rand mehr, an dem eine Lampe
   haengen koennte: auf dem Telefon lag sie 617px hoch von unten rechts unter
   dem einen Satz, den diese Flaechen tragen, unter den beiden Verweisen
   darunter und ueber die volle Hoehe des Fusses. Bei brennendem Barlicht stand
   das Fussmenue mitten auf dem Affen.

   Sie faellt deshalb ganz weg, statt leiser zu werden - gleichlautend zu
   `rand`: ein Wasserzeichen unter einer Textspalte ist kein schwaecheres
   Wasserzeichen, sondern ein schlechterer Kontrast. Was `wand` sagt, sagt auf
   dem Telefon ohnehin der Satz daneben, und er sagt es in Worten. */
:root[data-schleier=wand]{--schleier-kraft:0}
@media (min-width:62rem){
  :root[data-schleier=wand]{
    --schleier-ort:right 4vmin bottom 13vh;--schleier-mass:auto 76vh;
    --schleier-kraft:.055}
}

/* Unter 62rem ist die Lesespalte die ganze Wand: ein Schleier laege dann nicht
   neben dem Text, sondern darunter. Er faellt deshalb ganz weg, statt leiser
   zu werden - ein Wasserzeichen unter einer Textspalte ist kein schwaecheres
   Wasserzeichen, sondern ein schlechterer Kontrast. */
:root[data-schleier=rand]{--schleier-kraft:0}
@media (min-width:62rem){
  :root[data-schleier=rand]{
    --schleier-ort:left 3vmin bottom 12vh;--schleier-mass:auto 58vh;
    --schleier-kraft:.055}
}

a{color:inherit;text-decoration:none}
img{max-width:100%;height:auto;display:block}

/* Der Rand ist zugleich Raster; auf Geraeten mit Aussparung gewinnt der groessere Wert. */
.huelle{padding-inline:max(var(--grid-gap), env(safe-area-inset-left), env(safe-area-inset-right))}

/* ---------- Zwei Achsen, je nach Aufgabe der Seite ----------
   Wer eine Liste ueberfliegt, sucht am Rand: Programm und Rueckblick stehen
   linksbuendig und nutzen die volle Wand. Wer liest, folgt einer Spalte - und
   die stand bis hierher links unter einem mittigen Seitentitel, also auf einer
   anderen Achse als ihre Ueberschrift, mit 660 px leerer Wand daneben. Die
   lesenden Seiten sind genau die mit sichtbarem Seitentitel, also die ohne
   schlanken Kopf: dort ruecken Titel und Spalte auf dieselbe Mitte.

   **Die Veranstaltungsseite gehoert zu den lesenden.** Sie stand hier lange
   bei den Listen, weil ihr Kopf schlank ist - aber ein schlanker Kopf ist eine
   Angabe ueber die Ueberschrift und keine ueber die Aufgabe. Gelesen wird auf
   ihr wie auf jeder Textseite: Titel, Termindaten, Text. Sie bekommt ihre
   Spalte nur nicht ueber `main`, weil sie daneben Flaechen und volle
   Wandbreiten kennt - siehe »Die Achse der Veranstaltungsseite«. */
.kopf:not(.kopf--schlank)+main{max-width:62ch;margin-inline:auto}
.kopf:not(.kopf--schlank)+main.tor{max-width:52ch}

::selection{background:var(--primary);color:var(--titelfarbe)}

/* Rot laege auf dem Grund bei 2,84:1 und damit unter der Schwelle fuer
   Bedienelemente - der Ring nimmt darum Titelweiss. */
:focus-visible{outline:2px solid var(--titelfarbe);outline-offset:2px}
.zeile:focus-visible{outline-offset:-2px}

/* Auf einer umgekehrten Flaeche kehrt der Ring mit um. Titelweiss mit Abstand
   um einen titelweissen Kasten liest sich als Doppelrahmen - heller Kasten,
   dunkle Fuge, heller Ring - und macht aus einem Reiter oder einem Knopf ein
   Bauteil. Es ist dieselbe Regel und nicht ihre Ausnahme: der Ring nimmt die
   Gegenfarbe der Flaeche, auf der er steht, und legt sich auf ihre Kante statt
   daneben.

   Sie steht hier und nicht bei den einzelnen Flaechen, weil sie an keiner
   davon haengt, sondern an der Umkehrung. Wer die naechste gefuellte Flaeche
   baut, traegt sie hier ein - das ist eine Zeile und keine vierte Kopie.
   Gemeint sind die vier des Hauses: der gewaehlte Chip der lauten Leiste, die
   beiden Knoepfe am Termin, der Knopf des Tors und die runden Zeichen im Fuss.
   Die leisen Leisten fuellen nicht, sie behalten den hellen Ring. */
.filter a[aria-current]:focus-visible,
.filter button[aria-pressed=true]:focus-visible,
.event-daten .ticket:focus-visible,
.event-daten .kalender:focus-visible,
.tor-form button:focus-visible,
.fuss .sozial a:focus-visible{
  outline-color:var(--dunkel);outline-offset:-2px;
}

/* Unter Zeiger und Finger wird aus der weissen Flaeche eine rote - dort waere
   Dunkel wieder das Falsche (2,3:1, unter jeder Schwelle). Der Ring geht dann
   zurueck nach aussen und wird wieder hell. Auch das ist keine Ausnahme: er
   folgt der Fuellung, und ohne weisse Fuellung gibt es nichts zu verdoppeln.
   Die gewaehlten Chips fehlen hier, weil ihr Hover sie ausdruecklich ausnimmt
   - sie bleiben weiss, solange sie gewaehlt sind. */
.event-daten .ticket:active:focus-visible,
.event-daten .kalender:active:focus-visible,
.tor-form button:active:focus-visible,
.fuss .sozial a:active:focus-visible{
  outline-color:var(--titelfarbe);outline-offset:2px;
}
@media (hover:hover){
  .event-daten .ticket:hover:focus-visible,
  .event-daten .kalender:hover:focus-visible,
  .tor-form button:hover:focus-visible,
  .fuss .sozial a:hover:focus-visible{
    outline-color:var(--titelfarbe);outline-offset:2px;
  }
}

/* Der Sprung in den Inhalt. Unsichtbar, bis er den Fokus bekommt - dann ist er
   eine Beschriftung wie jede andere: auf der Wand, nicht auf einer Flaeche. */
.skip{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}
.skip:focus-visible{position:static;width:auto;height:auto;overflow:visible;
  display:inline-block;margin-top:1.2rem;font-family:Delight;font-weight:900;
  font-size:var(--text-s);line-height:1.7;letter-spacing:.08em;
  text-transform:uppercase;color:var(--titelfarbe)}

/* ---------- Kopf: Logo + Seitentitel ---------- */
.kopf{padding-block:var(--kopf-oben) 0;text-align:center}
/* Das Zeichen liegt als Maske in der Flaeche und nicht als Bild darin - anders
   liesse sich seine Farbe nicht schalten, und sie muss geschaltet werden. Das
   Seitenverhaeltnis kommt darum aus dem Stylesheet und nicht mehr aus der
   Datei. Ohne Maskenunterstuetzung steht das weisse Bild wie bisher.

   Dieselbe Loesung wie an der Lampe in der Bar (bar.css, »Die Lampe«): es ist
   dasselbe Zeichen an derselben Lampe, und es sagt auf beiden Seiten dasselbe
   auf dieselbe Weise. */
/* Die Lampe im Seitenkopf und die Lampe an einer Tuer sind derselbe Gegenstand
   und stehen deshalb in derselben Regel. Was sie unterscheidet, ist die
   Entfernung - und die ist eine Zahl, --logo-hoehe, nicht ein zweites Zeichen.
   Sie hing bis hierher an vier Tueren viermal verschieden: als schwingende
   Lampe (Bar), als starres <img> (Konzeptuebersicht) und zweimal gar nicht
   (Booking, propaganda). Siehe site/snippets/torzeichen.php. */
.kopf .logo,.torzeichen{width:auto;height:var(--logo-hoehe);aspect-ratio:488 / 1053;
  display:block;
  background:url("../img/logo.svg") center/contain no-repeat}
.kopf .logo{margin:0 auto;

  /* Herangeholt wird von oben, nicht aus der Mitte: das Kabel geht in die
     Decke, und was an einem Kabel haengt, kommt herunter und nicht
     auseinander. Derselbe Ursprung wie an der Lampe in der Bar. */
  transform-origin:50% 0;
  transition:transform var(--takt-hover) var(--kurve-hover)}

@supports (mask-image:url("")) or (-webkit-mask-image:url("")){
  .kopf .logo,.torzeichen{background:currentColor;color:var(--titelfarbe);
    -webkit-mask:url("../img/logo.svg") center/contain no-repeat;
            mask:url("../img/logo.svg") center/contain no-repeat}
}

/* An der Tuer haengt sie ueber dem Wort, mit dem Abstand eines Blocks darunter -
   sie fuehrt hier an, sie unterschreibt nicht. Der Affe unterschreibt, und das
   tut er im Fuss der Seite (fuss.php).

   Sie steht ueber ihrer Spalte und nicht neben ihr: an einer linksbuendigen
   Tuer (Booking, Konzeptuebersicht) haengt sie links, an einer mittigen
   (propaganda, Baustellentor) traegt der mittige Kopf sie selbst. */
.torzeichen{margin-bottom:var(--takt-zeile)}
.kopf .torzeichen{margin-inline:auto}
:root[data-licht=an] .torzeichen{color:var(--gluehton)}

/* Wer sich mit der Tastatur bewegt, bekommt dieselbe Auskunft - der Ring allein
   sagt »hier stehst du«, nicht »und hier geht es hin«. Steht ausserhalb der
   Zeigerabfrage: eine Tastatur hat keinen Hover. */
.kopf a:focus-visible .logo{transform:scale(1.04)}

/* Brennt das Barlicht, brennt auch die Quelle im Zeichen. Das ist keine zweite
   Auskunft neben der belichteten Wand, sondern ihr Ursprung: das Licht, das auf
   die Wand faellt, kommt aus dieser Spirale. Kalt-weiss heisst aus, warm heisst
   an - dieselben zwei Zustaende, dieselben zwei Farben wie in der Bar.

   Geschaltet, nicht ueberblendet: Licht ist an oder aus, es dimmt nicht auf. */
:root[data-licht=an] .kopf .logo{color:var(--gluehton)}
/* Listenseiten nehmen den Kopf zurueck. Wer auf »Programm« getippt hat, braucht
   das Wort nicht in Plakatgroesse wieder - er braucht die erste Zeile. Die hoehere
   Spezifitaet setzt sich gegen die vh-Kurve der Tablet-Abfrage durch. */
.kopf.kopf--schlank .logo{height:clamp(6rem, 9vh, 9rem)}
/* Damit die Ruhelage der Lampe auch auf den Listenseiten in der Spirale liegt,
   und nicht nur dort, wo das Logo in voller Groesse haengt. */
:root:has(.kopf--schlank){--logo-hoehe:clamp(6rem, 9vh, 9rem)}

.seitentitel{font-family:Delight;font-weight:900;font-size:var(--title);line-height:.8;
  letter-spacing:1.1px;text-transform:uppercase;color:var(--titelfarbe);
  margin:var(--takt-zeile) 0 0;overflow-wrap:break-word}

/* ---------- Hauptmenue (Startseite) ---------- */
.hauptmenue{display:flex;flex-direction:column;align-items:center;
  padding-block:var(--takt-block) var(--takt-zeile)}
.hauptmenue a{font-family:Delight;font-weight:900;font-size:var(--title);line-height:1.138;
  letter-spacing:1.1px;text-transform:uppercase;color:var(--titelfarbe);
  transition:color var(--takt-hover) var(--kurve-hover)}
.hauptmenue a:focus-visible{color:var(--primary-hell)}
/* ---------- Der Klebepunkt ----------
   Die eine Flaeche, die dieses System sich leistet, und die einzige Stelle, an
   der Farbe nicht aus einer Kategorie kommt.

   **Warum das erlaubt ist.** »Rot markiert, Rot dekoriert nicht« schliesst rote
   Flaechen *um Inhalte* aus. Ein Klebepunkt hat neben der Markierung keinen
   Inhalt - er ist die Bekanntmachung, nicht ihr Rahmen. Rot dekoriert hier
   nichts, es ist der ganze Gegenstand. Genau eine Stelle im Haus, und keine
   zweite: wer den naechsten roten Kasten baut, hat diese Begruendung nicht.

   **Warum es ein Kreis ist.** Der Radius ist die eine Rundung, die das System
   ohnehin kennt - 50% fuer echte Punkte. Der Klebepunkt bricht damit **einen**
   Grundsatz und nicht zwei: gedreht wird nicht die Form, sondern die Schrift
   darin. Ein Kreis mit Schraeglage sieht aus wie ein Kreis; erst die schiefe
   Zeile sagt »aufgeklebt« statt »eingebaut«. Und sie sagt es ohne Klebeband,
   ohne gerissene Kante, ohne Eselsohr und ohne Papierstruktur - das Haus hat
   genau eine Textur, den Putz, und die gehoert dem Licht.

   **Er empfaengt kein Licht.** --primary wird nicht mitbelichtet: eine Flaeche
   *ist* Licht, sie bekommt keines. Steigt die Wand bei brennendem Barlicht auf
   #37322C, steht der Punkt auf denselben #C40909 wie im Dunkeln - im hellen
   Raum also relativ leiser, im dunklen lauter. Papier an einer Wand. Titelweiss
   darauf haelt in beiden Zustaenden (5,68:1 dunkel, 5,70:1 hell), weil sich nur
   das Weiss aendert und nicht die Flaeche.

   **Einzelne Eigenschaften statt eines transform.** Scheibe und Schlagzeile
   tragen `scale`, `rotate` und `translate` getrennt und nicht als eine
   `transform`-Liste. Das ist Bedingung und nicht Geschmack: die Ankunft
   animiert die Groesse, der Griff dreht die Zeile, und der Ort steht fest -
   drei Dinge, die in einer gemeinsamen Liste einander ueberschreiben wuerden,
   sobald zwei davon gleichzeitig gelten. */
.klebewand{display:flex;flex-direction:column;align-items:center;
  margin-top:var(--takt-zeile);
  /* Der Punkt hat ein Mass, und der Text richtet sich danach - nicht
     umgekehrt. Die Schlagzeile ist im Panel auf 22 Zeichen begrenzt; was
     laenger ist, passt nicht in einen Kreis und wuerde ihn zur Ellipse
     ziehen. */
  --mass:min(26rem, 62vw)}

/* **Zwei stehen im Fluss nebeneinander, nicht uebereinander.** Gestapelt
   waeren sie auf einem Telefon zusammen ueber 500px hoch und schoeben das
   ganze Menue unter den Bildrand - wer das Programm sucht, muesste dann an
   der Ankuendigung vorbeiscrollen. Nebeneinander kosten sie die halbe Hoehe
   und lesen sich als das, was sie sind: zwei Dinge, die jemand nebeneinander
   geklebt hat. Der zweite haengt dabei ein Stueck tiefer - von Hand geklebt
   wird nicht auf einer Linie.

   Die Zahl steht als Attribut im Markup und nicht in einer :has()-Abfrage:
   die Seite weiss sie ohnehin, und was der Server weiss, muss der Browser
   nicht herleiten. */
.klebewand[data-anzahl="2"]{flex-direction:row;align-items:flex-start;
  justify-content:center;gap:var(--grid-gap);--mass:min(16rem, 40vw)}
.klebewand[data-anzahl="2"] .klebepunkt:nth-child(2){margin-top:2.4rem}

.klebepunkt{display:block;width:var(--mass);text-align:center;
  color:var(--titelfarbe);text-decoration:none}

.klebepunkt .scheibe{display:grid;place-items:center;
  width:100%;aspect-ratio:1;border-radius:50%;
  background:var(--primary);color:var(--titelfarbe);
  container-type:inline-size;
  transition:scale var(--takt-hover) var(--kurve-hover)}
/* Ohne Innenabstand, und das ist eine Rechnung und keine Nachlaessigkeit:
   `container-type:inline-size` misst die **Innenflaeche**. Mit 14% Rand haette
   1cqi nicht ein Prozent des Durchmessers gemessen, sondern eines um 28%
   kleineren Kastens - die Schlagzeile waere in jedem Punkt zu klein
   herausgekommen, und zwar unauffaellig, weil sie ja irgendwie passte. Der
   Abstand zum Rand entsteht stattdessen an der Schrift selbst, unten. */

/* Die Schrift skaliert am Punkt und nicht am Fenster: der Punkt schrumpft,
   wenn zwei kleben, und eine Zeile, die das nicht mitmacht, laege dann ueber
   dem Rand. 15cqi sind 15 Prozent des Punktdurchmessers. */
.klebepunkt .schlag{font-family:Delight;font-weight:900;text-transform:uppercase;
  font-size:clamp(1.8rem, 15cqi, 4.4rem);
  /* Ein Kreis ist nicht so breit, wie er breit ist: was oben und unten steht,
     hat weniger Platz als die Mitte. 82 und nicht 70,7: der Satz steht in der
     Mitte des Kreises, und dort ist er breiter als das eingeschriebene
     Quadrat. Bei drei Zeilen liegt die aeusserste noch bei 91%. Zu eng gefasst
     trennt Delight ein Wort zweimal - aus SOMMERPAUSE wurde SOM-MER-PAUSE. */
  max-width:82cqi;text-wrap:balance;
  /* Delight setzt das UE 0,894em ueber die Grundlinie und das O 0,015em
     darunter: unter 0,909em beruehren sich zwei Zeilen. Der Wert ist gerechnet
     und nicht gewaehlt. */
  line-height:.95;letter-spacing:.5px;
  /* Getrennt, nicht geschnitten. »SOMMERPAUSE« ist ein Wort ohne Fuge und
     breiter als der Kreis; ohne Trennung schnitte der Browser es strichlos
     mitten durch. Das Dokument traegt lang="de", also weiss der Browser, wo
     der Bindestrich hindarf. `break-word` bleibt die letzte Rettung. */
  -webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word;
  rotate:-5deg;
  transition:rotate var(--takt-hover) var(--kurve-hover)}
/* Der zweite kippt in die andere Richtung. Zwei gleich geneigte Zeilen waeren
   ein Muster, und Muster hat dieses Haus keine. */
.klebepunkt:nth-child(2) .schlag{rotate:4deg}

/* Der Satz steht auf der Wand und nicht im Punkt. Im Kreis haette er keinen
   Platz - und er soll auch keinen bekommen: was im Punkt steht, wird aus zwei
   Metern gelesen, was darunter steht, aus zwei Schritten. */
.klebepunkt .satz{display:block;margin-top:var(--takt-eng);
  font-size:var(--text-s);line-height:1.45;color:var(--titelfarbe)}

/* ---------- Zwei Waende, nicht eine ----------
   **Die Startseite hat zwei leere Waende, und der Punkt hatte nur die linke.**
   Das war nicht nur eine verschenkte Haelfte, sondern ein Fehler mit Folgen:
   weil zwei Punkte uebereinander in *eine* Wand mussten, brauchte die Wand
   eine Hoehenschwelle - und unterhalb davon fiel die Seite auf die Anordnung
   im Fluss zurueck. Auf einem 1280x800 grossen Fenster, dem Format eines
   13-Zoll-Laptops, standen die Punkte dadurch **ueber** dem Menue und schoben
   die Haelfte davon unter die Falz.

   Einer links, einer rechts halbiert den Hoehenbedarf. Die Hoehenschwelle
   faellt damit von 820px auf 680px, und beide Punkte duerfen groesser sein
   statt zu schrumpfen.

   **Auch die Breitenschwelle war zu hoch.** 1180px stammte aus der Zeit der
   einen Wand und aus den Randspuren der Reihe, wo sie hingehoert. Zwei Waende
   brauchen viel weniger: rechnerisch traegt jede ab etwa 900px einen Punkt in
   der kleinsten lesbaren Groesse. Sie steht jetzt bei 62rem - derselben
   Schwelle, die weiter oben schon im Blatt steht - und deckt damit auch die
   1152px, in denen die Konzeptuebersicht die Seite fotografiert. Bei 1180
   bekam ausgerechnet dieses Fenster die Anordnung im Fluss.

   **Die Wand wird gemessen, nicht gerechnet.** Der erste Anlauf leitete ihre
   Breite aus `62ch` ab - der Maximalbreite von `main` - und lag daneben, weil
   `main` diese Breite nie annimmt: `margin-inline:auto` hebt im senkrechten
   Flexfluss der Huelle den Stretch auf, und die Spalte ist damit **so breit
   wie ihr Inhalt** (477px bei einem Menue aus fuenf Woertern), nicht 744px.
   Eine Rechnung auf 62ch beschreibt also eine Spalte, die es nicht gibt.

   Was es gibt, ist der Prozentwert: die Lage liegt auf `main`, ihr `100%` ist
   die Spalte. Von dort aus ist jede Wand `50vw - 50% - Rand` - unabhaengig von
   Schrift, Sprache und Zahl der Menuepunkte. Waechst das Menue, wandern die
   Punkte mit.

   Sie haengen darum nicht *in* der Lage, sondern an ihren Aussenkanten:
   `right:100%` setzt den linken Punkt mit seiner rechten Kante an die linke
   Kante der Spalte, `left:100%` den rechten spiegelbildlich. Klebt nur einer,
   bleibt er links, wo die Leserichtung ihn erwartet.

   **Die Lage darf keine Klicks fressen.** Sie deckt die ganze Menuespalte,
   traegt dort aber nichts - `pointer-events:none` gibt die Zeilen darunter
   frei, die Punkte selbst holen sich das Ereignis zurueck. */
@media (min-width:62rem) and (min-height:680px){
  main:has(> .klebewand){position:relative}

  /* `display:block` statt Flex: in der Wand steht die Lage nicht mehr fuer die
     Anordnung, sondern nur noch fuer den Bezugsrahmen. Die Reihe im Fluss
     (data-anzahl="2") wird dadurch gegenstandslos - ihre Angaben stehen noch
     da und tun nichts. */
  .klebewand,.klebewand[data-anzahl="2"]{
    position:absolute;inset:0;margin:0;display:block;pointer-events:none;
    /* Die engere von zwei Grenzen gewinnt: die Breite der Wand (unten als
       max-width, weil erst dort der Prozentwert die Spalte meint) und die
       Hoehe zwischen Kopf und Fuss. Der Boden von 14rem ist die Groesse, unter
       der eine Schlagzeile im Kreis nicht mehr aus zwei Metern zu lesen ist -
       darunter greift die Schwelle oben und die Anordnung im Fluss. */
    --mass:clamp(14rem, calc(100dvh - 52rem), 30rem)}

  .klebepunkt{position:absolute;top:50%;translate:0 -50%;
    width:var(--mass);
    /* Hier meint `50%` die Spalte, weil die Lage auf ihr liegt. Der Punkt
       bekommt also genau die Wand minus zwei Zentimeter Luft. */
    max-width:calc(50vw - 50% - var(--grid-gap) - 2rem);
    pointer-events:auto;margin-top:0}
  .klebepunkt:nth-child(1){right:100%;margin-right:var(--grid-gap)}
  /* Der rechte haengt tiefer. Zwei Punkte auf einer Linie waeren gesetzt,
     nicht geklebt. */
  .klebepunkt:nth-child(2){left:100%;margin-left:var(--grid-gap);
    margin-top:6rem}
}

/* ---------- Angeklebt ----------
   Der Punkt klebte schon da, als jemand ankam - fast immer. Genau einmal je
   Sitzung wird er stattdessen **angeklebt**: er kommt eine Spur zu gross an,
   schwingt unter seine Groesse durch und setzt sich, und die Schlagzeile dreht
   sich dabei in ihre Schraeglage. Das ist die Geste, die den Gegenstand
   beschreibt, und sie dauert 460 ms.

   **Einmal je Sitzung, nicht bei jedem Bild.** Ein Aufschlag bei jedem Aufruf
   waere eine Ankuendigung der Ankuendigung; an eine Scroll-Zeitachse gehaengt
   waere er ein Regler. `kleben.js` merkt sich in der Sitzung, dass es passiert
   ist, und nimmt das Attribut nach dem Aufschlag wieder ab - sonst hielte die
   Fuellung der Animation den Griff darunter fest.

   **Der Ausgangszustand ist der sichtbare.** Ohne Skript, mit einem Modul, das
   nicht kommt, und bei reduzierter Bewegung klebt der Punkt einfach da. Ein
   Modul, das ausfaellt, darf keine Wand leeren. */
@keyframes klebe-auf{
  0%  {scale:1.22}
  62% {scale:.97}
  100%{scale:1}
}
@keyframes klebe-zeile{
  0%  {rotate:-16deg}
  62% {rotate:-3.2deg}
  100%{rotate:-5deg}
}
@keyframes klebe-zeile-zwei{
  0%  {rotate:15deg}
  62% {rotate:2.6deg}
  100%{rotate:4deg}
}
@media (prefers-reduced-motion:no-preference){
  .klebewand[data-kleben] .scheibe{
    animation:klebe-auf .46s var(--kurve-hover) both}
  .klebewand[data-kleben] .schlag{
    animation:klebe-zeile .46s var(--kurve-hover) both}
  .klebewand[data-kleben] .klebepunkt:nth-child(2) .schlag{
    animation-name:klebe-zeile-zwei}
  /* Der zweite kommt neunzig Millisekunden spaeter - eine Hand klebt nicht
     zwei Dinge gleichzeitig. */
  .klebewand[data-kleben] .klebepunkt:nth-child(2) .scheibe,
  .klebewand[data-kleben] .klebepunkt:nth-child(2) .schlag{
    animation-delay:.09s}
}
/* ---------- Der Zeiger ----------
   Der rote Punkt stand bis hierher unter dem Menue der Startseite. Er steht
   jetzt nicht mehr auf der Wand, sondern in der Hand: er ist der Zeiger, auf
   jeder Seite, in derselben Groesse und derselben Farbe wie vorher.

   Der Kern liegt ohne Verzug unter der Hand - ein ungenauer Zeiger ist kaputt.
   Der Ring haengt ihm ein paar Bilder nach und zieht sich ueber einem Ziel auf
   den Kern zusammen. Das ist kein Schmuck, sondern Ersatz: der Systemzeiger
   ist hier abgeschaltet, also muss der Zeiger selbst sagen, was anklickbar ist.

   Das Markup entsteht in zeiger.js. Ohne Skript gibt es keinen Zeiger - und
   dann auch keine Regel, die den vorhandenen versteckt. */
.zeiger{position:fixed;inset:0;z-index:4;pointer-events:none;
  opacity:0;transition:opacity var(--takt-hover) var(--kurve-hover)}
.zeiger[data-da]{opacity:1}
/* Wo ein anderer Zeiger genauer ist - Schreibmarke im Textfeld, Systemzeiger
   in einem fremden Dokument -, tritt der Punkt zurueck. Zwei Zeiger sind einer
   zu viel. */
.zeiger.fremd{opacity:0}
.zeiger b,
.zeiger .ring{position:absolute;left:0;top:0;display:block;
  transform:translate3d(-100px,-100px,0) translate(-50%,-50%)}
.zeiger b{border-radius:50%}
/* Kern und Ring sind bewusst die beiden Marken, die das System schon hat: der
   rote Punkt und die weisse Haarlinie des Fokusrings. Sie decken einander ab -
   auf der Wand steht der Ring, auf einer weissen Flaeche der Punkt, und auf
   einem rot gefaerbten Hoverlink, wo Rot auf Rot faellt, wieder der Ring. */
.zeiger{--ring-weit:3.6rem;--ring-eng:2.2rem}
.zeiger .kern{width:1.6rem;height:1.6rem;background:var(--primary)}
/* Der Ring aendert seine Groesse, nicht seinen Massstab: eine skalierte
   Haarlinie waere keine mehr, und genau sie ist der Zeiger auf rotem Grund.

   Er ist darum ein SVG-Kreis und kein Kaestchen mit Rundung. width und height
   je Bild zu schreiben, war die einzige Stelle im System, an der eine
   layoutausloesende Eigenschaft mit der Bildrate lief. Ein Kreis mit
   non-scaling-stroke laesst sich stattdessen skalieren: der Radius folgt dem
   Massstab, der Strich bleibt bei 1 px. Dieselbe Regel, ohne Layout. */
.zeiger .ring{width:var(--ring-weit);height:var(--ring-weit);overflow:visible}
.zeiger .ring circle{fill:none;stroke:var(--titelfarbe);stroke-width:1;
  vector-effect:non-scaling-stroke}

/* ---------- Filterleisten ---------- */
/* Die Leisten gehoeren zur Liste, nicht zum Kopf: ueber ihnen steht der
   Blockschritt, unter ihnen der Zeilenschritt. Vorher war es umgekehrt - die
   Bedienung sass 35 px unter dem Logo und 50 px ueber dem, was sie bedient. */
.filter{display:flex;flex-wrap:wrap;justify-content:center;gap:.6rem;
  margin-top:var(--takt-block)}
.filter a,.filter button{font-family:Delight;font-weight:900;font-size:var(--text-m);line-height:1.7;
  text-transform:uppercase;padding:.72rem 1.8rem;border-radius:2px;
  background:var(--background);color:var(--titelfarbe);
  transition:background var(--takt-hover) var(--kurve-hover),
             color var(--takt-hover) var(--kurve-hover)}
.filter button{border:0;cursor:pointer;font-weight:900}
.filter a[aria-current],
.filter button[aria-pressed=true]{background:var(--titelfarbe);color:var(--dunkel)}

/* Laut vor leise: die Zeitraumleiste ist gefuellt, Monate und Kategorien sind
   Text. Beide leisen Leisten teilen eine Grammatik, damit die laute die einzige
   bleibt, die von weitem als Bedienung liest.

   Zwei Zustaende, zwei Traeger: .belegt (hat Treffer im Ausschnitt) und
   [aria-current] (gewaehlt). Der dritte, ruhende, ist aus der Kategorieleiste
   verschwunden, seit tote Kategorien gar nicht mehr angeboten werden; ohne
   .belegt steht dort hoechstens noch eine gewaehlte, deren Ausschnitt leer ist.
   Die Monate teilen die stille Farbe weiter - sie sind von Haus aus belegt.
   Frueher hing alles am aria-current, was bis zu sechs Chips gleichzeitig als
   "aktuell" ausgezeichnet hat. */
.filter-leise{margin-top:var(--takt-eng);gap:1.6rem}
/* Zeitraum und Monat fragen beide nach der Zeit, die Kategorien nach etwas
   anderem. Ein Schritt trennt die zwei Fragen, ein enger haelt die erste
   zusammen. Bis hierher stand zwischen allen dreien derselbe Abstand von
   12 px - auf dem Telefon rettete das die Bildlaufleiste der Monatszeile,
   auf dem Schirm las sich die Kopfzone als ein einziger Wortteppich.

   Steht die Kategorieleiste allein - im Rueckblick, wo es keine Zeitraum- und
   keine Monatsleiste gibt -, ist sie die erste Bedienung der Seite und nimmt
   den Blockschritt wie jede andere. Sonst saesse sie gleich weit vom
   Dichtestreifen wie von der Zeitachse und gehoerte sichtbar zu keinem
   von beiden. */
.filter-kategorie{margin-top:var(--takt-block)}
.filter+.filter-kategorie{margin-top:var(--takt-zeile)}
.filter-leise a{font-weight:400;font-size:1.503rem;padding:.2rem 0;background:none;
  color:var(--text-still)}
.filter-leise a.belegt{color:var(--titelfarbe)}

/* Deckkraft trug frueher den ruhenden Zustand - und nahm dabei den Fokusring mit,
   den einzigen Hinweis, den ein Tastaturmensch hat. Sie ist darum durch die
   stille Textfarbe ersetzt; der Ring steht jetzt in voller Staerke. */
.filter-leise a[aria-current]{background:none;font-weight:900;color:var(--titelfarbe);
  text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.4em}
/* Die gewaehlte Kategorie traegt ihre Farbe - aber nicht als einziges Merkmal.
   Ausstellungsgrau ist dunkler als das stille Weiss der Leiste; als alleiniger
   Traeger machte die Farbe die Wahl unsichtbarer als eine tote Kategorie. */
.filter-kategorie a[aria-current]{color:var(--akzent,var(--titelfarbe))}

/* ---------- Programmliste ---------- */
.programm{margin-top:var(--takt-block);border-top:1px solid var(--linie)}

/* Was unmittelbar auf die Filterleisten folgt, ist das, was sie filtern - es
   rueckt naeher heran als der Block darueber. */
.filter-kategorie+section>.gruppe,
.filter-kategorie+section>.programm,
.filter-kategorie+.programm,
.filter-kategorie+.achse,
/* Faellt die Kategorieleiste weg, weil im Ausschnitt keine Kategorie belegt
   ist, steht die Leermeldung unter Zeitraum oder Monat - und braucht dort
   denselben engen Anschluss. */
.filter+.leer{margin-top:var(--takt-zeile)}
.zeile{display:grid;grid-template-columns:24fr 60fr 15fr;gap:var(--grid-gap);
  padding-block:var(--takt-zeile);border-bottom:1px solid var(--linie);
  transition:opacity var(--takt-hover) var(--kurve-hover)}

/* ---------- Lichtabfall ueber die Liste ----------
   Die Lampe steht im Fenster still, das Programm zieht an ihr vorbei. Jede Zeile
   liest ihren eigenen Abstand zur Lampe aus ihrer Lage im Fenster und leitet
   daraus --nah ab; die Farbregel oben rechnet mit diesem Wert dieselbe Skala
   noch einmal, nur mit weniger Licht.

   Es ist ein Abfall, kein Dimmer: --nah kann nur zuruecknehmen, was das Licht
   hinzugefuegt hat. Bei --licht:0 ist das Produkt null, und keine Paarung faellt
   je unter die Werte, die fuer den dunklen Raum nachgerechnet sind.

   Ohne view()-Zeitachse - heute Firefox - bleibt --nah bei 1: dann ist der Raum
   gleichmaessig belichtet, also genau der Zustand von vorher. */
@keyframes lichtabfall{from{--nah:.26}to{--nah:1}}

@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    /* Dieselbe Regel traegt die Zeitachse des Rueckblicks: dort stehen die
       meisten Zeilen der ganzen Seite, und ohne sie endete der Raum an der
       Programmliste - eine flach belichtete Wand hinter vierzehn Jahren.

       Die Programmzeile laeuft nur bei Licht mit. Ohne Licht liest niemand
       ihr --nah: die Farbregel oben ist dann abgeschaltet, und ein Wert, den
       keiner liest, muss auch nicht in jedem Bild neu gesetzt werden.

       Die Achsenzeile laeuft immer. Ihre Haarlinie haengt mit ihrer Deckkraft
       unmittelbar an --nah und nicht am Umweg ueber die Belichtung - sie
       verlaeuft also auch im dunklen Raum, und das ist so gewollt: die Achse
       zeigt Naehe, nicht Helligkeit. */
    :root[data-licht=an] .zeile,
    .achsenzeile{animation:lichtabfall linear both;
      animation-timeline:view();animation-range:cover 0% cover 100%}
  }
}

.zeile .wann{font-family:Delight;font-weight:400;font-size:var(--text-xl);line-height:1.25;
  text-transform:uppercase;margin:0}
.zeile .meta{font-family:Delight;font-size:var(--text-s);line-height:1.5;margin:0}
.zeile .kat{font-family:Delight;font-size:var(--text-s);line-height:1.5;
  text-transform:uppercase;color:var(--akzent,var(--farbe-default));margin:0}

/* Ein deutsches Kompositum bei 39px auf einem 375er Telefon schiebt die Seite
   sonst seitlich hinaus - und die Redaktion sieht es beim Eintragen nicht kommen.
   Es bricht ohne Strich um; warum, steht oben bei der Wand. */
.zeile .titel{font-family:Delight;font-weight:400;font-size:var(--h2);line-height:1.25;
  letter-spacing:1px;text-transform:uppercase;color:var(--titelfarbe);margin:0;
  overflow-wrap:break-word}
.zeile .titel strong{font-weight:900}

/* Heute traegt die Zeile die einzige Marke, die das System fuer »jetzt« kennt:
   den roten Punkt vom Startseitenmenue, auf Zeilengroesse. Rot markiert. */
.zeile.heute .wann{display:flex;align-items:baseline;gap:.8rem}
.zeile.heute .wann::before{content:"";flex:0 0 auto;width:.9rem;height:.9rem;
  border-radius:50%;background:var(--primary);transform:translateY(-.15em)}

.zeile .preis{font-family:Delight;font-size:var(--text-s);line-height:1.7;text-align:right;margin:0}
/* Eintritt frei ist der Normalfall - eine leere Preisangabe belegt keine Zeile.
   Und keinen Zeilenschritt: gestapelt blieb die leere Spalte als Rasterkind
   stehen und schob mit ihrem Abstand jede Zeile um acht Pixel auseinander -
   bei zwanzig Terminen ein Zentimeter Wand ohne Anlass. Auf dem Schirm aendert
   die Regel nichts, dort bleibt die dritte Spur ohnehin leer. */
.zeile .preis:empty{display:none}
.zeile>div:has(>.preis:empty){display:none}

/* ---------- Plakat in der Zeile (ohne Zeigergeraet, ohne Bewegung) ----------
   Das Vorschaubild am Cursor ist eine Zugabe fuer Zeigergeraete: es startet
   ohne feinen Zeiger gar nicht, und bei abgeschalteter Bewegung ebenfalls
   nicht. Wer mit dem Finger scrollt oder die Bewegung abgestellt hat, sah
   dadurch bisher ueberhaupt kein Plakat - dieselbe Luecke aus zwei Gruenden.

   Ein Plakat, das auf Antippen erscheint, waere die falsche Antwort: es
   bliebe stehen und laese sich als Zustand, genau wie der gedimmte Filter,
   den dieses System auf Touch deshalb nicht kennt. Also steht es fest in der
   Zeile. Damit ist es dort dauerhaft zu sehen und am Schirm nur fluechtig -
   das ist mehr als am Zeigergeraet, nicht gleich viel, und es ist gewollt.

   Die Form kommt nicht aus dem Baukasten, sondern aus der Haengung: gemeinsame
   Hoehe, Breite aus dem eigenen Seitenverhaeltnis, kein Zuschnitt. Eine Kachel
   schneidet zu, eine Haengung richtet aus - ein Hochformat steht schmal, ein
   Querformat laeuft breit, und die zerklueftete Kante ist das Bild von einem
   Plakat an der Wand. max-height und max-width zusammen, beide Masse auto:
   das Hochformat deckelt an der Hoehe, das seltene Panorama an der Spalte,
   und keines von beiden wird verzogen. */
.zeile-plakat{display:none}

/* Die Bedingung ist der Zeiger, nicht die Fensterbreite: exakt die Umkehrung
   dessen, woran hover-preview.js abbricht. Sonst bekaeme das breite
   Touch-Tablet weder das eine noch das andere, und das schmale Mausfenster
   bekaeme beides. prefers-reduced-motion steht daneben, weil das Modul auch
   dort nicht startet - und weil beide Abfragen im laufenden Betrieb kippen
   koennen: schaltet jemand die Bewegung wieder ein, faengt das Modul an und
   dieses Bild geht im selben Moment weg. Es liegt nie ein Plakat im Fluss,
   waehrend eines am Zeiger haengt. */
@media (hover:none), (pointer:coarse), (prefers-reduced-motion:reduce){
  /* Es haengt am Titel, in jedem Layout an derselben Stelle. In der
     Ausnahmespalte (15fr) waere es auf einem breiten Touch-Schirm rund 170px
     breit gewesen - eine Briefmarke, also genau das, wogegen es antritt.
     Getrennt wird es vom Titel durch den Schritt, den das System fuer »in der
     Zeile« kennt; ein neuer Wert waere hier der neunte Abstand.

     Die Hoehe steht fest, die Breite folgt dem Seitenverhaeltnis - die
     Grammatik der Haengung, nur mit einem Bild je Reihe. Sie muss fest stehen
     und darf nicht aus max-height kommen: ein noch nicht geladenes
     loading=lazy-Bild mit width:auto und height:auto belegt 0x0, die
     width/height-Attribute reservieren dann nichts, und die Zeile springt beim
     Nachladen auf - unter der Hand von jemandem, der gerade liest.

     object-fit uebernimmt den einen Fall, den eine feste Hoehe sonst verzoege:
     ein Panorama, das breiter ist als die Spalte, wird an der Breite gedeckelt
     und steht dann niedriger in seinem Feld, statt gestaucht zu werden. Es hat
     keine Flaeche, also ist das Feld die Wand - man sieht kein Kaestchen,
     sondern ein kuerzeres Bild. */
  .zeile-plakat{display:block;height:22rem;width:auto;max-width:100%;
    object-fit:contain;object-position:left center;
    margin-top:var(--takt-zeile)}
}

/* Der Leerzustand ist der eine Moment, in dem wirklich gelesen wird - er nennt
   den Filter, der die Liste geleert hat, und den Weg zurueck. */
.leer{color:var(--text-gedaempft);font-size:var(--text-m);line-height:1.7;
  padding-block:var(--takt-block);max-width:52ch}
.leer strong{font-weight:700;color:var(--titelfarbe)}
.leer a{text-decoration:underline;text-underline-offset:.2em}

/* ---------- Vorschaubild am Cursor ----------
   Das Canvas liegt fest ueber der Seite; gezeichnet wird nur, solange eine
   Zeile gehovert wird.

   Drei Lagen, in dieser Reihenfolge: das Lineament der Liste (Trennlinien,
   Achse, Achsenpunkte) ganz unten, darueber das Bild, darueber die Schrift.
   Das Bild laeuft also ueber die Linien hinweg, aber nie ueber ein Wort.

   Traeger der Lagen sind zwei verschiedene Elemente: die Zeile selbst zeichnet
   ihre Trennlinie (Rahmen, bleibt unten), die drei Spalten darin tragen die
   Schrift (angehoben). Deshalb bekommt .zeile ausdruecklich keinen z-index -
   ein eigener Stapelkontext wuerde die Spalten wieder mit hinunterziehen.

   Das gilt auch fuer alles darueber. Kein Vorfahr einer Liste darf ein
   Stapelkontext sein, sonst liegt die ganze Liste in einer Lage und das Bild
   ueber ihr - also ueber der Schrift. Im Rueckblick ist das einmal passiert:
   die Achse trug fuer den Jahressprung einen view-transition-name, und der
   macht einen. Sie traegt ihn jetzt nur noch waehrend des Sprungs, siehe
   html[data-sprung] .achse weiter unten. Wer hier etwas hinzufuegt - opacity,
   filter, transform, will-change, contain -, faellt in dieselbe Grube. */
.hover-canvas{position:fixed;inset:0;width:100%;height:100%;z-index:1;
  pointer-events:none;display:block}
.zeile>div{position:relative;z-index:2}
/* Solange das Canvas liegt, bleibt die gehoverte Zeile ungedimmt: das Bild ist
   die Rueckmeldung genug, und ein opacity-Wert unter 1 wuerde die Schrift in
   einen eigenen Stapelkontext sperren - sie verschwaende hinter dem Bild. */
/* Nur Zeilen, die wirklich ein Plakat mitbringen. Der Rueckblick ist der Fall,
   an dem der alte, weiter gefasste Selektor auffiel: dort traegt ein Bruchteil
   der Zeilen ein Bild, und alle uebrigen verloren dadurch ihre einzige
   Rueckmeldung, ohne eine neue zu bekommen. */
body.hat-vorschau .zeile[data-preview]:hover{opacity:1}

/* Gruppen der Programmliste: LAEUFT vor KOMMT. Eine Beschriftung, keine Landmarke -
   das Jahr im Archiv steht eine Stufe hoeher und darf groesser sein. Ueber der
   Ueberschrift steht mehr Luft als darunter; sie gehoert zu ihrer Liste. */
.gruppe{font-family:Delight;font-weight:900;font-size:var(--text-s);line-height:1.7;
  letter-spacing:.08em;text-transform:uppercase;color:var(--titelfarbe);
  margin:var(--takt-block) 0 0}
.gruppe+.programm{margin-top:var(--takt-eng)}
/* Folgt eine Gruppe auf eine Leermeldung (die 404 zeigt, was stattdessen haengt),
   traegt deren eigener Blockabstand den Schritt schon - sonst stuende er doppelt. */
.leer+section>.gruppe{margin-top:0}

/* Es gibt nichts zu kaufen, aber etwas zu merken. */
.kalender-abo{margin:var(--takt-block) 0 0}
.kalender-abo a{font-family:Delight;font-weight:900;font-size:var(--text-s);
  line-height:1.7;text-transform:uppercase;color:var(--titelfarbe)}
.kalender-abo a::before{content:"↓ "}
/* Der Download ist die Nebenauskunft: derselbe Satzbau, eine Stufe leiser. */
.kalender-abo .dazu{font-weight:400;color:var(--text-still);margin-left:1.6rem}
.kalender-abo .dazu::before{content:none}

/* ---------- Rueckblick: Dichtestreifen ----------
   Das Portraet des Hauses in einer Zeile. Die einzige Farbe darin ist die, die
   das Programm selbst mitgebracht hat - keine Skala, kein Verlauf. */
.dichte{margin:var(--takt-block) 0 0}
.dichte svg{display:block;width:100%;height:3rem}
.dichte figcaption{position:relative;height:2.4rem;margin-top:.6rem;
  border-top:1px solid var(--linie)}
.dichte figcaption .jahr{position:absolute;top:.6rem;font-family:Delight;
  font-size:var(--text-xs);line-height:1;color:var(--text-still);
  padding-left:.4rem;border-left:1px solid var(--linie);
  transition:opacity var(--takt-hover) var(--kurve-hover)}

/* ---------- Rueckblick: die Zeitachse ----------
   Die senkrechte Linie sitzt auf der Datumsspalte des Programmrasters. Die
   Timeline ist kein neues Layout, sondern die Programmliste, der eine Achse
   gewachsen ist - wer vom Programm kommt, erkennt dieselbe Zeile wieder.

   Sie sitzt auf der Kante der Datumsspalte, nicht in der Mitte der Gasse: die
   Kante ist die Grenze zwischen wann und was, und die freie Gasse dahinter ist
   der Platz, an dem die Jahreszahl haengt. 24fr von 24+60+15, abzueglich der
   beiden Spaltenabstaende in ihrem Anteil. */
.achse{--achse-x:calc(24.2424% - .4848 * var(--grid-gap));position:relative;
  margin-top:var(--takt-block)}
/* Jedes Jahr ist eine Gruppe: der Bezugsrahmen, in dem seine Zahl haengt. */
.jahrgruppe{position:relative}

/* Die Jahreszahl haengt an der Achse und laeuft mit ihrem Jahr mit - senkrecht,
   in der Gasse zwischen Datum und Titel, festgehalten, solange das Jahr im Bild
   ist. Sie hat deshalb keine Flaeche mehr: eine Platte in der unbelichteten
   Wandfarbe stand bei brennendem Barlicht als dunkles Rechteck auf der hellen
   Wand und schnitt ausserdem das Vorschaubild ab. Das Jahr steht jetzt in der
   Zeit, statt sie zu verdecken.

   Sie steht in der Beschriftungs-Groesse des Systems - dieselbe, die Filter,
   Ticket-Knopf und Fussmenue tragen. Die 8rem Hoehe sind die Laenge der vier
   Ziffern und werden per negativem Aussenabstand gleich wieder herausgerechnet:
   die Zahl nimmt keine Zeile ein, loest sich aber rechtzeitig vom Rand, damit
   zwei Jahre nie uebereinander liegen. */
/* Ohne Zeigerereignisse: die Zahl liegt in der Gasse und damit ueber der ersten
   Zeile ihrer Gruppe. Sie darf dort kein Loch in deren Trefferflaeche schlagen. */
.jahrmarke{position:sticky;top:var(--takt-zeile);z-index:2;pointer-events:none;
  height:8rem;margin:0 0 -8rem calc(var(--achse-x) + .4rem);
  writing-mode:vertical-rl;
  font-family:Delight;font-weight:900;font-size:var(--text-s);line-height:1;
  letter-spacing:.18em;text-transform:uppercase;color:var(--titelfarbe)}

/* Die Achse ist nicht mehr eine Linie ueber der ganzen Liste, sondern ein Stueck
   je Zeile. Damit liest sie dasselbe --nah wie die Zeile selbst: oben an der
   Lampe steht sie voll, unten faellt sie auf ein Zehntel - man sieht am Rand des
   Auges, wie weit man in der Zeit gekommen ist. Das ist kein Verlauf auf einem
   Element, es ist die Belichtung des Raums, an der Achse abgelesen.

   Ohne view()-Zeitachse - heute Firefox - und bei reduzierter Bewegung bleibt
   --nah bei 1: dann ist die Achse durchgehend gleich hell, also genau die Linie
   von vorher. */
/* Der Rueckweg dimmt beim Ueberfahren eines Streifensegments Dutzende Zeilen
   auf einmal. Ohne Uebergang liest sich das als Neuzeichnen der Seite, nicht
   als Rueckmeldung - und unterlaeuft damit genau das, was die Kopplung zeigen
   soll. Es ist dieselbe Dauer und dieselbe Kurve wie ueberall sonst. */
.achsenzeile{position:relative;transition:opacity var(--takt-hover) var(--kurve-hover)}
.achsenzeile::before{content:"";position:absolute;left:var(--achse-x);top:0;bottom:0;
  width:1px;background:var(--linie);opacity:calc(.2 + .8 * var(--nah))}

/* Der Punkt sitzt auf der Achse, in der Farbe seiner Kategorie, auf der Mittellinie
   der Datumszeile. Die Schriftgroesse der Pseudoelemente ist dieselbe wie die des
   Datums, damit .625em (die halbe Zeilenhoehe) mitwaechst. Er steht als ::after
   hinter der Linie in der Malreihenfolge - ein Punkt auf der Achse, nicht darunter. */
.achsenzeile::after{content:"";position:absolute;left:var(--achse-x);
  font-size:var(--text-xl);top:calc(2.6rem + .625em);
  width:.8rem;height:.8rem;margin:-.4rem 0 0 -.4rem;border-radius:50%;
  background:var(--akzent,var(--farbe-default))}
/* Eine Laufzeit ist ein Strich, kein Punkt - sichtbar laenger, ohne Massstab. */
.achsenzeile.spanne::after{width:.2rem;height:2.4rem;margin:-1.2rem 0 0 -.1rem;
  border-radius:0}

/* ---------- Rueckblick: Streifen und Achse wissen voneinander ----------
   Es ist dasselbe Programm in zwei Darstellungen. Die Standmarke sagt, wo in den
   vierzehn Jahren die Liste gerade steht; das Ueberfahren eines Monatssegments
   nimmt umgekehrt alles zurueck, was nicht zu diesem Monat gehoert.

   Beides ist Rueckmeldung auf eine Handlung, keine Bewegung: die Marke springt,
   sie faehrt nicht, und sie bleibt deshalb auch bei reduzierter Bewegung. */
.dichte{position:relative}
/* Die Marke faehrt, statt zu springen: die Kopplung zwischen Liste und Streifen
   wird dadurch sichtbar, statt behauptet. Sie faehrt nur, wenn der Monat
   wechselt - rueckblick.js schreibt nur dann. Bei reduzierter Bewegung springt
   sie wieder; der pauschale Block unten greift nur auf animation, deshalb steht
   die Ausnahme dort ausdruecklich. */
.dichte-marke{transition:left var(--takt-hover) var(--kurve-hover);
  position:absolute;top:0;height:3rem;width:1px;
  background:var(--titelfarbe);pointer-events:none}
.achse.sucht .achsenzeile:not(.treffer){opacity:.3}
.dichte svg a rect{transition:fill var(--takt-hover) var(--kurve-hover)}
.dichte svg a.mit rect{fill:var(--titelfarbe)}

/* ---------- Rueckblick: Der Griff ----------
   Auf einem Zeigergeraet ist der Streifen ein Instrument: ueberfahren nimmt die
   Liste zurueck, anklicken springt ins Jahr. Auf dem Telefon war er ein Bild.
   Gemessen an einem 375er Schirm: fuenfundzwanzig Segmente zu 7,6 x 4,3 px -
   ein Zehntel des Bodens, den dieselbe Seite jedem Kategoriefilter gibt.

   Er wird deshalb nicht angetippt, sondern gehalten. Der Daumen faehrt ueber
   die Jahre, unter ihm steht der Monat, und die Liste nimmt zurueck, was nicht
   dazugehoert - dieselbe Rueckmeldung, die die Maus im Vorbeifahren bekommt.
   Beim Loslassen geht es dorthin.

   Das ist kein Hover auf Touch. Der Grund, aus dem es hier keinen gibt, ist,
   dass ein angetippter Zustand stehenbleibt und sich als Filter liest; eine
   Geste, die mit dem Finger endet, kann das nicht. Und es ist derselbe Griff
   wie an der Lampe (lampe.css, »Der Griff«): eine Ursache, die Hand heisst,
   und ein Ende, das von selbst kommt.

   Senkrecht bleibt der Seite: pan-y laesst das Scrollen durch und faengt nur
   die waagerechte Fahrt ab - die Achse ist waagerecht, also ist sie unsere.
   Ohne Skript steht kein data-griff da und der ganze Block ist wirkungslos. */
.dichte[data-griff]{touch-action:pan-y;-webkit-user-select:none;user-select:none;
  -webkit-touch-callout:none}

/* Die Flaeche waechst, das Aussehen nicht - dieselbe Regel wie fuer die Kreise
   im Fuss. Der Streifen misst 3rem; 7px oben und unten heben den Griff auf die
   44px, die diese Seite jedem Ziel schuldet. Die Beschriftungszeile darunter
   traegt nichts Anklickbares, es wird also nichts verdeckt. */
.dichte[data-griff]::before{content:"";position:absolute;inset:-.7rem 0 auto;
  height:calc(3rem + 1.4rem)}

/* Gehalten: der Monat unter dem Daumen steht wie ein ueberfahrenes Segment -
   dieselbe Marke, andere Hand. */
.dichte svg a.griff rect{fill:var(--titelfarbe)}

/* Die Ablesung. Sie steht in der Beschriftungszeile und nimmt sie ganz: die
   Jahreszahlen sind die Legende dieser Achse, der Monat ihre genaue Stelle, und
   beide zugleich waeren zwei Schriften auf einer Zeile. Die Zeile behaelt dabei
   Hoehe, Ort und Haarlinie - es wird nichts umgebrochen und nichts geschoben,
   und mit dem Finger ist alles wieder da.

   Sie weicht dem Daumen aus: liegt er links, steht sie rechts und umgekehrt.
   Eine Ablesung unter der Hand, die sie ablesen will, ist keine. */
.dichte-wort{position:absolute;top:.6rem;font-family:Delight;font-weight:900;
  font-size:var(--text-xs);line-height:1;text-transform:uppercase;
  color:var(--titelfarbe);white-space:nowrap;
  pointer-events:none;opacity:0;
  transition:opacity var(--takt-hover) var(--kurve-hover)}
.dichte-wort[data-seite=links]{left:0;right:auto}
.dichte-wort[data-seite=rechts]{right:0;left:auto}
.dichte.gegriffen .dichte-wort{opacity:1}
.dichte.gegriffen figcaption .jahr{opacity:0}

/* ---------- Rueckblick: blaettern ---------- */
.blaettern{display:flex;gap:2rem;margin-top:var(--takt-block)}
.blaettern a{font-family:Delight;font-weight:900;font-size:var(--text-s);
  line-height:1.7;text-transform:uppercase;color:var(--titelfarbe)}
.blaettern a[rel=next]{margin-left:auto}

/* ---------- Gestaltung aus propaganda ----------

   Die App schickt am Termin **Woerter** mit, keine Farbwerte - `kategorie`,
   `duplex`, `versal`. Aufgeloest werden sie hier, und nur hier. Das ist kein
   Umweg: die Farben dieses Hauses rechnen mit `--belichtung`, sie aendern sich
   also mit dem Licht in der Bar. Ein Hexwert aus einer Datei koennte das nicht
   und waere ab dem ersten Abend falsch.

   **Uebernommen wird Material, nie Komposition.** Was hier steht, faerbt und
   behandelt; das Raster der Detailseite bleibt unangetastet. Eine Seite scrollt
   und wird gelesen - ein Plakatraster darauf waere kein konsistentes Haus,
   sondern eine unlesbare Seite mit Haltung.

   Ein Termin ohne diese Attribute faellt durch alle Regeln hindurch und sieht
   aus wie immer. */

/* Der Grund. `kategorie` ist der laute Fall - dann traegt die Seite die Farbe
   der Kategorie als Flaeche, und die Tinte muss mitwechseln. */
article[data-grund="kategorie"]{
  background:var(--akzent,var(--farbe-default));
  color:var(--wand);
  padding:var(--takt-block) var(--grid-gap);
  margin-top:var(--takt-block);

  /* Zwei Blockabstaende mehr ueber dem Auftakt - der eigene Rand der Flaeche
     und ihr Innenrand. Ohne die Zulage rechnete der Auftakt mit einem Kopf,
     den es auf dieser Seite so nicht gibt, und das Plakat schoebe den Titel
     genau um diese zwei Abstaende unter die Falz. */
  --auftakt-zulage:calc(var(--takt-block) * 2);

  /* **Ein Grund, eine Tinte — und dafuer wird nicht ueberschrieben, sondern
     umdefiniert.** Das Haus faerbt an vielen Stellen mit `var(--titelfarbe)`:
     die Datumszeile, Linien, stille Texte. Auf einem uebernommenen Grund
     leuchteten die weiter, als gaebe es ihn nicht — und ausgerechnet das Datum
     war betroffen, die eine Zeile, wegen der jemand diese Seite oeffnet.

     Jede dieser Regeln einzeln zu ueberschreiben waere ein zweiter Satz
     Farbregeln neben dem ersten und beim naechsten Zusatz im Haus wieder
     unvollstaendig. Stattdessen bekommt der Artikel andere Werte fuer dieselben
     Namen: es gibt keinen zweiten Satz Farbwerte, es gibt eine Skala. */
  --titelfarbe:var(--wand);
  --farbe-default:var(--wand);
  --text-still:rgb(26 26 26 / .62);
  --text-gedaempft:rgb(26 26 26 / .78);
  --linie:rgb(26 26 26 / .28);
}
article[data-grund="tiefschwarz"]{background:var(--tiefe,#212121)}

/* Die Tinte folgt dem Grund. Sie wird nur gesetzt, wo der Grund gewechselt hat -
   sonst gilt weiter, was das Haus ohnehin setzt. */
article[data-tinte="wandschwarz"],
article[data-tinte="gegenkategorie"]{color:var(--wand)}
article[data-tinte="titelweiss"],
article[data-tinte="blattweiss"]{color:var(--titelfarbe)}
article[data-grund="kategorie"] .event-titel,
article[data-tinte="wandschwarz"] .event-titel,
article[data-tinte="gegenkategorie"] .event-titel{color:inherit}
/* **Wo der Akzent selbst der Grund ist, kann nichts mehr in ihm stehen.** Die
   Kategoriezeile faerbt sich mit `var(--akzent, ...)` - auf einem Grund aus
   ebendiesem Akzent stand sie damit unsichtbar in sich selbst. `--akzent`
   umzudefinieren geht hier nicht: derselbe Wert traegt eine Zeile darueber den
   Hintergrund. Also dieser eine Selektor, und er muss die Regel des Hauses
   ueberbieten - deshalb der Weg ueber `.event-kopf`. */
article[data-grund="kategorie"] .event-kopf .kat{color:var(--wand)}
article[data-grund="kategorie"] .balken{background:var(--wand)}

/* Die Stimme des Titels: Versalien und Gewicht. Einen freien Grad gibt es
   nicht - das waere eine Groessenangabe, und die gehoert ans Blatt. */
article[data-titel="versal"] .event-titel{
  font-weight:var(--titel-gewicht,900);
  letter-spacing:-.015em;
  line-height:1.05;
}

/* Die Bildbehandlung. Dieselben Werte wie am Blatt - wer sie hier aendert,
   muss sie dort mitaendern, sonst zeigen Seite und Aushang zwei Bilder. */
article[data-behandlung="grau"] .event-bilder img{filter:grayscale(1) contrast(1.08)}
article[data-behandlung="hart"] .event-bilder img{filter:grayscale(1) contrast(2.1) brightness(.94)}
/* Duplex ist ein Siebdruck, kein Graustich: dunkel wird Tinte, hell laesst den
   Grund der Seite stehen. Die Filterkette steht **im Dokument** und nicht in
   einer eigenen Datei - `filter:url(datei.svg#id)` traegt in Chrome nicht, und
   ein Effekt, der in einem Browser fehlt, waere schlimmer als keiner. Das
   Snippet legt sie ins Markup, sobald ein Termin sie braucht. */
article[data-behandlung="duplex"] .event-bilder img{
  filter:url(#gestaltung-duplex);
}

/* **Wieviel Raum das Bild bekommt** - drei Stufen, keine Zahl. Am Blatt ist
   der Bildanteil ein Bruchteil der Flaeche; eine Seite hat keine, also traegt
   sie stattdessen die Auffaelligkeit: schmal, Spalte, voll.

   **Beschnitten wird hier nie.** Ein »Band« ist am Blatt ein geschnittener
   Streifen, weil das Blatt einen Ausschnitt kennt - die Seite kennt keinen. Sie
   gibt dem Bild dann weniger Raum, statt es blind zu schneiden: ein Plakat, dem
   der Titel abgeschnitten wird, waere schlimmer als ein kleines Plakat.

   **Der freie Raum ist jetzt eine Hoehe und keine Spalte mehr.** Seit das
   Plakat den Auftakt fuehrt, misst die Seite ihm den ersten Bildschirm zu -
   und was daran verhandelbar bleibt, ist der Anteil, den es davon nimmt. Ohne
   Angabe nimmt es alles: das ist die Regel des Auftakts und zugleich die
   lauteste der drei Stufen, deshalb steht sie dort und nicht hier. */
article[data-bild="schmal"] .event-bilder{--bildanteil:.55}
article[data-bild="spalte"] .event-bilder{--bildanteil:.78}
article[data-bild="voll"] .event-bilder{--bildanteil:1}

/* Der Schleier: die Lampe als Flaeche hinter der Seite, angeschnitten wie am
   Blatt. Sie liegt hinter allem und nimmt die Tinte an. */
article[data-schleier]{position:relative;isolation:isolate}
/* **Als Maske, nicht als Bild.** Nur so folgt die Farbe der Tinte der Seite -
   und nur so kehrt der Schleier auf hellem Grund mit um. Ein eingefaerbtes
   Bild waere auf einem farbigen Grund weiss geblieben. */
article[data-schleier]::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:currentColor;
  -webkit-mask:url(../img/logo.svg) no-repeat right top / auto 140%;
  mask:url(../img/logo.svg) no-repeat right top / auto 140%;
  opacity:.13;
}

/* ---------- Die Achse der Veranstaltungsseite ----------
   Eine Spalte in der Mitte, Wand zu beiden Seiten. Die Seite stand bis hierher
   ganz links: eine 74 Zeichen breite Textspalte am Rand einer 1350 px breiten
   Wand, unter einem Zeichen, das mittig haengt. Zwei Achsen auf einer Seite,
   und die staerkere - die des Hauszeichens - war leer.

   In der Spalte steht, was gelesen wird: Kategorie und Titel, die Termindaten,
   der Text, der Nachtrag, der Weg zurueck. Die ganze Wand nehmen die beiden
   Dinge, die sie brauchen: das Plakat im Auftakt und die Haengung.

   **Das Raster steht am <article> und nicht an `main`.** Der Artikel ist auf
   dieser Seite selbst ein Grund (`data-grund`), und ein auf 62ch gekappter
   Grund waere ein Streifen. Er behaelt darum die volle Breite und traegt die
   Spalte in sich, statt selbst eine zu sein.

   `min(62ch, 100%)` und nicht `62ch`: die beiden Randspuren koennen nicht
   negativ werden, eine feste Zahl liefe unterhalb der Spaltenbreite also aus
   der Wand heraus. */
.event-seite{--spalte:min(62ch, 100%);position:relative;
  display:grid;grid-template-columns:1fr var(--spalte) 1fr}
.event-seite>*{grid-column:2}
.event-seite>.event-auftakt,
.event-seite>.haengung-block{grid-column:1 / -1}
/* Ein Rasterfeld ist so breit wie seine Spur. Ein Verweis, der die ganze Spalte
   anfasst, ist eine Flaeche und kein Wort - er bleibt an seinem Anfang stehen.
   Die Regel gilt fuer beide Lagen: auf groben Zeigern ist der Weg zurueck ein
   inline-flex mit 44 px Mindesthoehe und waere sonst 74 Zeichen breit.

   Seit die Reihe am Fuss steht, ist der Weg zurueck ein Feld dieser Zeile und
   nicht mehr ein Kind des Artikels - die Regel gilt jetzt dort. */
/* In der Reihe traegt die Zeile den Abstand, nicht der Verweis darin. Und er
   steht hier als einziger in Titelweiss: die Betonung liegt auf dem Ausgang. */
.reihe-fuss>.zurueck{justify-self:center;margin-top:0;color:var(--titelfarbe)}

/* **Der Wisch nimmt die Querachse, das Scrollen behaelt die Laengsachse.**
   Ohne diese Angabe entscheidet der Browser waehrend der Geste, ob er sie
   selbst braucht, und bricht sie mitten im Ziehen ab. `pinch-zoom` steht
   ausdruecklich dabei: eine Seite, auf der man nicht mehr aufziehen kann, hat
   fuer eine Wischgeste die Lupe verkauft. Auf dieser Seite gibt es nichts, was
   quer liefe - die Haengung bricht um, die Plakate stehen nebeneinander im
   Fluss -, also ist nichts weggenommen. */
.event-seite{touch-action:pan-y pinch-zoom}

/* ---------- Der Auftakt ----------
   **Erst das Plakat, dann der Titel** - und beide zusammen auf genau einem
   Bildschirm. Wer hier ankommt, kommt fast immer ueber einen geteilten Link,
   und was ihn geoeffnet hat, war das Bild. Es stand bisher rechts neben den
   Termindaten, in zwei Dritteln der Wand, unter einem Titel, den es haette
   ankuendigen sollen. Jetzt fuehrt es, und der Titel liest sich darunter in
   der Breite der Textspalte - dieselbe Spalte, die auch die Termindaten und
   den Text traegt. Eine Achse von oben bis unten.

   **Der Deckel ist der Bildschirm, das Ziel ist sein Rand.** Das Bild bekommt
   genau den Rest, den der Titel uebriglaesst: keine Zeile weniger, damit der
   Auftritt nicht verschenkt wird, und keine mehr, damit der Titel nicht unter
   die Falz rutscht. Ein Plakat, das seinen eigenen Titel verdeckt, kuendigt
   nichts mehr an.

   Gerechnet wird aus Groessen, die ohnehin im Haus stehen - Kopfrand,
   Zeichenhoehe, Blockabstand - und einem Fussmass, damit der Titel nicht auf
   der Kante steht. Ohne Plakat wird gar nichts gerechnet: dann traegt der
   Auftakt nur den Titel und ist so hoch wie dieser.

   `svh` und nicht `vh`: auf dem Telefon ist der Bildschirm waehrend des
   Scrollens groesser als beim Laden, und ein Deckel, der nur in der groesseren
   Lage haelt, haelt nicht. Die vh-Zeile darueber ist der Rueckfall fuer
   Browser ohne die Einheit - dort steht es wie bisher. */
.event-auftakt{margin-top:var(--takt-block)}
.event-auftakt--bild{
  --auftakt-abzug:calc(var(--kopf-oben) + var(--logo-hoehe)
    + var(--takt-block) + var(--takt-zeile) + var(--auftakt-zulage, 0px));
  display:flex;flex-direction:column;gap:var(--takt-zeile);
  height:calc(100vh - var(--auftakt-abzug));
  height:calc(100svh - var(--auftakt-abzug))}
/* Der Titel gibt nichts ab. Er ist das Mass, aus dem der Rest fuer das Bild
   folgt - schruempfte er mit, gaebe es kein Mass mehr, sondern zwei Groessen,
   die sich gegenseitig nachgeben. */
.event-kopf{margin-top:var(--takt-block);max-width:62ch}
/* Im Auftakt traegt der Abstand der Auftakt selbst; im Flexkasten fallen zwei
   Raender nicht mehr zusammen, und der zweite stuende in der Rechnung. Auf der
   Fotoseite, wo derselbe Kopf ohne Auftakt steht, bleibt er, wie er war. */
.event-auftakt--bild .event-kopf{flex:none;margin-top:0}
/* Der Auftakt nimmt die ganze Wand, der Titel darin aber nicht: er steht in der
   Spalte wie alles, was gelesen wird. Weil `max-width` hier in derselben
   Schrift und Groesse rechnet wie die Spur des Rasters, sind es dieselben
   62ch - eine Achse, zwei Wege dorthin.

   `width:100%` steht dabei nicht zur Zierde: im Auftakt mit Plakat ist der Kopf
   ein Flexkind, und ein Flexkind streckt sich nur, solange kein Rand der
   Querachse `auto` ist. Mit den beiden `auto`-Raendern - und die braucht es
   fuer die Mitte - fiel `stretch` weg, der Kopf schrumpfte auf die Breite
   seines Titels, und die Mitte schob ihn ein. Sichtbar war das nur bei kurzen
   Titeln: lange fuellten die 62ch aus und standen zufaellig richtig, »Open Mic«
   stand 240px zu weit rechts. Die Breite gehoert der Spalte, nicht dem Wort. */
.event-auftakt .event-kopf{width:100%;margin-inline:auto}
.event-kopf .kat{font-family:"IBM Plex";font-size:var(--text-s);line-height:1.4;
  text-transform:uppercase;color:var(--akzent,var(--farbe-default));margin:0 0 .6rem}
.event-titel{font-family:Delight;font-weight:400;font-size:var(--h1);line-height:1.25;
  text-transform:uppercase;color:var(--titelfarbe);margin:0;
  overflow-wrap:break-word}
.event-titel strong{font-weight:900}

/* Die Antwort auf »wann muss ich wo sein« - die eine Frage, wegen der jemand
   hier ist. Sie stand als vier gleich grosse Zeilen im Abstand der
   Browser-Absatzraender: 196 px, in denen nichts fuehrt und nichts
   zusammengehoert. Jetzt fuehrt der Tag, Zeit und Laufzeit haengen dicht
   darunter, der Ort steht einen Schritt daneben, und was zu tun ist, kommt
   nach dem Blockabstand. Eine Angabe, drei Gruppen, drei verschiedene
   Abstaende - das ist die Kadenz. */
.event-daten{margin-top:var(--takt-block);max-width:62ch;
  font-family:Delight;font-size:var(--text-m);line-height:1.4}
.event-daten p{margin:0}
.event-daten .datum{font-weight:900;font-size:var(--text-l);line-height:1.25;
  text-transform:uppercase;color:var(--titelfarbe)}
.event-daten .zeit,
.event-daten .bis{margin-top:.6rem}
.event-daten .ort{margin-top:var(--takt-eng)}
.event-daten .eintritt{font-size:var(--text-s);margin-top:var(--takt-zeile)}
.event-daten .ticket,
.event-daten .kalender{display:inline-block;margin-top:var(--takt-zeile);padding:.72rem 1.8rem;
  background:var(--titelfarbe);color:var(--dunkel);font-family:Delight;font-weight:900;
  font-size:var(--text-s);text-transform:uppercase;border-radius:2px}
/* Die Plakatstelle. Sie nimmt, was der Auftakt ihr laesst, und gibt es an das
   Bild weiter - deshalb steht hier eine Hoehe und keine Breite.

   **Zwei Plakate stehen nebeneinander, nicht uebereinander.** Gestapelt haetten
   beide eine halbe Hoehe, und zwei halbe Plakate sind kein Auftakt, sondern
   zwei Briefmarken. Nebeneinander behaelt jedes die volle.

   Aufgesetzt wird unten: was kleiner ausfaellt als sein Platz - ein liegendes
   Bild, eine gedaempfte Stufe -, sitzt auf dem Titel statt in der Mitte seines
   Kastens zu schweben. Der Leerraum sammelt sich dann oben, unter dem Zeichen,
   wo er wie Luft aussieht und nicht wie ein Riss zwischen zwei Dingen, die
   zusammengehoeren.

   **Links an der Spalte, rechts an der Wand.** Das Plakat beginnt dort, wo der
   Titel darunter beginnt: eine Kante, an der beide haengen, und der Blick faellt
   vom Bild in die erste Zeile, statt dazwischen einen Schritt zur Seite zu
   machen. Ein Bild ist kein Satz - es braucht keine zweite Kante, und rechts
   endet es darum, wo es zu Ende ist.

   **Nach rechts gilt trotzdem die Wand und nicht die Spalte.** Mehrere Plakate
   in einer 62ch-Spalte waeren mehrere halbe Plakate, und der Auftakt gaebe
   genau das her, was er ankuendigen soll. Der Einzug ist darum die linke
   Randspur des Rasters - dieselbe Zahl, aus demselben `--spalte`, damit die
   beiden Masse nicht auseinanderlaufen -, und was rechts davon liegt, steht der
   Reihe offen.

   Wie gross die Bilder werden, entscheidet die erste Grenze, die haelt: die
   Hoehe des Auftakts oder der Rest der Wand. Stehende Plakate stossen an die
   Hoehe und stehen dann in voller Groesse nebeneinander; liegende oder viele
   stossen an die Breite und geben gemeinsam nach - `max-width` deckelt jedes
   Feld, `contain` haelt jedes Verhaeltnis, und weil alle um denselben Faktor
   schrumpfen, bleibt die gemeinsame Hoehe gemeinsam. */
.event-bilder{flex:1 1 auto;min-height:0;
  display:flex;gap:var(--grid-gap);align-items:flex-end;
  margin-left:calc((100% - var(--spalte)) / 2)}
.event-bilder a{display:block;min-width:0;height:calc(100% * var(--bildanteil, 1))}
/* Die Hoehe fuehrt, die Breite folgt ihr aus dem Seitenverhaeltnis. Wird das
   Bild dabei breiter als die Wand, deckelt max-width - und `contain` haelt das
   Verhaeltnis, statt zu zerren. Beschnitten wird auch hier nie. */
.event-bilder img{display:block;height:100%;width:auto;max-width:100%;
  object-fit:contain;object-position:left bottom}

/* ---------- Die Haengung ----------
   Die Fotos, die nach der Veranstaltung dazukommen. Kein Karussell, kein
   Kachelraster, keine Karten: Bilder haengen auf einer Schiene. Eine Reihe,
   gemeinsame Hoehe, Breiten aus dem eigenen Seitenverhaeltnis.

   Das Seitenverhaeltnis traegt das Layout zweimal - als Breite bei Zielhoehe
   (flex-basis) und als Anteil am Rest der Zeile (flex-grow). Weil beide
   proportional zu ihm sind, kuerzt es sich in der Hoehe weg: jedes Bild einer
   Reihe steht exakt gleich hoch, und keines wird dafuer beschnitten. Genau das
   trennt eine Haengung von einer Kachelwand - eine Kachel schneidet zu, eine
   Haengung richtet aus. */
.haengung-block{margin-top:var(--takt-block)}
/* Der Nachweis steht einmal ueber allem, nicht an jedem Bild. Ein Name, der an
   hundert Fotos wiederholt wird, ist kein Nachweis mehr, sondern ein Muster. */
.nachweis{margin:0 0 var(--takt-zeile);font-family:Delight;font-weight:900;
  font-size:var(--text-s);text-transform:uppercase;color:var(--text-gedaempft)}

/* Die Zielhoehe einer Reihe. Gemessen: darueber - bei 34vh - fielen zu wenige
   Bilder in eine Reihe, und der Rest, den sich zwei Bilder teilten, machte aus
   einer Reihe von 279px die naechste von 518px. Bei 26vh liegen die Reihen einer
   Haengung zwischen 213 und 253px: verschieden hoch, wie an einer Wand, aber
   ohne dass eine Reihe die Seite an sich reisst. */
.haengung{--reihe:clamp(20rem, 26vh, 34rem);
  display:flex;flex-wrap:wrap;gap:var(--grid-gap)}
.haengung a{flex:var(--seite) 1 calc(var(--seite) * var(--reihe));min-width:0}
/* Ein einzelnes Foto ist keine Reihe. Es haengt gross, wie ein Bild, das allein
   an einer Wand haengt - dieselbe Rechnung, nur ein anderes Mass. */
.haengung a:only-child{flex-basis:calc(var(--seite) * 68vh)}
.haengung img{display:block;width:100%;height:auto;aspect-ratio:var(--seite)}
/* Die letzte Reihe endet, sie streckt sich nicht. Ein unsichtbarer Platzhalter
   nimmt ihren Rest auf - sonst waeren die letzten zwei Bilder das groesste
   Ereignis der Seite, nur weil zufaellig zwei uebrig blieben. Eine Haengung an
   einer echten Wand hoert genauso auf: mitten auf der Wand. */
.haengung::after{content:"";flex:999999 0 0;height:0}

.haengung-mehr{display:inline-block;margin-top:var(--takt-zeile);
  font-family:Delight;font-weight:900;font-size:var(--text-s);text-transform:uppercase}




/* 72ch sind nicht 72 Zeichen: ch misst die Null, und deutsche Kleinbuchstaben
   sind schmaler - gemessen liefen 86 Zeichen pro Zeile. 62ch treffen die 72. */
.body{margin-top:var(--takt-block);max-width:62ch;font-size:var(--text-m);line-height:1.7}
.body p{margin:0 0 1.7em}
/* Der letzte Absatz traegt seinen Abstand nicht ueber den Block hinaus. Seit
   main eine eigene Spalte ist, faellt er nicht mehr heraus und verschmilzt
   nicht mehr mit dem Abstand des Fusses - er wuerde sich zu ihm addieren, und
   60 px vor dem Fuss gelten einmal. */
.body>:last-child{margin-bottom:0}
.body a{text-decoration:underline;text-underline-offset:.2em}
.body h2,.body h3{font-family:Delight;font-weight:900;text-transform:uppercase;
  line-height:1.15;margin:2em 0 .6em}
.body h2{font-size:var(--h3)} .body h3{font-size:var(--h4)}
.body figure{margin:var(--takt-block) 0}
.body figcaption{margin-top:var(--takt-eng);font-size:var(--text-s);
  line-height:1.5;color:var(--text-gedaempft)}
.body .embed iframe{display:block;width:100%;aspect-ratio:16/9;border:0}

.body blockquote{margin:2em 0;padding-left:1.5em;border-left:2px solid var(--primary)}

.support{margin-top:var(--takt-block);padding-top:var(--takt-zeile);
  border-top:1px solid var(--linie);
  font-size:var(--text-s);color:var(--text-gedaempft)}
.support h2{font-family:Delight;font-weight:900;font-size:var(--text-s);
  text-transform:uppercase;margin:0 0 .6rem}
.support a{text-decoration:underline;text-underline-offset:.2em}

.zurueck{display:inline-block;margin-top:var(--takt-block);font-family:Delight;font-weight:900;
  font-size:var(--text-s);text-transform:uppercase}

/* ---------- Die Reihe ----------
   **Der Weg weiter und der Weg zurueck.** Bis hierher endete jede
   Veranstaltungsseite mit einem einzigen »← Programm« - und das schickte einen
   Termin von 2019 auf die Liste der kommenden und verwarf unterwegs jede
   Filterwahl. Der Weg *hinein* war gestaltet (der wandernde Titel), der Weg
   weiter und zurueck war es nicht.

   Die Reihe ist die Liste, aus der jemand gekommen ist - mit ihrem Zeitraum,
   ihrem Monat, ihrer Kategorie, ihrem Jahr. Sie steht an zwei Orten:

   1. **am Fuss**, als Zeile aus drei Teilen, ueberall und ohne Bedingung;
   2. **an den beiden Raendern der Wand**, ab 1180px, als mitlaufende Spuren.

   Der zweite Ort ist die Zugabe fuer Auge und Maus, der erste ist der Boden.
   Auf einem Telefon gibt es nur den Fuss und den Wisch - und weil ein Wisch
   niemandem sagt, dass es ihn gibt, muss der Fuss die Auskunft allein tragen.

   **Die Reihe spricht in Datum und Kategorie.** Genau die beiden Angaben, die
   die Programmzeile links traegt. Nicht den Titel: der gehoert auf die Seite,
   zu der der Verweis fuehrt, und senkrecht in eine 9rem breite Spur gesetzt
   waere er ein Band. */

.reihe-fuss{margin-top:var(--takt-block);padding-top:var(--takt-zeile);
  border-top:1px solid var(--linie);
  display:grid;grid-template-columns:1fr auto 1fr;
  align-items:start;gap:var(--takt-zeile)}
.reihe-fuss>:first-child{justify-self:start}
.reihe-fuss>:last-child{justify-self:end}

/* Drei Teile, zwei Pfeile. Der Weg hinaus traegt keinen: er steht in
   Titelweiss zwischen zwei gedaempften Nachbarn, und die Betonung liegt damit
   auf dem Ausgang statt auf dem Weiterblaettern. Ein dritter Pfeil in der
   Mitte haette ausserdem keine Richtung - hinaus ist keine. */
.reihe-nachbar{display:flex;align-items:baseline;gap:.6rem;
  font-family:Delight;font-size:var(--text-s);line-height:1.5;
  text-transform:uppercase;color:var(--text-gedaempft);
  transition:color var(--takt-hover) var(--kurve-hover)}
.reihe-nachbar--vor{text-align:right}
/* Der Pfeil steht aussen: links vor dem Datum, rechts dahinter. Er zeigt aus
   der Seite heraus, nicht in sie hinein. */
.reihe-nachbar--vor .reihe-pfeil{order:1}
.reihe-nachbar .reihe-kat{color:var(--akzent, var(--farbe-default))}
.reihe-nachbar:hover,.reihe-nachbar:active{color:var(--titelfarbe)}

/* Der leere Platz am Anfang und am Ende der Reihe. Er haelt das Feld, damit
   der Weg hinaus in der Mitte stehen bleibt - er zeigt nichts an. Kein
   gedaempfter Pfeil, kein abgeschalteter Knopf: das System kennt keinen
   deaktivierten Zustand (vgl. `.nahsicht button[hidden]`). */
.reihe-nachbar--leer,.reihe-spur--leer{display:block}

/* ---------- Die Randspuren ----------
   **Nichts schwebt.** Die Spuren liegen nicht ueber der Seite, sondern an
   ihrem Rand: ab 1180px rueckt der Artikel um `--spur` von beiden Waenden ab
   und gibt ihnen den Platz. Das Plakat im Auftakt und die Haengung enden
   dadurch dort, wo die Spur beginnt - die Wand hat auf dieser einen Seite
   einen Rand bekommen, und an dem haengen die Nachbarn.

   Getragen werden sie von einer Lage, die genau so hoch ist wie der Artikel;
   darin haengt jede Spur mit `position:sticky` auf der Leselinie - derselben
   Hoehe, von der auch der Lichtabfall rechnet. Am Ende des
   Artikels loesen sie sich und laufen mit hinaus: die Reihe gehoert zur
   Veranstaltung, nicht zum Fenster.

   Keine senkrechte Trennlinie. Haarlinien trennen in diesem System Zeilen,
   waagerecht; eine Linie ueber die volle Hoehe waere ein Rahmen, und Rahmen
   gibt es nicht. Der Abstand trennt. */
.reihe-spuren{display:none}

@media (min-width:1180px){
  .event-seite{padding-inline:var(--spur)}

  /* `grid-column: 1 / -1` ist hier nicht Gestaltung, sondern Bedingung: eine
     absolut gestellte Lage in einem Raster bekommt ihren Bezugsrahmen aus der
     Spur, in der sie steht - und `.event-seite > *` stellt jedes Kind in die
     mittlere. `inset:0` haette sich dann auf die Textspalte bezogen, und die
     Spuren stuenden mitten im Text statt an der Wand. */
  /* Der Rand, in dem die Spuren haengen, ist der `padding-inline` des Artikels
     - und eine Rasterspur endet am Innenrand, nicht am Aussenrand. Die Lage
     greift darum um genau diesen Wert nach beiden Seiten hinaus. Ohne das
     stuende sie buendig mit dem Plakat im Auftakt, das die volle Wand nehmen
     darf: ein liegendes Plakat liefe unter die rechte Spur. */
  .reihe-spuren{position:absolute;inset:0 calc(-1 * var(--spur));
    grid-column:1 / -1;display:flex;
    justify-content:space-between;align-items:flex-start;
    pointer-events:none}

  .reihe-spur{position:sticky;top:33vh;pointer-events:auto;
    width:var(--spur);min-height:1px;
    /* Senkrecht wie die Jahresmarke an der Achse - dieselbe Setzung, dieselbe
       Laufweite. Es ist die eine Leserichtung, die dieses Haus quer kennt. */
    writing-mode:vertical-rl;
    display:flex;align-items:center;justify-content:flex-start;
    gap:var(--takt-zeile);
    font-family:Delight;font-size:var(--text-s);line-height:1;
    letter-spacing:.18em;text-transform:uppercase;
    color:var(--text-gedaempft);
    transition:color var(--takt-hover) var(--kurve-hover)}

  /* Der Pfeil bleibt waagerecht. In der senkrechten Schreibrichtung wuerde er
     mitgedreht, und ein »→«, das nach unten zeigt, verspricht etwas anderes,
     als hier passiert. */
  .reihe-spur .reihe-pfeil{writing-mode:horizontal-tb;font-weight:900;
    font-size:var(--text-l);letter-spacing:normal;line-height:1;
    transition:transform var(--takt-hover) var(--kurve-hover)}
  .reihe-spur .reihe-kat{color:var(--akzent, var(--farbe-default))}

  .reihe-spur:hover{color:var(--titelfarbe)}
  /* Der Pfeil tritt beim Ueberfahren einen Schritt nach aussen - in die
     Richtung, in die er zeigt. Dieselbe Rueckmeldung wie ueberall: 0.18s,
     ease-out-cubic, und ohne sie passiert gar nichts. */
  .reihe-spur--vor:hover .reihe-pfeil{transform:translateX(.4rem)}
  .reihe-spur--zurueck:hover .reihe-pfeil{transform:translateX(-.4rem)}
}

/* ---------- Lichtstatus ----------
   Kein gruener Punkt, kein OPEN-Schild: das Signal ist die Belichtung der Seite,
   der Satz ist die Auskunft. Er steht in derselben Grammatik wie jede andere
   Beschriftung des Systems - Delight 900, Versalien, Beschriftungsgroesse.

   Die Zeile ist so laut wie der Raum: Nur wenn das Licht an ist, traegt die
   Aussage Titelweiss. Im Dunkeln steht sie gedaempft, im unbekannten Fall gibt
   es sie gar nicht - dort bleiben allein die Oeffnungszeiten stehen. */
.lichtstatus{font-family:Delight;font-size:var(--text-s);line-height:1.7;
  letter-spacing:.08em;text-transform:uppercase;margin:0}
/* Nur der Satz zum geltenden Zustand steht da. Seit dem Ausbau der
   Entwurfsleiste liefert das Snippet ohnehin nur noch diesen einen aus - die
   Regel bleibt trotzdem stehen: sie ist es, die den Satz an `data-licht`
   bindet, und ohne sie stuende der Papiersatz am Bildschirm. */
.lichtstatus .fall{display:none}
/* Der Satz fuers Papier bleibt am Bildschirm weg - dort gibt es die genauere
   Auskunft. Er traegt kein data-fall und faellt schon unter die Regel darueber;
   die Zeile hier sagt, dass das Absicht ist und kein Versehen. */
.lichtstatus .fall--papier{display:none}
:root[data-licht=an] .lichtstatus .fall[data-fall=an],
:root[data-licht=aus] .lichtstatus .fall[data-fall=aus],
:root[data-licht=unbekannt] .lichtstatus .fall[data-fall=unbekannt]{display:inline}

.lichtstatus .aussage,.lichtstatus .dazu{white-space:nowrap}
.lichtstatus .aussage{font-weight:900;color:var(--text-gedaempft)}
:root[data-licht=an] .lichtstatus .aussage{color:var(--titelfarbe)}
.lichtstatus .dazu{color:var(--text-gedaempft)}
/* Derselbe Trennpunkt wie zwischen Uhrzeit, Ort und Kategorie in der Programmzeile. */
.lichtstatus .aussage+.dazu::before{content:"\00B7";color:var(--trennpunkt);
  margin:0 .8rem 0 .6rem}

.lichtstatus--kopf{text-align:center;margin-top:var(--takt-zeile)}
/* Im Fuss eine eigene Zeile ueber Symbolen und Menue - der Fuss ist eine
   umbrechende Reihe, die Auskunft ueber den Ort steht darin zuoberst. */
.lichtstatus--fuss{flex:0 0 100%;margin-bottom:-.8rem}

/* ---------- Baustellentor ----------
   Kein Kasten, keine Karte: das Feld ist eine Haarlinie, auf die geschrieben
   wird, der Knopf ist der Ticket-Knopf des Systems. Die Seite hinter dem
   Passwort scheint nicht durch - das Tor zeigt weder Menue noch Fuss. */
.tor{max-width:52ch;margin:var(--takt-block) auto 0}
.tor-satz{font-size:var(--text-m);line-height:1.7;color:var(--text-gedaempft);margin:0}

.tor-form{display:flex;flex-wrap:wrap;align-items:flex-end;gap:2rem;margin-top:var(--takt-block)}
.tor-feld{flex:1 1 24rem;display:block}
.tor-feld span{display:block;font-family:Delight;font-weight:900;font-size:var(--text-s);
  line-height:1.7;letter-spacing:.08em;text-transform:uppercase;color:var(--titelfarbe)}
.tor-feld input{width:100%;margin-top:.6rem;padding:.8rem 0;
  font-family:"IBM Plex",system-ui,sans-serif;font-size:var(--text-m);line-height:1.4;
  color:var(--titelfarbe);background:none;border:0;
  border-bottom:1px solid var(--linie);border-radius:0}
.tor-feld input:focus{outline:none;border-bottom-color:var(--titelfarbe)}
/* Der Ring liegt auf dem Feld, nicht auf der Linie - sonst waere er halb verdeckt. */
.tor-feld input:focus-visible{outline:2px solid var(--titelfarbe);outline-offset:2px}
.tor-feld input[aria-invalid=true]{border-bottom-color:var(--primary-hell)}

.tor-form button{padding:.72rem 1.8rem;border:0;border-radius:2px;cursor:pointer;
  font-family:Delight;font-weight:900;font-size:var(--text-s);line-height:1.7;
  text-transform:uppercase;background:var(--titelfarbe);color:var(--dunkel)}

/* Leer belegt die Zeile keinen Platz - sonst spraenge das Formular beim Fehler. */
.tor-fehler{font-family:Delight;font-weight:900;font-size:var(--text-s);line-height:1.7;
  letter-spacing:.08em;text-transform:uppercase;color:var(--primary-hell);margin:var(--takt-zeile) 0 0}
.tor-fehler:empty{display:none}

/* ---------- Entwurfsleiste: ausgebaut am 30.08.2026 ----------
   Hier standen rund dreissig Zeilen fuer eine feste Leiste am unteren Rand:
   die Marke »Entwurf«, drei Knoepfe fuer den Lichtzustand und drei Wege
   hinaus. Sie ist weg, weil die Seite fertig aussehen soll - eine Leiste, die
   »Entwurf« sagt, ist das Gegenteil davon.

   Die drei Lichtknoepfe sind nicht verschwunden, sondern umgezogen: sie stehen
   in der Konzeptuebersicht unter `/uebersicht`, im Abschnitt »Der
   Lichtschalter«, mit eigenem Stylesheet. Dort sind sie kein Geruest mehr,
   sondern der Gegenstand des Abschnitts.

   Mit der Leiste faellt auch `body:has(.lichtprobe) .fuss` weg - der Fuss
   braucht keinen Platz mehr unter sich freizuhalten. */

/* ---------- Fuss ---------- */
/* 60 px vor dem Fuss - einmal. Aussenabstand und Innenabstand trugen bis
   hierher beide 60 und ergaben zusammen 120. */
.fuss{display:flex;flex-wrap:wrap;align-items:center;gap:2rem;
  padding-block:0 max(3rem, env(safe-area-inset-bottom));margin-top:var(--takt-fuss)}
.fuss .sozial{display:flex;gap:1.2rem;margin-right:auto}
.fuss .sozial a{width:3.2rem;height:3.2rem;border-radius:50%;background:var(--titelfarbe);
  display:grid;place-items:center;color:var(--background);
  transition:background var(--takt-hover) var(--kurve-hover),
             color var(--takt-hover) var(--kurve-hover)}
.fuss .sozial svg{width:1.6rem;height:1.6rem;fill:currentColor;display:block}
.fuss nav{display:flex;flex-wrap:wrap;gap:clamp(2rem,4vw,6rem)}
.fuss nav a{font-family:Delight;font-size:var(--text-m);text-transform:uppercase}

/* ---------- Die Unterschrift ----------
   Der freigestellte Affe neben der Anschrift. Er steht auf jeder Seite genau
   einmal an dieser Stelle - das ist der Unterschied zwischen einer Marke und
   einer Unterschrift, und es ist die Regel, die DESIGN.md fuer die Design-App
   laengst aufschreibt (»Freigestellt ist der Affe ein Buchstabe«). Auf der
   Seite des Hauses fehlte sie: das Zeichen fuehrte hier jede Seite an und
   unterschrieb keine.

   **Eine eigene Zeile ueber die ganze Breite.** flex-basis:100% in einer
   umbrechenden Zeile heisst: sie steht auf jedem Schirm allein und draengt
   sich nie zwischen Kanaele und Menue.

   **Zweieinhalbmal so hoch wie die Schrift daneben** (DESIGN.md). Auf gleicher
   Hoehe waere er ein Aufzaehlungszeichen, darueber wuerde er die Zeile
   anfuehren. Die Zahl steht als `2.5em` an genau einer Stelle und waechst mit
   der Schrift mit, statt zweimal gepflegt zu werden.

   **Als Maske, nicht als Bild** - nur so folgt seine Farbe der Tinte, und nur
   so kehrt er sich auf dem Papier mit um. Das Seitenverhaeltnis 442 / 361 ist
   die gemessene Huelle der Figur; es steht hier und nicht in der Datei. */
.fuss .unterschrift{flex-basis:100%;margin:0;
  display:flex;align-items:center;gap:1.2rem;
  font-family:Delight;font-size:var(--text-s);line-height:1.5;
  letter-spacing:.02em;color:var(--text-still)}
/* Die drei Teile der Anschrift halten je zusammen; umbrechen darf die Zeile
   nur an den beiden Trennpunkten. Warum, steht am Markup in fuss.php. */
.fuss .unterschrift .anschrift>span{white-space:nowrap}
.unterschrift-zeichen{flex:0 0 auto;height:2.5em;width:auto;aspect-ratio:442 / 361;
  background:url("../img/affe.svg") center/contain no-repeat}
@supports (mask-image:url("")) or (-webkit-mask-image:url("")){
  .unterschrift-zeichen{background:currentColor;
    -webkit-mask:url("../img/affe.svg") center/contain no-repeat;
            mask:url("../img/affe.svg") center/contain no-repeat}
}

/* ---------- Der Dank an Kirby ----------
   Steht am Fuss des Impressums und nirgends sonst; das Markup dazu in
   site/snippets/dank-kirby.php, das Zeichen in assets/img/kirby-logo.svg.

   **Kleingedrucktes, und es sieht auch so aus.** Der Dank ist eine Zusage und
   keine Werbeflaeche: --text-still, die duennste Schrift, die dieses Haus
   erlaubt, und dieselbe, in der die Unterschrift im Fuss steht. Sie ist gegen
   den hellsten Grund gerechnet, den es gibt - siehe die Rechnung am Schleier.

   **Das Zeichen als Maske**, genau wie der Affe der Unterschrift: die Pfade im
   Presskit tragen keine Farbe und stuenden sonst schwarz auf der dunklen Wand.
   So nimmt der Schriftzug die Tinte der Zeile an, wandert mit dem Licht und
   kehrt sich auf dem Papier mit um. Das Seitenverhaeltnis 121 / 42 ist die
   Leinwand der Datei; die Hoehe von 2.5em ist die der Unterschrift, damit die
   beiden fremden Zeichen im Haus gleich gross auftreten.

   **Ueber dem Satz und nicht daneben.** Neben dem Satz waere der Schriftzug
   ein Wort in ihm - und »kirby« steht im Satz schon als Wort, dort wo der
   Verweis haengt. Uebereinander sagen sie zweierlei: das Zeichen, womit
   gebaut ist, der Satz, warum das hier steht. */
.dank{margin-top:var(--takt-fuss);max-width:62ch;
  display:flex;flex-direction:column;align-items:flex-start;gap:var(--takt-eng);
  font-size:var(--text-s);line-height:1.6;color:var(--text-still)}
.dank p{margin:0}
.dank a{color:inherit;text-decoration:underline;text-underline-offset:.2em}
.dank-zeichen{flex:0 0 auto;height:2.5em;width:auto;aspect-ratio:121 / 42;
  background:url("../img/kirby-logo.svg") center/contain no-repeat}
@supports (mask-image:url("")) or (-webkit-mask-image:url("")){
  .dank-zeichen{background:currentColor;
    -webkit-mask:url("../img/kirby-logo.svg") left center/contain no-repeat;
            mask:url("../img/kirby-logo.svg") left center/contain no-repeat}
}

/* ---------- Und wer es gebaut hat ----------
   Die Unterschrift des Machers am Fuss des Impressums, unter dem Dank an
   Kirby - dieselbe Zeile wie am Ende der Konzeptuebersicht. Das Markup in
   site/snippets/gebaut.php. Die Klassen heissen `gebaut` und nicht
   `signatur`, weil uebersicht.css seine eigene Signatur hat und beide
   Stylesheets auf derselben Seite liegen koennen.

   Eine Zeile und kein Kasten: kein Rahmen, keine Flaeche, keine zweite Wand.
   Sie steht in der stillsten Tinte des Hauses - laut wird sie erst unter dem
   Zeiger. */
.gebaut{margin-top:var(--takt-zeile)}
.gebaut-marke{display:inline-flex;align-items:center;gap:1.6rem;
  text-decoration:none;color:var(--text-still)}
/* **Das einzige fremde Zeichen im Haus, das keine Maske ist.** Es traegt zwei
   Farben, die keine Hausfarben sind, und soll sie behalten. Der Graufilter in
   Ruhe ist die Regel der Konzeptuebersicht, Wort fuer Wort: genau eine rote
   Flaeche ist erlaubt, und das ist der Klebepunkt. */
.gebaut-zeichen{flex:0 0 auto;width:auto;height:4.4rem;display:block;
  filter:grayscale(1) brightness(1.9) opacity(.55);
  transition:filter var(--takt-hover) var(--kurve-hover),
             transform var(--takt-hover) var(--kurve-hover)}
.gebaut-wort{display:flex;flex-direction:column;gap:.3rem;min-width:0}
.gebaut-wort b{font-family:Delight;font-weight:900;font-size:1.4rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--text-gedaempft);
  transition:color var(--takt-hover) var(--kurve-hover)}
.gebaut-wort>span{font-size:1.4rem;line-height:1.45;color:var(--text-still)}

/* **Das Herz schlaegt - die eine Schleife, die dieses Haus zulaesst.**
   Bewegung ist hier sonst immer eine Antwort auf eine Handlung; ein Herz, das
   nicht schlaegt, ist aber ein Symbol und kein Herz.

   Damit es die Ausnahme bleibt, ist es dreifach klein gehalten: der Ausschlag
   sind 16 Prozent (an 1.4rem gut zwei Pixel - man sieht es aus Lesenaehe und
   nie aus dem Augenwinkel), es schlaegt in der Tinte der Zeile und nicht in
   Rot, und der Takt ist ein Herzschlag und kein Blinken: zwei Schlaege dicht
   hintereinander, dann eine lange Pause. `currentColor` heisst ausserdem, dass
   es unter dem Zeiger mitgeht, wenn die Zeile ihre Farbe wechselt. */
.gebaut-herz{width:1em;height:1em;vertical-align:-.12em;fill:currentColor;
  transform-origin:center;animation:gebaut-puls 1.7s ease-in-out infinite}
@keyframes gebaut-puls{
  0%,26%,100%{transform:scale(1)}
  8%{transform:scale(1.16)}
  17%{transform:scale(1.07)}
}

@media (hover:hover){
  .gebaut-marke:hover .gebaut-zeichen,
  .gebaut-marke:focus-visible .gebaut-zeichen{filter:none;transform:rotate(-90deg)}
  .gebaut-marke:hover .gebaut-wort b,
  .gebaut-marke:focus-visible .gebaut-wort b{color:var(--primary-hell)}
}
/* Ohne Zeiger bleibt die Antwort auf den Druck - dieselbe Regel wie ueberall
   im Haus: ein Daumen bekommt eine Rueckmeldung, kein Hover. */
.gebaut-marke:active .gebaut-zeichen{filter:none;transform:rotate(-90deg)}
.gebaut-marke:active .gebaut-wort b{color:var(--primary-hell)}
.gebaut-marke:focus-visible{outline:2px solid var(--primary-hell);
  outline-offset:.6rem}

/* Wer weniger Bewegung verlangt hat, bekommt ein stehendes Herz - es sagt
   dasselbe, nur leiser. Die Drehung faellt aus demselben Grund weg; der
   Farbwechsel bleibt, denn er ist die Auskunft. */
@media (prefers-reduced-motion:reduce){
  .gebaut-herz{animation:none}
  .gebaut-zeichen{transition:filter var(--takt-hover) linear}
  .gebaut-marke:hover .gebaut-zeichen,
  .gebaut-marke:focus-visible .gebaut-zeichen,
  .gebaut-marke:active .gebaut-zeichen{transform:none}
}

/* ---------- Zeigergeraete: Hover nur, wo er auch wieder weggeht ----------
   Auf Touch bleibt :hover nach dem Antippen haengen. Eine gedimmte Zeile oder
   ein rot gefaerbter Filter liest sich dann wie ein Zustand, der er nicht ist. */
@media (hover:hover){
  /* Das Zeichen kommt unter dem Zeiger ein Stueck herunter. Es ist der Weg
     nach Hause und auf jeder Seite dasselbe Ziel - eine Farbe braucht es dafuer
     nicht, die sagt hier schon, ob das Licht brennt. Vier Prozent: an einem
     Kopf in voller Groesse gut acht Pixel, am schlanken drei. Genug, dass die
     Hand es merkt, zu wenig, um mit dem Stoss der Lampe zu streiten - die
     bleibt die einzige grosse Bewegung des Hauses.

     Der Lichtkegel zieht nicht mit: seine Ruhelage haengt an der gemessenen
     Lage der Spirale, und eine Transformation misst niemand neu. Bei vier
     Prozent wandert die Spirale gut einen Pixel - die Quelle bleibt, wo sie
     ist, und das ist richtiger, als eine Wand auf einen Hover neu zu
     belichten. */
  .kopf a:hover .logo{transform:scale(1.04)}

  /* Der Klebepunkt gibt unter dem Zeiger genauso nach - dieselben vier
     Prozent, dieselbe Kurve. Er ist ein Ding an der Wand, das jemand
     anfasst, und keine Flaeche, die ihre Farbe wechselt: rot war er schon.
     Nur der mit einem Ziel bewegt sich; ein Aushang ohne Verweis reagiert
     nicht darauf, dass jemand hinsieht.

     **Und die Zeile richtet sich auf.** Der Punkt ist schief geklebt; unter
     einer Hand geht die Neigung gegen null, als drueckte jemand ihn fest.
     Das ist die Rueckmeldung, die ein Kreis sonst nicht geben kann - an einer
     runden Flaeche sieht man weder Drehung noch Kante, nur die Schrift. */
  a.klebepunkt:hover .scheibe{scale:1.04}
  a.klebepunkt:hover .schlag{rotate:0deg}

  .zeile:hover{opacity:.62}
  .filter a:hover:not([aria-current]),
  .filter button:hover:not([aria-pressed=true]){color:var(--primary-hell)}
  .kalender-abo a:hover,.blaettern a:hover{color:var(--primary-hell)}
  .tor-form button:hover{background:var(--primary);color:var(--titelfarbe)}
  .dichte svg a:hover rect{fill:var(--titelfarbe)}
  .filter-leise a:hover:not([aria-current]){background:none;color:var(--titelfarbe)}

  /* Dieselbe Regel gilt fuer jeden uebrigen Weg des Systems. Sie stand bis
     hierher an sieben Stellen ausserhalb dieser Abfrage - und genau die sieben
     blieben auf dem Telefon nach dem Antippen rot bzw. rot unterlegt stehen,
     als waeren sie ein gewaehlter Zustand. Ein Hover, der nicht wieder weggeht,
     ist kein Hover, sondern eine falsche Auskunft. */
  .hauptmenue a:hover,
  .leer a:hover,
  .body a:hover,
  .zurueck:hover,
  .haengung-mehr:hover,
  .fuss nav a:hover{color:var(--primary-hell)}
  /* **Ein Bild an der Wand reagiert nicht darauf, dass jemand hinsieht.**
     Hier stand bis zum 30.08.2026 dieselbe Rueckmeldung wie auf einer
     Programmzeile - Deckkraft auf 62% - mit der Begruendung, ein Bild, das
     man anklicken kann, muesse das sagen. Der Preis dafuer war zu hoch: eine
     Haengung ist kein Menue, und wer an ihr entlangfaehrt, dimmt sich durch
     die eigenen Fotos. Ein Plakat haengt und haelt still.

     Was die Anklickbarkeit sagt, ist damit der Zusammenhang und nicht die
     Flaeche - der Systemzeiger kann es nicht sagen, weil ihn `zeiger-an`
     ohnehin abschaltet. Der Druck sagt es weiterhin: die `:active`-Regel
     unten bleibt, sie ist die Rueckmeldung auf einen Daumen und kein Zustand,
     den man beim Vorbeifahren ausloest. Wer hier wieder etwas einsetzt, setzt
     eine Haarlinie und keine Deckkraft. */
  .event-daten .ticket:hover,
  .event-daten .kalender:hover,
  .fuss .sozial a:hover{background:var(--primary);color:var(--titelfarbe)}
}

/* ---------- Der Finger: dieselbe Auskunft, ausgeloest vom Druck ----------
   Der Block darueber ist richtig eingezaeunt - ein Hover, der nach dem
   Antippen stehenbleibt, behauptet einen Zustand, den es nicht gibt. Nur war
   damit die Diagnose behandelt und nicht das Symptom: auf dem Telefon fiel die
   gesamte Rueckmeldung der Seite weg, und nichts trat an ihre Stelle. Wer
   einen Filter antippt, sah bis zum Neuaufbau der Liste nicht, dass er
   getroffen hat - und die Filterleiste ist die Kernbedienung dieser Seite.

   :active kann nicht haengenbleiben, er endet mit dem Finger. Deshalb steht er
   hier draussen und gilt fuer beide Haende: am Zeiger ist er der Druckpunkt vor
   dem Klick, am Telefon die einzige Rueckmeldung ueberhaupt.

   Es ist kein zweites Vokabular. Jede Zeile hier ist die Schwester einer Zeile
   von oben, mit demselben Wert und demselben Takt - dieselbe Umkehrung, die der
   Zeiger sieht. Die Bar-App macht es seit jeher so (bar.css, ».knopf-name:active«);
   die Seite zieht damit nach, und beide Flaechen antworten wieder gleich.

   Alle Ziele sind <a> oder <button>. Das ist keine Zufaelligkeit, sondern die
   Bedingung: iOS Safari gibt :active nur Verweisen und Knoepfen, nicht
   beliebigen Kaesten. Die Programmzeile ist ein <a> - deshalb geht sie mit. */
.zeile:active{opacity:.62}
.filter a:active:not([aria-current]),
.filter button:active:not([aria-pressed=true]){color:var(--primary-hell)}
.kalender-abo a:active,.blaettern a:active{color:var(--primary-hell)}
.tor-form button:active{background:var(--primary);color:var(--titelfarbe)}
a.klebepunkt:active .scheibe{scale:1.04}
a.klebepunkt:active .schlag{rotate:0deg}
.dichte svg a:active rect{fill:var(--titelfarbe)}
.filter-leise a:active:not([aria-current]){background:none;color:var(--titelfarbe)}
.hauptmenue a:active,
.leer a:active,
.body a:active,
.zurueck:active,
.haengung-mehr:active,
.fuss nav a:active{color:var(--primary-hell)}
/* Diese beiden bleiben, obwohl ihre Hover-Schwestern weg sind, und das ist
   kein Versehen: ein Druck ist eine Handlung, ein Hover ist ein Vorbeifahren.
   Auf dem Telefon ist das hier die einzige Rueckmeldung darauf, dass der
   Daumen das Bild getroffen hat - sie faellt weg, sobald er loslaesst. */
.event-bilder a:active img,
.haengung a:active img,
.event-daten .ticket:active,
.event-daten .kalender:active,
.fuss .sozial a:active{background:var(--primary);color:var(--titelfarbe)}
/* Das Zeichen kommt auch unter dem Finger herunter - derselbe Weg wie unter dem
   Zeiger, und bei abgeschalteter Bewegung faellt er genauso weg (siehe unten). */
.kopf a:active .logo{transform:scale(1.04)}

/* Erst jetzt darf die Antwort des Systems weg. iOS legt sonst sein graues
   Rechteck ueber jeden Treffer - die einzige Flaeche dieser Seite, deren
   Aussehen nicht hier entschieden wird, und sie hat weder den Takt noch die
   Farbe des Hauses. Vor den Regeln daruber waere diese Zeile ein Verlust
   gewesen: dann bliebe auf dem Telefon gar nichts. Die Reihenfolge im
   Stylesheet ist also auch die Reihenfolge der Begruendung. */
a,button,summary,[role=button]{-webkit-tap-highlight-color:transparent}

/* Der Systemzeiger weicht dem roten Punkt - aber nur, wenn zeiger.js ihn
   tatsaechlich gesetzt hat, und nur auf feinen Zeigern. Die Regel steht so
   spaet, weil sie sich gegen jedes cursor:pointer weiter oben durchsetzen muss.
   In Schreibfeldern bleibt die Schreibmarke: dort ist sie die genauere Auskunft. */
@media (hover:hover) and (pointer:fine){
  :root.zeiger-an,:root.zeiger-an *{cursor:none}
  :root.zeiger-an input,:root.zeiger-an textarea,:root.zeiger-an select,
  :root.zeiger-an [contenteditable],:root.zeiger-an iframe{cursor:auto}
}

/* ---------- Tablet: zwei Spalten statt Stapel ----------
   Unter 1000px bleiben von der Preisspalte 135px, in denen meist nichts steht.
   Der Preis rutscht unter den Titel, Termin und Titel behalten ihr Verhaeltnis. */
@media (max-width:1000px){
  .zeile{grid-template-columns:34fr 66fr}
  .zeile>div:nth-child(3){grid-column:2}
  /* Zwei Spalten statt drei: die Kante der Datumsspalte wandert von 24 % auf 34 %,
     und die Achse mit ihr. Sonst laege sie im Titel. */
  .achse{--achse-x:calc(34% - .34 * var(--grid-gap))}
  .zeile .preis{text-align:left}

  /* Das Logo bindet sich unterhalb des Desktops an die Fensterhoehe statt an eine
     feste Groesse: es soll das erste Bild anfuehren, nicht fuellen. 13vh sind auf
     einem 812er-Telefon 106px, auf einem 700er 91px, auf dem Tablet 133px. */
  :root{--logo-hoehe:clamp(6rem, 13vh, 13rem)}
}

/* ---------- Telefon ---------- */
@media (max-width:640px){
  /* --title hat eine Untergrenze von 5.88rem (58.8px) und laeuft auf schmalen
     Viewports aus dem Bild. Dort deshalb eine eigene, viewport-gebundene Kurve. */
  :root{--title:clamp(3.2rem, 11vw, 5.6rem)}

  /* Ein Bild je Reihe. Eine Schiene mit zwei Fotos nebeneinander ergibt auf
     375px zwei Briefmarken - und ein Foto, das man nicht erkennt, ist kein
     Foto, sondern eine Ankuendigung davon. */
  .haengung a{flex-basis:100%}

  /* Der Kopf ist schmaler und niedriger, die Lampe haengt entsprechend tiefer
     im Bild und leuchtet kuerzer weit. */
  :root{--lampe-weite:58rem;--lampe-hoehe:52rem;
    --lichtfeld:radial-gradient(var(--lampe-weite) var(--lampe-hoehe) at 50% 50%,
      var(--wand-hell) 0%,
      color-mix(in oklab, var(--wand-hell) 70%, transparent) 24%,
      color-mix(in oklab, var(--wand-hell) 36%, transparent) 50%,
      color-mix(in oklab, var(--wand-hell) 14%, transparent) 72%,
      color-mix(in oklab, var(--wand-hell) 0%, transparent) 100%)}
  .huelle::after{height:22rem}

  .zeile{grid-template-columns:1fr;gap:.8rem;padding-block:2rem}
  .zeile>div:nth-child(3){grid-column:auto}
  /* Uhrzeit, Ort und Kategorie teilen sich eine Zeile statt drei */
  .zeile>div:first-child{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:.8rem}
  .zeile>div:first-child .wann{flex:0 0 100%}
  /* Die Laufzeit einer Ausstellung bekommt eine eigene Zeile - sonst kippt die
     Metazeile um und der Trennpunkt beginnt den Umbruch. */
  .zeile .laufzeit{flex:0 0 100%}
  .zeile .laufzeit::before,.zeile .laufzeit+.meta::before{content:none !important}
  .zeile .meta+.meta::before,.zeile .meta+.kat::before{
    content:"\00B7";color:var(--trennpunkt);margin-right:.8rem}

  /* Der Blockabstand faellt vom Desktop-Schritt (5rem) auf den naechstkleineren:
     ueber der ersten Trennlinie sind 5rem auf einem Telefon eine Luecke, kein
     Absatz. Ein Wert, nicht neun - alles, was am Takt haengt, faellt mit. */
  :root{--takt-block:3rem}

  /* Der obere Rand ist hier die Gehaeusekante, nicht der Seitenrand einer
     Flaeche - ueber dem Logo reicht der enge Schritt. */
  :root{--kopf-oben:var(--takt-eng)}

  /* Die Bildlaufleiste der Monatszeile traegt auf dem Telefon schon, was auf
     dem Schirm der Zeilenschritt tragen muss: die Trennung der Zeitfrage von
     der Kategoriefrage. Beides zusammen waere eine Luecke, kein Absatz. */
  .filter+.filter-kategorie{margin-top:var(--takt-eng)}

  /* Zwoelf Jahreszahlen nebeneinander laufen auf 390px ineinander. Jede zweite
     reicht als Orientierung und bleibt an ihrer richtigen Stelle - eine an den
     Rand geschobene Zahl waere lesbar, aber falsch. */
  .dichte figcaption .jahr:nth-child(even){display:none}
  /* Auf einer Spalte gibt es keine Datumsspalte mehr, an deren Kante die Achse
     sitzen koennte. Sie rueckt an den Zeilenanfang und nimmt die Jahreszahl vor
     sich: aussen die Zahl, dann die Achse mit ihren Punkten, dann die Zeile. */
  .achse{--achse-x:2.2rem}
  .achsenzeile{padding-left:3.8rem}
  .achsenzeile::after{top:calc(2rem + .625em)}
  .jahrmarke{margin-left:0;letter-spacing:.12em}

  /* Auf dem Telefon fuehrt die Breite, nicht die Hoehe. Auf der Wand bekommt
     das Plakat den Rest des Bildschirms als Hoehe und richtet sich darin unten
     aus - was schmaler ausfaellt, laesst Luft unter dem Zeichen. Auf 375px ist
     diese Luft keine Luft mehr: ein quadratisches Plakat stand in einem Kasten
     von 420px Hoehe und war selbst nur 341 hoch, und die 79px dazwischen lasen
     sich als Riss zwischen Zeichen und Bild. Sichtbar wurden sie beim Antippen
     - die Rueckmeldung faerbt die Bildflaeche, und gefaerbt wurde der leere
     Teil des Kastens gleich mit.

     Das Bild bekommt darum keine Hoehe mehr zugeteilt, sondern zwei Grenzen:
     die Spaltenbreite und ein Deckel von 60svh. Ein ersetztes Element mit
     `auto` in beiden Achsen schrumpft dann proportional bis zur ersten Grenze,
     die haelt - der Kasten ist wieder das Bild, und der Titel folgt ihm dicht.
     Der Deckel haelt, was der Auftakt auf der Wand haelt: ein hohes Plakat
     schiebt die Antwort auf »wann muss ich wo sein« nicht unter die Falz. */
  .event-auftakt--bild{height:auto}
  .event-bilder{flex:0 0 auto}
  .event-bilder a{height:auto}
  .event-bilder img{width:auto;height:auto;max-width:100%;max-height:60svh}
  /* Drei Teile passen auf 375px nicht in eine Zeile. Die beiden Nachbarn
     stehen darum nebeneinander, der Weg hinaus darunter und linksbuendig - er
     ist das Ziel, nicht die Mitte, sobald es keine Mitte mehr gibt. Und die
     Kategorie faellt weg: die Antwort ist das Datum, das Wort war die Zugabe. */
  .reihe-fuss{grid-template-columns:1fr 1fr;row-gap:var(--takt-zeile)}
  .reihe-fuss>.zurueck{grid-column:1 / -1;grid-row:2;justify-self:start}
  .reihe-fuss>[data-reihe=zurueck]{grid-column:1;grid-row:1}
  .reihe-fuss>[data-reihe=vor]{grid-column:2;grid-row:1}
  .reihe-nachbar .reihe-kat{display:none}

  .fuss{flex-direction:column;align-items:flex-start}
  .fuss .sozial{margin-right:0}

  /* ---------- Vier Verweise, zwei Spalten ----------
     Die vier zusammen sind 344px breit und haben auf keinem Telefon eine
     Zeile: bei 375px stehen 341px zur Verfuegung, und zwar bei einem
     Spaltenabstand von null. Sie brechen also immer - bisher als 3 + 1, und
     »Datenschutz« stand danach allein unter den anderen dreien, mit demselben
     Abstand darueber, den der Fuss zwischen seinen Bloecken haelt. Das las
     sich nicht als vierter Verweis, sondern als eigene Angabe.

     Zwei Spalten sind die Antwort, weil sie den Umbruch setzen, statt ihn
     hinzunehmen: 2 + 2 ist eine Anordnung, 3 + 1 ist ein Rest. Die Spalten
     stehen auf max-content, damit die zweite an der Kante der breitesten
     Beschriftung haengt und nicht in der Fenstermitte - der Fuss haelt eine
     Gruppe zusammen und fuellt keine Wand.

     Beide Abstaende kommen aus dem Takt und sind keine neuen Zahlen: quer der
     Zeilenschritt, laengs der enge - genau das, was sie sind, naemlich zwei
     Zeilen derselben Leiste. */
  .fuss nav{display:grid;grid-template-columns:repeat(2,max-content);
    justify-content:start;
    column-gap:var(--takt-zeile);row-gap:var(--takt-eng)}

  /* Aussage und Zeitangabe stehen auf 375px nicht mehr nebeneinander. Sie
     brechen darum als zwei Zeilen um, ohne den Trennpunkt vor sich her zu
     schieben - ein fuehrender Punkt am Zeilenanfang ist kein Trenner mehr. */
  .lichtstatus .dazu{display:block}
  .lichtstatus .aussage+.dazu::before{content:none}

  /* Die Filter duerfen nicht mehr Platz beanspruchen als das, was sie filtern.
     Monate und Kategorien laufen darum als je eine Zeile seitlich weiter; der
     angeschnittene letzte Chip ist der Hinweis, dass es weitergeht. */
  /* Die Bildlaufleiste sass direkt unter den Woertern und las sich als
     Unterstreichung der ersten beiden. Sie bekommt darum Abstand. */
  .filter-leise{
    display:flex;flex-wrap:nowrap;justify-content:flex-start;
    overflow-x:auto;overscroll-behavior-x:contain;
    scroll-snap-type:x proximity;scrollbar-width:thin;
    scrollbar-color:var(--linie) transparent;padding-bottom:1.6rem}
  .filter-leise>a{flex:0 0 auto;scroll-snap-align:start}
  /* Die Leiste bekam ihre Haarlinie frueher zweimal: einmal ueber
     scrollbar-width/-color und einmal ueber ::-webkit-scrollbar. Sobald das
     erste Paar gesetzt ist, sieht Chrome das zweite nicht mehr an - die drei
     Regeln haben nie etwas getan und sind hier weg. Die Leiste bleibt, was sie
     war: duenn und in der Farbe der Trennlinien. */
}

/* ---------- Telefon quer: der Kopf frisst sonst zwei Drittel des Bildes ---------- */
@media (max-height:520px) and (orientation:landscape){
  :root{--kopf-oben:1.2rem}
  :root{--logo-hoehe:7rem}
  .seitentitel{font-size:clamp(2.8rem, 7vh, 4.4rem);margin-top:.8rem}
  .filter{margin-top:1.6rem}
  .hauptmenue{padding-block:1.6rem 1rem}
}

/* ---------- Grobe Zeiger: 44px Mindestflaeche, ohne sichtbare Aenderung ----------
   Die Flaeche waechst, das Aussehen nicht: die Kategoriefilter bleiben Text. */
@media (pointer:coarse){
  .filter a,.fuss nav a{min-height:44px;display:inline-flex;align-items:center}
  .filter-leise a{min-width:44px;min-height:44px;padding-block:0;
    display:inline-flex;align-items:center;justify-content:center}
  .zurueck,.event-daten .ticket,.event-daten .kalender,
  .haengung-mehr,
  .kalender-abo a,.blaettern a{min-height:44px;display:inline-flex;align-items:center}
  /* Die Nachbarn am Fuss sind auf dem Telefon die einzige sichtbare Bedienung
     der Reihe - den Wisch sieht man nicht. Sie bekommen darum dieselbe
     Trefferhoehe wie jeder andere Verweis hier. */
  .reihe-nachbar{min-height:44px;align-items:center}
  .tor-form button,.tor-feld input{min-height:44px}
  /* Die Kreise im Fuss bleiben 32px gross; die Trefferflaeche waechst unsichtbar darum herum. */
  .fuss .sozial a{position:relative}
  .fuss .sozial a::after{content:"";position:absolute;inset:-6px;border-radius:50%}
}

/* ---------- Der Weg: Liste -> Termin ----------
   Die einzige gestaltete Bewegung des Systems, und sie hat genau eine Aufgabe:
   den Weg zu erklaeren, den fast jeder Besuch nimmt. Wer in der Liste auf einen
   Titel tippt, sieht denselben Titel als Ueberschrift der Detailseite - er
   wandert dorthin, statt zu verschwinden und woanders neu zu erscheinen. Ein
   Plakat wird von der Wand genommen, nicht ausgetauscht.

   Dieselbe Zuordnung traegt den Filterwechsel: bleibt eine Veranstaltung in der
   gefilterten Liste, ruecken Titel an ihre neue Stelle, statt dass die ganze
   Seite blinkt. Was hinzukommt und was wegfaellt, ist damit sichtbar.

   Die Wand bewegt sich nicht: der Grundwechsel laeuft in 0.16s ab und ist nur
   da, damit der Text nicht hart umspringt. Bewegt wird der Titel, 0.42s, mit
   einer Verzoegerungskurve statt einer Feder - ein Plakat federt nicht.

   Der Name kommt aus dem Markup (--vt, aus dem Slug der Veranstaltung), weil er
   auf beiden Seiten derselbe sein muss. Ohne Unterstuetzung - heute Firefox -
   wechselt die Seite hart, so wie bisher. */
@view-transition{navigation:auto}

::view-transition-old(root),
::view-transition-new(root){animation-duration:.16s}

@media (prefers-reduced-motion:no-preference){
  .zeile .titel,
  .event-titel{view-transition-name:var(--vt,none);view-transition-class:termin}

  ::view-transition-group(.termin){animation-duration:var(--takt-weg,.42s);
    animation-timing-function:var(--kurve-weg,cubic-bezier(.16,1,.3,1))}

  /* Dieselbe Bewegung bedient zwei sehr verschiedene Haeufigkeiten. Der Sprung
     auf eine Detailseite passiert einmal; das Filtern ist die Kernbedienung der
     Programmliste und passiert im Dutzend. Eine halbe Sekunde, die beim ersten
     Mal traegt, steht beim zwoelften Mal im Weg.

     Das Attribut kommt denselben Weg wie data-sprung: im alten Dokument in den
     Zwischenspeicher gelegt, im neuen im Kopf ausgelesen, bevor gezeichnet wird
     (siehe weg.js und kopf.php). Gleiche Kurve, gleiche Bewegung, halbe Zeit -
     der Titel rueckt an seine neue Stelle, statt dorthin zu reisen. */
  html[data-filterwechsel] ::view-transition-group(.termin){animation-duration:.2s}

  /* **Der Weg zurueck ist der kurze Weg.** Derselbe Titel wandert, dieselbe
     Kurve - aber nicht dieselbe Dauer. `--takt-weg` ist die Dauer einer
     Ankunft: man kommt an einer Stelle an, die man noch nicht kennt. Zurueck
     kommt niemand an, er kehrt um. Eine halbe Sekunde, die den Hinweg traegt,
     ist auf dem Rueckweg das Warten darauf, wieder dort zu sein, wo man schon
     war - dieselbe Rechnung wie beim Filterwechsel und beim Blaetterschritt,
     nur an dem Weg, nach dem der Takt benannt ist.

     Bis hierher stand das nur auf dem Papier: `--takt-rueckweg` trug den
     Schritt zur Seite und den Weg aus der Nahsicht, aber nicht den Rueckweg.
     Der lief in `--takt-weg`. Es ist derselbe Ausfall wie zuvor an der
     Nahsicht, nur andersherum - dort fehlte die Regel, hier die Unterscheidung.

     Das Attribut setzt der Kopf, bevor gezeichnet wird (kopf.php): einmal aus
     dem Verlauf selbst - `navigation.activation` nennt eine Rueckkehr beim
     Namen -, einmal aus dem Zwischenspeicher, wenn der sichtbare Rueckweg am
     Fuss eine gewoehnliche Navigation ausloest (reihe.js). Beide Wege enden an
     derselben Stelle; sie sollen auch gleich lang dauern.

     Die Wand darunter bleibt bei ihren 0.16s. Sie ist schon der kuerzeste
     Wert des Hauses, und eine Ueberblendung, die noch kuerzer waere, ist
     keine mehr, sondern ein Sprung. */
  html[data-rueckweg] ::view-transition-group(.termin){
    animation-duration:var(--takt-rueckweg,.28s)}

  /* Der Jahressprung ist kein Seitenwechsel, sondern eine Bewegung auf derselben
     Achse: die Liste laeuft in die Richtung des Pfeils durch. "Frueher" heisst
     tiefer in der Zeit, also von unten herein; "neuer" umgekehrt. Dieselbe
     Verzoegerungskurve und dieselbe Dauer wie der wandernde Titel - es ist
     dieselbe Bewegung, nur eine Gruppe groesser.

     Ohne Unterstuetzung - heute Firefox - wechselt die Seite hart, so wie bisher;
     ohne Skript steht kein data-sprung und es bleibt bei der Ueberblendung. */
  /* Der Name steht nur waehrend des Sprungs da, und das ist keine Sparsamkeit,
     sondern Notwendigkeit: view-transition-name macht aus dem Element einen
     Stapelkontext. Eine benannte Achse schliesst damit alles, was in ihr liegt,
     in eine eigene Lage ein - und das Vorschaubild, das als festes Canvas ueber
     der Seite liegt, kann nicht mehr zwischen die Linien und die Schrift
     geraten. Es lag dann ueber beidem und verdeckte im Rueckblick genau die
     Titel, neben denen es erklaeren sollte. Auf der Programmliste fiel das nie
     auf: die traegt keinen Namen.

     Gesetzt wird das Attribut in beiden Dokumenten - im alten beim Klick
     (rueckblick.js), im neuen im Kopf vor dem ersten Bild (kopf.php). Beide
     Aufnahmen brauchen den Namen, sonst gibt es keine Gruppe, die wandern
     koennte. Wenn der Uebergang durch ist, faellt es weg und die drei Lagen
     stimmen wieder. */
  html[data-sprung] .achse{view-transition-name:achse}

  /* **Waehrend die Achse wandert, wandert kein Titel.** Seit der Rueckblick
     seine Zeilen benennt, liegen benannte Titel *in* der benannten Achse - und
     ein benanntes Element wird aus der Aufnahme seines Vorfahren
     herausgenommen. Die Achse liefe dann mit Loechern dort, wo die Titel
     stehen, und jeder von ihnen bekaeme seine eigene Gruppe: zwischen zwei
     Jahrgaengen haben die wenigsten einen Gegenpart, es waeren also achtzig
     einzelne Ueberblendungen ueber einer durchlaufenden Liste. Genau der
     Schwarm, den weg.js auf dem Hinweg verhindert.

     Der Jahressprung ist wie der Blaetterschritt: es traegt genau ein Name die
     Bewegung, und der liegt an der Achse als Ganzes. Es ist derselbe Satz und
     dieselbe Regel wie html[data-blaettern] .event-titel weiter unten.
     *Nicht benannt heisst nicht bewegt.*

     Der Filterwechsel bleibt ausdruecklich ausgenommen: dort verdienen die
     Namen ihr Dasein, weil bleibende Titel an ihre neue Stelle ruecken. */
  html[data-sprung] .achse .titel{view-transition-name:none}

  html[data-sprung]::view-transition-old(achse),
  html[data-sprung]::view-transition-new(achse){animation-duration:var(--takt-weg,.42s);
    animation-timing-function:var(--kurve-weg,cubic-bezier(.16,1,.3,1))}
  html[data-sprung=frueher]::view-transition-old(achse){animation-name:achse-hoch-raus}
  html[data-sprung=frueher]::view-transition-new(achse){animation-name:achse-hoch-rein}
  html[data-sprung=neuer]::view-transition-old(achse){animation-name:achse-runter-raus}
  html[data-sprung=neuer]::view-transition-new(achse){animation-name:achse-runter-rein}


  /* ---------- Der Blaetterschritt in der Reihe ----------
     Ein Termin weiter ist derselbe Sprung wie ein Jahr weiter, nur eine Groesse
     kleiner und eine Achse quer: die Spalte laeuft in die Richtung des Pfeils
     durch, statt dass die Seite blinkt. Dieselben zwoelf Prozent, dieselbe
     Verzoegerungskurve.

     **Aber der kurze Takt, nicht der lange.** Der Weg auf eine Detailseite
     passiert einmal und darf sich Zeit nehmen; das Blaettern in der Reihe ist
     eine Kernbedienung und passiert im Dutzend - wie der Filterwechsel. Eine
     halbe Sekunde, die beim ersten Mal traegt, steht beim zwoelften Mal im Weg.
     `--takt-rueckweg` traegt darum ab hier beides: den Weg zurueck und den
     Schritt zur Seite. Beide sind kurz, und aus demselben Grund - man war schon
     da, oder man geht nur einen Schritt.

     **Es wandert kein Titel.** Zwischen zwei Veranstaltungen gibt es keinen
     Gegenpart: der Titel der einen ist nicht der Titel der anderen. Jeder
     Name, der stehen bliebe, bekaeme seine eigene Gruppe und liefe seine
     eigene Bewegung - genau der Schwarm, den weg.js auf dem Hinweg
     verhindert. Es traegt darum genau ein Name die Bewegung, und der liegt an
     der Spalte als Ganzes. Nicht benannt heisst nicht bewegt.

     Der Name steht nur waehrend des Schritts da, aus demselben Grund wie an
     der Achse: er macht aus der Spalte einen Stapelkontext. Gesetzt wird er
     in beiden Dokumenten - im alten beim Wisch oder Klick (reihe.js), im neuen
     im Kopf vor dem ersten Bild (kopf.php). */
  html[data-blaettern] .event-seite{view-transition-name:spalte}
  html[data-blaettern] .event-titel{view-transition-name:none}

  html[data-blaettern]::view-transition-old(spalte),
  html[data-blaettern]::view-transition-new(spalte){
    animation-duration:var(--takt-rueckweg,.28s);
    animation-timing-function:var(--kurve-weg,cubic-bezier(.16,1,.3,1))}
  html[data-blaettern=vor]::view-transition-old(spalte){animation-name:spalte-links-raus}
  html[data-blaettern=vor]::view-transition-new(spalte){animation-name:spalte-links-rein}
  html[data-blaettern=zurueck]::view-transition-old(spalte){animation-name:spalte-rechts-raus}
  html[data-blaettern=zurueck]::view-transition-new(spalte){animation-name:spalte-rechts-rein}
}

@keyframes spalte-links-raus{to{transform:translateX(-12%);opacity:0}}
@keyframes spalte-links-rein{from{transform:translateX(12%);opacity:0}}
@keyframes spalte-rechts-raus{to{transform:translateX(12%);opacity:0}}
@keyframes spalte-rechts-rein{from{transform:translateX(-12%);opacity:0}}

@keyframes achse-hoch-raus{to{transform:translateY(-12%);opacity:0}}
@keyframes achse-hoch-rein{from{transform:translateY(12%);opacity:0}}
@keyframes achse-runter-raus{to{transform:translateY(12%);opacity:0}}
@keyframes achse-runter-rein{from{transform:translateY(-12%);opacity:0}}



/* ---------- Der Einzug ----------
   Oben wandert, unten haengt sich auf.

   Der Auftakt hat seine eigene Ankunft: der Titel wandert aus der Liste
   hierher, und das Plakat steht, wo es steht. Darunter beginnt die Spalte, und
   die kam bisher gar nicht an - sie war einfach da. Wer ueber einen geteilten
   Link hereinkommt, sah ein Plakat mit einer Bildschirmhoehe und darunter,
   beim ersten Wisch, eine fertige Wand aus Text.

   Jetzt haengt sich die Spalte auf, Block fuer Block, so wie sie gelesen wird:
   1.2rem von unten herauf, in der Kurve und der Dauer des Hauses. Das ist
   derselbe Weg wie oben, nur kurz - kein Auftritt, sondern ein Zurechtruecken.

   **Die Kadenz der Abstaende ist die Kadenz der Ankunft.** Die Termindaten
   sind keine Liste gleich lauter Zeilen, sondern drei Gruppen in drei
   Abstaenden - der Tag, der Ort, das zu Tuende. Genau diese drei Gruppen
   kommen nacheinander an, im selben Verhaeltnis. Vier gleich getaktete Zeilen
   waeren die Kadenz, die das Layout vermeidet, noch einmal aufgebaut.

   **Der Einzug gilt dem Gelesenen, nicht dem Gehaengten.** Die Haengung
   bekommt keinen - Bilder haengen an einer Wand, sie ziehen nicht ein, und
   eine Reihe Fotos, die nacheinander erscheint, waere die Kachelwand mit einer
   Uhr daran. Es ist derselbe Satz wie beim Hover: ein Bild an der Wand
   reagiert nicht darauf, dass jemand hinsieht.

   Der Ausgangszustand ist der sichtbare. Gerichtet wird erst, wenn einzug.js
   `data-einzug` gesetzt hat - ohne Skript, mit einem Modul, das nicht kommt,
   und bei reduzierter Bewegung steht die Spalte einfach da.

   **`screen and`, und das ist keine Formsache.** Papier hat keinen Rand, ueber
   den etwas hereinkaeme: ein Block, der auf dem Schirm nie ins Bild geraten
   ist, stuende beim Drucken bei Deckkraft 0 - der Aushang, den die
   Ehrenamtliche an die Tuer haengt, kaeme halb leer aus dem Drucker. Der
   Einzug ist eine Sache des Schirms und gehoert dorthin. */
@media screen and (prefers-reduced-motion:no-preference){
  html[data-einzug] .event-seite .event-daten>*,
  html[data-einzug] .event-seite .body,
  html[data-einzug] .event-seite .support,
  html[data-einzug] .event-seite .reihe-fuss{
    opacity:0;transform:translateY(var(--takt-eng))}

  html[data-einzug] .event-seite .event-daten.da>*,
  html[data-einzug] .event-seite .body.da,
  html[data-einzug] .event-seite .support.da,
  html[data-einzug] .event-seite .reihe-fuss.da{
    animation:einzug var(--takt-weg) var(--kurve-weg) both}

  /* Drei Gruppen, drei Schritte. 70 ms sind der kleinste Abstand, den man als
     Reihenfolge liest und nicht als Verzoegerung; drei davon bleiben unter
     einer Viertelsekunde und damit innerhalb der einen Bewegung. */
  html[data-einzug] .event-seite .event-daten.da>.ort{animation-delay:.07s}
  html[data-einzug] .event-seite .event-daten.da>.eintritt,
  html[data-einzug] .event-seite .event-daten.da>.ticket,
  html[data-einzug] .event-seite .event-daten.da>.kalender{animation-delay:.14s}
}

@keyframes einzug{from{opacity:0;transform:translateY(var(--takt-eng))}
  to{opacity:1;transform:none}}

/* Bewegung ist auf dieser Seite genau viererlei: die Vorschau am Cursor (die sich
   ueber dieselbe Abfrage selbst abschaltet), der wandernde Titel samt seinem
   Weg in die Nahsicht, der Einzug der Spalte und geschobenes Scrollen. Farb- und
   Deckkraftwechsel bleiben - sie sind Rueckmeldung auf eine Handlung, keine Bewegung,
   und ihr Wegfall nimmt Orientierung, statt sie zu schonen.

   Der Einzug und die Fassung der Nahsicht stehen vollstaendig in
   no-preference - hier ist darum nichts zurueckzunehmen. Was dort nicht
   gesetzt wird, steht einfach da, und das ist die schonende Fassung: ein Text,
   der schon aufgehaengt ist. */
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms!important;animation-iteration-count:1!important}
  html{scroll-behavior:auto}
  .filter-leise{scroll-snap-type:none}
  /* Der wandernde Titel faellt weg; der Grundwechsel bleibt. Er ist eine
     Deckkraft, keine Bewegung, und ohne ihn spraenge der Text hart um - das ist
     das Gegenteil von schonend. Die Namen stehen deshalb in
     no-preference, diese Regel hier nicht. */

  /* Der Lichtabfall haengt am Scrollen und ist damit die einzige Stelle, an der
     eine Farbe sich ohne Handlung des Nutzers aendert. Sie faellt hier weg; der
     Raum ist dann gleichmaessig belichtet statt gar nicht. */
  .zeile,
  .achsenzeile{animation:none;--nah:1}

  /* Die Standmarke faehrt sonst; hier springt sie wieder. Ein Uebergang auf
     left ist keine Animation und faellt vom Block oben nicht mit. */
  .dichte-marke{transition:none}

  /* Das Zeichen bleibt stehen. Nicht »springt statt faehrt«: ein Sprung ist
     die haerteste Form derselben Bewegung und damit das Gegenteil von
     schonend. Der Weg nach Hause ist ein Verweis, kein Zustand - es geht
     nichts verloren, wenn er sich nicht bewegt. */
  .kopf a:hover .logo,
  .kopf a:active .logo,
  .kopf a:focus-visible .logo{transform:none}
  .kopf .logo{transition:none}
  /* Aus demselben Grund und mit derselben Folge: der Punkt bleibt liegen, wo
     er klebt, und die Zeile bleibt schief. Angeklebt wird auch nicht - die
     Ankunft steht ohnehin schon in einer no-preference-Abfrage. */
  a.klebepunkt:hover .scheibe,
  a.klebepunkt:active .scheibe,
  a.klebepunkt:focus-visible .scheibe{scale:1}
  a.klebepunkt:hover .schlag,
  a.klebepunkt:active .schlag,
  a.klebepunkt:focus-visible .schlag{rotate:-5deg}
  a.klebepunkt:nth-child(2):hover .schlag,
  a.klebepunkt:nth-child(2):active .schlag,
  a.klebepunkt:nth-child(2):focus-visible .schlag{rotate:4deg}
  .klebepunkt .scheibe,.klebepunkt .schlag{transition:none}
}

/* ---------- Papier ----------
   Die Wand ist eine Flaeche, und Flaechen druckt ein Browser nicht mit. Auf
   Papier stand darum bisher weisse Schrift auf weissem Blatt: ein leeres Blatt,
   und zwar genau fuer die eine Person, die es am haeufigsten braucht - die
   Ehrenamtliche, die den Monat ausdruckt und an die Tuer haengt.

   Umgekehrt wird nicht die Gestaltung umgedreht, sondern der Traeger gewechselt.
   Papier ist weiss und trocken; es hat kein Barlicht, keinen Sandboden und
   keinen Zeiger. Was bleibt, ist der Aushang selbst: Datum links, Titel gross,
   Haarlinie dazwischen - dieselbe Ordnung, nur in Schwarz.

   Die Kategoriefarben fallen weg. Sie sind auf der Wand die einzige Farbe mit
   Grund; auf einem Schwarzweissdrucker waeren sechs helle Pastelltoene sechs
   Graustufen, die niemand auseinanderhaelt. Die Kategorie steht ohnehin als
   Wort da. */
@media print{
  :root{
    --licht:0;
    --wand:#fff;
    --background:#fff;
    --textfarbe:#000;
    --titelfarbe:#000;
    --primary:#000;
    --primary-hell:#000;
    --dunkel:#000;
    --linie:rgba(0,0,0,.35);
    --trennpunkt:rgba(0,0,0,.45);
    --text-gedaempft:rgba(0,0,0,.75);
    --text-still:rgba(0,0,0,.55);
    --farbe-default:#000;
    --takt-block:2rem;
    --takt-fuss:2rem;
  }
  /* Die Belichtungsregel setzt beide Weiss nicht nur an der Wurzel, sondern je
     Zeile - dort wuerde ein Wert von der Wurzel nicht ankommen, sondern
     ueberschrieben. Auf Papier muessen deshalb dieselben drei Traeger genannt
     werden wie dort. Sonst bleibt der Aushang schwarz und die Liste darin
     weiss. */
  :root,.zeile,.achsenzeile{
    --textfarbe:#000;
    --titelfarbe:#000;
    --linie:rgba(0,0,0,.35);
    --trennpunkt:rgba(0,0,0,.45);
    --text-gedaempft:rgba(0,0,0,.75);
    --text-still:rgba(0,0,0,.55);
    --farbe-default:#000;
  }
  html,body{background:#fff;color:#000}
  /* Papier hat keinen Zeiger, also traefe die Abfrage oben zu und das Plakat
     stuende im Ausdruck. Der gedruckte Aushang ist aber ein Textdokument -
     zusammengeruecktes Datum, Titel, Haarlinie. Ein Bild je Termin machte aus
     zwei Blaettern zwanzig. */
  .zeile-plakat{display:none}

  /* Der Klebepunkt druckt, aber ohne die Flaeche. --primary steht auf Papier
     auf Schwarz, und ein handtellergrosser schwarzer Kreis mit weisser Schrift
     darin waere ein Tintenfleck - auf genau dem Blatt, das die Ehrenamtliche
     an die Tuer haengt. Was uebrig bleibt, ist die Ankuendigung selbst:
     Schlagzeile und Satz ueber einer Haarlinie, linksbuendig, in derselben
     Ordnung wie der Aushang darunter. Auch die Schraeglage faellt weg - sie
     sagt »aufgeklebt«, und auf einem Blatt klebt nichts. */
  .klebewand{position:static;display:block;margin:0 0 var(--takt-zeile);
    padding-bottom:var(--takt-eng);border-bottom:1px solid var(--linie);
    inset:auto}
  /* Die Punkte haengen am Schirm in den beiden Waenden und damit absolut.
     Auf Papier gibt es keine Waende - beide treten in den Fluss zurueck.
     Ausdruecklich auch `max-width` und `translate`: sie rechnen mit vw und
     mit einer Lage, die es hier nicht gibt. */
  .klebepunkt{position:static;width:auto;max-width:none;translate:none;
    margin:0;text-align:left}
  .klebepunkt+.klebepunkt{margin-top:var(--takt-eng)}
  .klebewand[data-anzahl="2"] .klebepunkt:nth-child(2){margin-top:var(--takt-eng)}
  /* `aspect-ratio` muss mit weg. Ohne Kreis, aber mit Verhaeltnis waere die
     Schlagzeile ein quadratischer Block ueber die halbe Seite - beide Masse
     stehen auf `auto`, und genau dann greift das Verhaeltnis. */
  .klebepunkt .scheibe{display:block;width:auto;height:auto;aspect-ratio:auto;
    padding:0;border-radius:0;background:none;color:#000;scale:1}
  .klebepunkt .schlag{font-size:var(--h3);rotate:0deg;max-width:none}
  .klebepunkt .satz{color:#000}
  /* Der Akzent kommt aus dem Markup, nicht aus einem Token - er wird deshalb
     hier ueberschrieben und nicht oben mit umgestellt. */
  *{--akzent:#000 !important;-webkit-print-color-adjust:economy;print-color-adjust:economy}

  @page{margin:14mm}

  /* Alles, was den Raum baut, hat auf Papier keine Entsprechung. */
  .lichtlage,.zeiger,.hover-canvas,.huelle::after,
  .huelle::before{display:none !important}
  .filter,.filter-leise,.kalender-abo,.blaettern,.skip,.fuss .sozial,
  .dichte-marke,.dichte-wort{display:none}
  /* Und alles, was eine Handlung ist. Ein Knopf auf Papier ist kein Knopf,
     sondern eine schwarze Flaeche mit schwarzer Schrift darin - die Umkehrung
     des Systems hat auf einem weissen Blatt keine zweite Farbe mehr, in die sie
     umkehren koennte. Der Kalendereintrag steht ohnehin dort, wo man ihn machen
     kann, und das ist nicht dieses Blatt. */
  /* Die Reihe faellt mit: sie ist von Anfang bis Ende Bedienung. Zwei Pfeile
     und ein Weg zurueck sagen auf einem Aushang an der Tuer nichts - dort gibt
     es keinen Nachbartermin zum Antippen und keine Liste, auf die man
     zurueckkaeme. */
  .event-daten .ticket,.event-daten .kalender,.zurueck,
  .reihe-fuss,.reihe-spuren{display:none}
  .event-seite{padding-inline:0}

  .huelle{min-height:0;padding-inline:0}
  /* Der Affe ist in Weiss gezeichnet - auf Papier waere er weiss auf weiss und
     damit nicht da. Umgedreht, nicht ersetzt: es ist dieselbe Zeichnung, nur auf
     dem anderen Traeger. Ein Aushang ohne das Zeichen des Hauses ist ein Zettel. */
  .kopf .logo{height:4rem;filter:invert(1);
    -webkit-print-color-adjust:exact;print-color-adjust:exact}
  /* Liegt das Zeichen als Maske, braucht es kein Umdrehen: dann ist es
     schlicht schwarz. Ein umgedrehter Gluehton waere blau. */
  @supports (mask-image:url("")) or (-webkit-mask-image:url("")){
    .kopf .logo{filter:none;color:#000}
  }
  /* Eine Zeile gehoert auf ein Blatt; ein Titel ohne sein Datum ist keine Auskunft. */
  .zeile,.achsenzeile,.jahrgruppe{break-inside:avoid}
  .gruppe{break-after:avoid}
  .zeile{padding-block:1.2rem}
  /* Ein Plakat gehoert auf den Aushang, aber nicht als eigene Seite. Gedeckelt
     auf gut ein Drittel der Hoehe steht es ueber Titel und Termindaten, statt
     sie auf Blatt zwei zu schieben - und ein dunkles Plakat kostet dabei nicht
     eine ganze Patrone. */
  .event-bilder img{max-height:9cm;width:auto;height:auto}
  /* Ein Blatt hat keinen Bildschirm, den man fuellen koennte. Der Auftakt
     legt seinen Deckel darum ab und wird wieder so hoch wie das, was in ihm
     steht - sonst stuende auf Papier eine leere Flaeche in Fensterhoehe. */
  .event-auftakt--bild{height:auto;display:block}
  /* Ein Blatt hat auch keine Wand neben der Spalte: auf 14 mm Rand ist die
     Mitte die einzige Achse, die es gibt. Das Raster faellt darum weg und der
     Satz steht wieder von Rand zu Rand. */
  .event-seite{display:block}
  .event-bilder{display:block;margin-left:0}
  .event-bilder a{height:auto}
  .event-auftakt--bild .event-kopf{margin-top:var(--takt-zeile)}
  /* Die Adresse hinter dem Wort - auf Papier ist ein Link nur dann einer,
     wenn er sich abtippen laesst. */
  .body a[href^="http"]::after{content:" (" attr(href) ")";font-size:.85em;word-break:break-all}
  .fuss{border-top:1px solid var(--linie);padding-top:1.2rem}
  /* Auf einem Blatt an der Tuer sind vier Namen von Rechtstexten kein Fuss,
     sondern Fuellsel. Was dort steht, ist die eine Angabe, die jemand vor der
     Tuer braucht. */
  .fuss nav{display:none}
  /* Der Lichtzustand ist eine Auskunft ueber jetzt und wird auf Papier zur
     Behauptung. Statt seiner die Zeiten - der Satz dafuer steht immer im
     Markup und ist nur hier sichtbar (siehe lichtstatus.php). */
  .lichtstatus .fall{display:none !important}
  .lichtstatus .fall--papier{display:inline !important}
}
