/* ============================================================
   Martin Sonneborn — One-Pager (Editorial Broadsheet, Foto-Hero)
   Built on the Sonneborn Design System tokens (styles.css).
   Newsprint paper + agitprop red + Anton poster type; the hero is a
   full-bleed EU-Parliament photo under a dark scrim — the photo is
   framed (zoom-pan) so text never sits on the person.
   ============================================================ */

/* Marken-Rot auf dunklem Grund: --red-500 (#981436) erreicht auf #0e0d0c nur
   2,30:1. Dieser Ton ist derselbe Farbton, nur hell genug für 5,3:1. Überall
   dort benutzen, wo rote SCHRIFT auf Schwarz steht — nicht für Flächen. */
:root{--red-on-dark:#d06279;
  /* Hoehe des gepinnten EU-Bandes. Steht als Token hier, weil das JS sie fuer
     die Fusslinie des Megafons braucht — beides muss denselben Wert benutzen. */
  --eu-pinned-h:56px;
  /* Der Megafon-Gag hat bewusst eigene Zeiten: der Auftritt darf laenger sein als
     UI-Bewegung (AUDIT: „Marketing / explanatory can be longer"), der Abgang muss
     kurz sein, weil er mit dem Aufklappen des Bandes zusammenfaellt. Benannt statt
     als nackte Zahlen verstreut — vorher standen 550ms, 500ms und 220ms an drei
     Stellen ohne erkennbaren Zusammenhang. */
  --dur-gag-in:550ms;
  --dur-gag-out:220ms;
  /* Das Filter-Umschalten hat bewusst eigene Zeiten. NICHT --dur-fast
     umbiegen: an dem Token haengen auch die Chips, die Knoepfe und der
     Skip-Link — die sollen unveraendert schnell bleiben.
     Der Eintritt ist gestaffelt, den Index --i setzt apply() in site.js auf
     die ersten vier sichtbaren Zeilen (danach gedeckelt, sonst ueberholt
     Zeile 13 den Takt). Deckel 3 x 22ms = 66ms Vorlauf, macht mit 170ms
     Dauer 236ms Gesamtlaenge.
     Der Test vom 2026-09-03 stand auf 240ms/35ms = 345ms und ist zurueck-
     genommen: gemessen fuehlte sich das als Verzoegerung an, nicht als
     Politur. Ein Filter ist eine Zustandsaenderung, keine Erzaehlung. */
  --dur-filter:170ms;
  --ease-filter:cubic-bezier(0.16, 0.84, 0.24, 1);
  --shift-filter:11px;
  --stagger-filter:22ms}

/* ---------- FORMREGEL (eine pro Rolle, keine Ausnahmen ausser einer) ----------
   Das Designsystem vergibt die Radien nach Rolle (tokens/spacing.css):
     Flaechen, Buttons, Bilder .... 0        „posters, stamps", hart wie Siebdruck
     Tags / Chips ................. pill     Token sagt woertlich „tags only"
     Rundknoepfe .................. circle
   Einzige bewusste Ausnahme: der Marker-Block hinter SONNEBORN traegt
   ungleiche, organische Ecken — das ist eine Handgeste, kein UI-Element.
   Vorher standen hier sechs Formsprachen nebeneinander (0 / 4px / 12px /
   pill / circle / organisch), u.a. zwei Buttons mit zwei Kanten und zwei
   chip-artige Dinge mit zwei Formen. */

*{box-sizing:border-box}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion: reduce){html{scroll-behavior:auto}}
body{margin:0;background:var(--paper);color:var(--ink-900);font:var(--text-body)}
/* Landmark ohne eigene Box: das sticky EU-Band bleibt am Body verankert
   und damit bis zum Seitenende gepinnt. */
main{display:contents}
.wrap{max-width:var(--container-max);margin:0 auto;padding:0 var(--gutter)}

/* Skip-Link: sichtbar nur bei Tastatur-Fokus */
.skip-link{position:absolute;left:12px;top:-56px;z-index:100;background:var(--ink-900);color:#fff;
  font:var(--fw-bold) 14px/1 var(--font-sans);padding:12px 18px;border-radius:var(--radius-0);
  transition:top var(--dur-fast) var(--ease-out)}
.skip-link:focus{top:12px;outline:none;box-shadow:0 0 0 3px var(--paper),0 0 0 6px rgba(152,20,54,.85)}
a{color:inherit;text-decoration:none}
/* Ersetzt das graue OS-Tap-Rechteck durch die Marke. Bewusst NICHT `transparent`:
   die ~20 Papier-Ziele ohne eigenen :active-State (Header-Social, .brand, Quellen-
   und Impressum-Link) hätten sonst gar keine Touch-Rückmeldung mehr. Alpha .18
   liegt unter allen Fokusring-Alphas, damit ein Tap-Blitz nie als Fokus gelesen wird. */
a,button{-webkit-tap-highlight-color:rgba(152,20,54,.18)}
/* base.css:22 setzt ein ungeschütztes a:hover{text-decoration:underline}. Auf Touch
   rastet das als Unterstrich auf button-förmigen Links ein — dort abschalten, für
   echte Zeiger bleibt es unangetastet. */
@media (hover: none){a:hover{text-decoration:none}}

/* ---------- HOVER-GUARD ----------
   Alle Hover-Zustände hängen an echten Zeigern. Ohne diesen Block feuern sie auf
   Touch beim Antippen und BLEIBEN hängen — u.a. auf .termin (nicht interaktiv) und
   auf drei Elementen mit target=_blank, die dann nach der Rückkehr „ausgewählt"
   aussehen. Der Block steht bewusst GANZ OBEN: alle :active-Regeln weiter unten
   haben gleiche Spezifität und gewinnen dadurch, solange der Finger unten ist. */
@media (hover: hover) and (pointer: fine) {
  .social a:hover{color:var(--red-500);transform:translateY(-1px)}
  .site-footer .social a:hover,
  .hero-social a:hover{color:var(--red-on-dark)}   /* Footer und Hero sind dunkel */
  .btn-cta:hover{background:var(--red-600)}
  .eu:hover{background:var(--red-600)}
  .eu:hover .eu-arrow-inline{transform:translateX(7px)}
  .filter-chip:hover{border-color:var(--red-500);color:var(--red-600)}
  /* .termin:hover ist bewusst weg: die Zeile ist nicht klickbar, faerbte sich
     aber wie ein Knopf ein und versprach eine Detailansicht, die es nicht gibt. */
  .termin-tickets:hover{background:var(--red-500);color:#fff;transform:translate(2px,2px)}
  .book a:hover img{transform:translate(-3px,-5px);box-shadow:7px 7px 0 var(--red-500)}
  .footer-legal a:hover{color:var(--red-on-dark)}
  .books-sub:hover{color:#fff}
  /* Stand bis 2026-08-02 AUSSERHALB dieses Blocks und blieb auf Touch nach dem
     Antippen haengen — dieselbe Falle wie bei den anderen neun. */
  .books-nav:hover{border-color:var(--red-on-dark);color:var(--red-on-dark)}
  .quote-toggle:hover{background-color:var(--red-600)}
  /* Die Spur-Fassung traegt keine Flaeche (siehe Handy-Block), also darf der
     Hover auch keine einfaerben — sonst blitzte hier ein rotes Quadrat auf. */
  .quote-toggle-spur:hover{background-color:transparent;color:#fff}
}

/* social icon rows */
/* flex:0 0 auto ist hier tragend: ohne das saugt die Icon-Reihe den gesamten
   Ueberlauf des space-between-Headers auf und die Icons schrumpfen auf 7,5px
   (bei 321px sogar auf 0) — sichtbar bleibt nur das ueberstehende SVG.
   Die Trefferflaeche ist 44px hoch, das Glyph bleibt 20px. */
.social{display:flex;align-items:center;gap:6px}
.social a{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:44px;margin:-12px -6px;color:var(--ink-700);
  transition:color var(--dur-fast) var(--ease-out),transform var(--dur-fast) var(--ease-out)}
.social svg{flex:0 0 auto;width:20px;height:20px;fill:currentColor;display:block}

/* ---------- HEADER (on paper) ---------- */
.site-header{background:var(--paper);position:sticky;top:0;z-index:50;border-bottom:1px solid var(--ink-200)}
.site-header .wrap{display:flex;align-items:center;justify-content:space-between;gap:20px;height:86px}
.brand{display:inline-flex;flex-direction:column;gap:3px;text-decoration:none;white-space:nowrap}
.brand-name{font:var(--fw-black) 25px/1 var(--font-sans);text-transform:uppercase;letter-spacing:.02em;color:var(--ink-900)}
.brand-name .red{color:var(--red-600)}
.brand-sub{font:var(--fw-bold) 11px/1 var(--font-sans);text-transform:uppercase;letter-spacing:.2em;color:var(--red-600)}
.site-header .social svg{width:22px;height:22px}
/* Rechnung: Wortmarke 207px + 20px Abstand + sechs 44px-Ziele mit 6px Luecken
   = 521px, plus 48px Aussenabstand => unter ~620px passt das nicht mehr
   nebeneinander. Vorher wurde die Reihe stattdessen auf 7,5px zusammen-
   gequetscht (bei 321px auf 0) und blieb als sechs unsichtbare Tab-Stopps
   stehen. Hier verschwindet sie ganz — der Footer traegt dieselben sechs
   Links in voller Groesse. */
/* Bis 2026-08-01 lag die Grenze bei 620px (dort wurde es rechnerisch eng).
   Jetzt 700px: darunter faehrt das Megafon-Cutout in genau diese Ecke ein und
   wuerde die Icons ueberlagern. Dieselben sechs Links stehen im Footer. */
@media (max-width:700px){.site-header .social{display:none}}

/* ---------- HERO (full-bleed EU-Parliament photo, cinematic) ---------- */
.hero{position:relative;overflow:hidden;border-bottom:3px solid var(--ink-900);padding-top:clamp(14px,2.6vw,28px);background:var(--ink-900)}
/* Foto füllt den Hero randlos. */
.hero-bg{position:absolute;inset:0;z-index:0;display:block;margin:0}
.hero-bg img{width:100%;height:100%;object-fit:cover;object-position:50% 38%;transform:scale(1.32);transform-origin:6% 46%}
/* Dunkler Verlauf-Schleier: links/unten kräftig für Textlesbarkeit, oben-rechts
   leicht für die Pressestimme; ganz unten ein roter Übergang zum EU-Band. */
.hero::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(95deg, rgba(20,18,16,.92) 0%, rgba(20,18,16,.82) 30%, rgba(20,18,16,.5) 48%, rgba(20,18,16,.18) 62%, rgba(20,18,16,0) 76%),
    radial-gradient(120% 95% at 100% 0%, rgba(20,18,16,.62) 0%, rgba(20,18,16,.26) 26%, rgba(20,18,16,0) 52%),
    linear-gradient(0deg, rgba(20,18,16,.85) 0%, rgba(20,18,16,.14) 24%, rgba(20,18,16,0) 40%),
    linear-gradient(0deg, rgba(152,20,54,.36) 0%, rgba(152,20,54,0) 15%)}
/* Bildnachweis: gehört sichtbar ans Foto, darf aber nichts von ihm wollen.
   Unten rechts auf dem dunkelsten Teil des Schleiers, klein und zurückgenommen —
   noch gut lesbar (rund 5:1), aber ohne Anspruch auf Aufmerksamkeit.
   z-index 2, damit es über dem Schleier, aber unter dem Text liegt. */
.hero-credit{position:absolute;right:var(--gutter);bottom:8px;z-index:2;margin:0;
  font:var(--fw-medium) 10px/1.2 var(--font-sans);letter-spacing:.04em;
  color:rgba(243,239,232,.55);pointer-events:none}
/* Unter 700px steht der Bildnachweis ganz unten, die Social-Reihe darueber.
   Nebeneinander passen sie nicht: die Reihe misst 262px, der Nachweis rund 160,
   verfuegbar sind 327. */
/* Bei 320x720 gemessen: rgba(...,.55) auf dem Scrim = 4,49:1 — 0,01 unter
   der geforderten 4,5. Auf .62 sind es ~5,3:1. Die Schriftgroesse bleibt,
   der Bildnachweis soll klein sein; lesbar muss er trotzdem sein. */
@media (max-width:620px){.hero-credit{font-size:9px;color:rgba(243,239,232,.62)}}

/* ---------- SOCIAL AN DER HERO-UNTERKANTE (nur Handy) ----------
   Auf dem Handy verschwindet die Reihe aus dem Header (das Megafon braucht die
   Ecke) und stand danach erst im Footer, also nach 3.100px Scrollweg. Hier sitzt
   sie am unteren Rand des Heros: der endet bei 375x812 fast genau an der Falz,
   die Reihe liegt damit im Daumenbereich, auf dunklem Grund und ohne mit der
   Ueberschrift zu konkurrieren.
   position:absolute — die Reihe kostet keine Layouthoehe, der Hero bleibt so
   hoch wie er war. Die Icons klont das JS aus dem Header, damit die sechs
   SVG-Pfade nicht ein drittes Mal im Markup stehen.
   Sichtbar sind immer genau zwei Reihen: Desktop Header + Footer, Handy Hero +
   Footer. Die jeweils abgeschaltete ist display:none und damit auch aus dem
   Tab-Fluss. */
.hero-social{display:none}
@media (max-width:700px){
  /* Mittig ueber die volle Breite, der Bildnachweis sitzt darunter an der
     Unterkante. bottom:28 laesst der 44px-Trefferflaeche (sie ragt ueber die
     negativen Raender 12px unter die sichtbaren Glyphen) Luft zum Nachweis:
     bei 28px ueberlappte sie ihn um 3px, bei 38px bleiben 4px frei. */
  .hero-social{display:flex;justify-content:center;position:absolute;left:0;right:0;bottom:38px;z-index:3;gap:2px}
  .hero-social a{color:rgba(243,239,232,.92)}
  .hero-social svg{width:21px;height:21px}
}

/* Hero füllt die Resthöhe, sodass das Aktivitäten-Band beim ersten Laden
   genau am unteren Bildschirmrand sitzt (Header + Hero + Band = 100vh). */
/* --eu-band-h setzt das Skript aus der GEMESSENEN Bandhoehe (site.js, messeBand).
   Vorher stand hier die Konstante 249, die ein 131px hohes Band unterstellte.
   Seit das Band eine dritte Zeile traegt, sind es 152px — die Unterkante lag
   damit 21px UNTER der Falz (gemessen 1440x900: Bandunterkante 921). Der
   Fallback 131px haelt den Wert, bis das Skript einmal gemessen hat, und
   entspricht dem alten Verhalten. 249 = 87 Header + 3 Strich + 28 Luft + 131. */
.hero-grid{position:relative;z-index:2;display:grid;grid-template-columns:minmax(0,1fr);gap:24px;align-items:center;
  min-height:max(460px, calc(100svh - 118px - var(--eu-band-h, 131px)))}
/* min-width:0 ist Pflicht, nicht Kosmetik: als Grid-Element hat .hero-text von
   Haus aus min-width:auto, also die Mindestbreite seines Inhalts. Seit im Hero
   ein Wischkarussell steckt, ist dieser Inhalt 9800px breit (14 Folien à 100%),
   und die Spalte wuchs auf die vollen 700px max-width — gemessen bei 375px
   Viewport, die halbe Seite lief unter dem Bildrand hindurch. Die minmax(0,1fr)
   der Spalte allein genügt dagegen nicht, der Riegel muss am Element selbst
   sitzen. */
.hero-text{align-self:center;padding:clamp(18px,2.5vw,30px) 0;max-width:700px;min-width:0}
/* ══════ PRESSESTIMMEN ══════
   Ein Markup, zwei Erscheinungsformen.
   Desktop: rechts oben, EIN Zitat sichtbar, die uebrigen display:none, Wechsel
            per Ueberblendung, dunkler Schleier hinter dem Text.
   <=900px: Wischkarussell ueber die volle Breite, OHNE Schleier — der
            Hero-Verlauf ist dort oben zu 90% deckend, ein zweiter Schleier
            darueber war nur eine graue Platte im Bild.
   Nebeneffekt der Folienbauweise: reserveHeight() ist ersatzlos entfallen. Auf
   dem Handy liegen alle Folien in einer Flex-Zeile, die Spur ist damit von sich
   aus so hoch wie die hoechste Folie — der Ruck, den die Funktion abfing, kann
   konstruktiv nicht mehr entstehen. */
/* 880 statt der frueheren 820: seit die Quelle nicht mehr umbrechen darf, ist
   sie der breiteste Einzelposten. Gemessen brauchte die laengste („Victor
   Negrescu …") samt Knopf und Polsterung 813px — sieben Pixel unter der alten
   Grenze. Das haelt keine Ersatzschrift aus, die vor dem Laden der Webfont kurz
   breiter setzt; mit 880 sind es 67px Reserve. */
/* max-width stand auf 880px. Zwischen 901 und 1100px Fensterbreite lief das
   laengste Zitat damit als EINE Zeile von 733px (~82 Zeichen) ueber den Hero —
   deutlich ueber dem lesbaren Mass von 45-75. min() deckelt zusaetzlich auf
   62% der Fensterbreite, was in diesem Band 560-680px ergibt. */
.hero-quote{position:absolute;top:0;right:var(--gutter);max-width:min(880px,62vw);margin:0;text-align:right;z-index:3;
  /* 180ms statt der frueheren 500: die Blende laeuft ZWEIMAL je Wechsel (raus,
     Text tauschen, rein) und der Wechsel feuert alle 7,5s von selbst. Mit 500
     waren das 1000ms Bewegung je Wechsel, rund 13% der Zeit stand das Zitat im
     Uebergang. Das JS liest die Dauer aus dieser Zeile, nicht aus einer zweiten
     Zahl — siehe blendeDauer() im Skript. */
  transition:opacity var(--dur-base) var(--ease-out)}
.hero-quote.is-fading{opacity:0}
.hero-quote-track{display:block}
.hero-quote-slide{display:none}
.hero-quote-slide.is-active{display:block}
/* Der Schleier haengt auf der inneren Huelle, damit er den Text umschliesst
   statt eine Box zu fuellen. Weicher Auslauf nach allen Seiten (schon bei 62%
   durchsichtig), sonst entstuende eine sichtbare Kante. */
/* position:relative macht die Huelle zum Bezugsrahmen fuer den Eckknopf.
   padding-bottom von 26 auf 36: das Eckquadrat ragt 26px in die Box hinein und
   braucht Abstand zur Quellenzeile — 36 minus 26 lassen 10px Luft. */
.hero-quote-inner{position:relative;display:inline-block;padding:22px 42px 36px 64px;
  background:radial-gradient(78% 92% at 62% 48%,
    rgba(20,18,16,.88) 0%, rgba(20,18,16,.78) 30%, rgba(20,18,16,.5) 55%,
    rgba(20,18,16,.2) 76%, rgba(20,18,16,0) 100%)}
.hero-quote-text{display:block;font:italic var(--fw-regular) clamp(18px,2.1vw,26px)/1.35 var(--font-serif);color:#f3efe8}
/* ---------- QUELLENZEILE ----------
   Nur noch die Quelle, rechtsbuendig — sie schliesst damit exakt mit der rechten
   Kante des Zitattextes ab. Vorher teilte sie sich eine Flex-Zeile mit dem Knopf
   und war um dessen Breite plus Abstand nach links versetzt.
   nowrap haelt sie einzeilig, ausdrueckliche Ansage: der Autor darf unten nicht
   umbrechen. Nachgemessen: die laengste Quelle („Victor Negrescu …") misst
   einzeilig 659px, verfuegbar sind 714px. Auf schmaleren Desktops schrumpft die
   Schrift ueber clamp() mit, der Abstand bleibt also erhalten. Auf dem Handy
   wird nowrap wieder aufgehoben. */
.hero-quote-byline{display:block;text-align:right;margin-top:9px}
.hero-quote-cite{display:block;margin-top:0;white-space:nowrap;
  font:var(--fw-bold) clamp(12px,1.05vw,15px)/1.2 var(--font-sans);text-transform:uppercase;letter-spacing:.12em;color:rgba(243,239,232,.85)}
/* ---------- PLAY/PAUSE: rotes Quadrat in der unteren rechten Ecke ----------
   Aus dem Fluss genommen, deshalb kostet der Knopf keine Layoutbreite mehr und
   kann die Quellenzeile nicht mehr verschieben.
   Der Trick mit background-clip: das Element ist volle 44x44 gross und damit als
   Trefferflaeche normgerecht, eingefaerbt wird aber nur die Inhaltsbox — sichtbar
   bleibt ein 26px-Quadrat. Die 9px Polsterung ringsum sind klickbar, aber unsichtbar.
   Gefuellt statt nur umrandet, weil der Schleier genau hier, in der Ecke, schon
   fast durchsichtig ist: eine Flaeche traegt sich selbst, eine Kontur nicht.
   Radius 0 — die Formregel ganz oben sagt fuer Buttons hart, und ein Quadrat ist
   hier ausdruecklich gewuenscht.
   right/bottom auf -9px: das SICHTBARE Quadrat soll ohne Abstand in der Ecke
   sitzen. Weil die 9px Polsterung ringsum unsichtbar sind, muss die 44px-Box
   um genau diese 9px ueber die Kante hinausragen — sonst bliebe optisch ein
   Rand. Die Box laeuft dabei in den Gutter, nicht ueber den Bildschirm. */
.quote-toggle{position:absolute;right:-9px;bottom:-9px;display:flex;align-items:center;justify-content:center;
  width:44px;height:44px;padding:9px;border:0;border-radius:var(--radius-0);
  background:var(--red-500);background-clip:content-box;
  color:var(--paper);cursor:pointer;
  /* color gehoert MIT in die Liste: die Handy-Fassung faerbt beim Druck den Glyph
     statt der Flaeche (siehe .quote-toggle-spur:active). Ohne das sprang dort die
     einzige Rueckmeldung hart, waehrend alles andere auf der Seite blendet. */
  transition:background-color var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out)}
/* Pause = zwei Balken aus Raendern, Play = ein Dreieck aus Raendern. currentColor
   sorgt dafuer, dass beide Formen die Textfarbe mitnehmen. */
.quote-toggle-glyph{display:block;width:8px;height:11px;
  border-left:3px solid currentColor;border-right:3px solid currentColor}
.quote-toggle[aria-pressed="true"] .quote-toggle-glyph{width:0;height:0;border:none;
  border-left:10px solid currentColor;border-top:6px solid transparent;border-bottom:6px solid transparent;margin-left:2px}
/* base.css:32 setzt global box-shadow:var(--ring) — Rot auf Rot verschwindet,
   deshalb hier ein heller Ring direkt am sichtbaren Quadrat statt an der
   unsichtbaren 44px-Box. */
.quote-toggle:focus-visible{outline:none;box-shadow:none}
.quote-toggle:focus-visible .quote-toggle-glyph{outline:2px solid var(--paper);outline-offset:9px}
.quote-toggle:active{background-color:var(--accent-press)}
.quote-nav{display:none}
/* Reduced motion: Zitat wechselt hart statt zu faden, das Karussell springt
   statt zu gleiten (das JS setzt dafuer behavior:auto). Die Rotation selbst
   laeuft weiter — ein Textwechsel alle 7,5s ist keine Bewegung. */
/* Die Positionsstriche gab es bisher nur unter 900px. Ueber 900px rotierten
   vierzehn Zitate alle 7,5s voellig blind — 105 Sekunden fuer einen Durchlauf,
   ohne Zaehler, ohne Anhaltspunkt. Die bessere Fassung lag im DOM und war nur
   abgeschaltet. Rechtsbuendig unter die Quellenzeile, damit sie die
   Zitatachse nicht bricht. */
@media (min-width:901px){
  .quote-nav{display:flex;justify-content:flex-end;align-items:center;gap:10px;margin-top:10px}
  .quote-dots{display:flex;align-items:center;gap:4px}
  .quote-dot{display:block;width:14px;height:2px;background:rgba(243,239,232,.32);
    transform:scaleX(.5);transform-origin:left center;
    transition:background var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out)}
  .quote-dot.is-on{transform:scaleX(1);background:var(--paper)}
  /* Der Eckknopf am Desktop bleibt der Pausenknopf; die Striche daneben sind
     rein visuell (der Container traegt aria-hidden). */
  .quote-nav .quote-toggle{display:none}
}
@media (prefers-reduced-motion: reduce){.hero-quote{transition:none}.hero-quote.is-fading{opacity:1}
  .quote-toggle,.quote-dot{transition:none}}
.hero-name{font-family:var(--font-poster);font-weight:var(--fw-regular);text-transform:uppercase;font-size:clamp(52px,8.8vw,120px);line-height:.86;letter-spacing:.005em;color:#fff;margin:14px 0 0}
/* „SONNEBORN" als rot hingewischter Marker-Block: gleichmäßig um die Versalien,
   leicht schräg (Stempel-Motiv) mit organisch gerundeten Enden für Dynamik. */
.hero-name .red{display:inline-block;color:#fff;
  background:linear-gradient(var(--red-500),var(--red-500)) left center / 100% 100% no-repeat;
  padding:.14em .2em .1em;margin-top:.1em;line-height:.7;
  border-radius:8px 16px 9px 15px;transform:rotate(-1.8deg);transform-origin:left center;
  box-shadow:5px 6px 0 rgba(20,18,16,.32)}
/* Marker-Animation: das Rot wischt beim Laden von links ein. */
@media (prefers-reduced-motion: no-preference){
  .hero-name .red{background-size:0% 100%;animation:marker-swipe .75s var(--ease-out) .35s both}
}
@keyframes marker-swipe{from{background-size:0% 100%}to{background-size:100% 100%}}
.hero-lead{font:var(--fw-regular) clamp(17px,2.4vw,21px)/1.55 var(--font-serif);color:var(--text-on-dark);max-width:480px;margin:16px 0 0}
/* Der naechste Termin ueber der Falz. Kickergroesse, damit er den Lead nicht
   bedraengt — er ist ein Fakt, keine Ueberschrift. */
.hero-next{font:var(--fw-bold) 12px/1.3 var(--font-sans);text-transform:uppercase;letter-spacing:var(--ls-caps);
  color:rgba(243,239,232,.92);margin:16px 0 0}
.hero-next[hidden]{display:none}
.hero-cta{display:flex;flex-wrap:wrap;gap:14px;margin-top:22px}
.btn-cta{display:inline-flex;align-items:center;gap:10px;background:var(--red-500);color:#fff;font:var(--fw-black) 15px/1 var(--font-sans);
  text-transform:uppercase;letter-spacing:.04em;padding:18px 28px;box-shadow:6px 6px 0 rgba(246,243,236,.9);
  transition:transform var(--dur-fast) var(--ease-out),background var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out)}
/* box-shadow bewusst in der Transition: der Offset-Block muss 6px→3px zusammen-
   gehen, WÄHREND der Button 3px vorrückt — sonst zerfällt die Screenprint-Illusion
   in ein bloßes Verschieben. Einzige Ausnahme von „nur transform/opacity". */
/* Zweitknopf auf Kontur. Zwei gefuellte Knoepfe nebeneinander sind kein
   Primaer — dieselbe Ueberlegung wie bei .is-next in der Terminliste. Der
   Schlagschatten bleibt, sonst faellt der Knopf aus dem Siebdruck-Idiom. */
.btn-cta--zweit{background:transparent;color:#fff;box-shadow:6px 6px 0 rgba(246,243,236,.28),inset 0 0 0 2px rgba(246,243,236,.92)}
.btn-cta--zweit:active{background:rgba(246,243,236,.14);box-shadow:3px 3px 0 rgba(246,243,236,.28),inset 0 0 0 2px rgba(246,243,236,.92)}
.btn-cta:active{transform:translate(3px,3px);box-shadow:3px 3px 0 rgba(246,243,236,.9);background:var(--accent-press)}
@media (prefers-reduced-motion:reduce){.btn-cta:active{transform:translate(1px,1px);box-shadow:5px 5px 0 rgba(246,243,236,.9)}}
/* Ohne diese Zeile würde der Fokusring durch die neue box-shadow-Transition
   einblenden statt zu erscheinen. Ring schaltet hart AN, blendet beim Blur aus. */
.btn-cta:focus-visible{transition:transform var(--dur-fast) var(--ease-out),background var(--dur-fast) var(--ease-out)}
/* MUSS HINTER der Basisregel stehen: Media Queries erhoehen die Spezifitaet
   NICHT. Dieser Block stand zuerst davor und wurde von .btn-cta (gleiche
   Spezifitaet, spaeter im Blatt) restlos ueberschrieben — die Knoepfe
   behielten ihre vollen 145+137px und der zweite lief bei 320px bis x=320,
   sein Schlagschatten aus dem Fenster. Dieselbe Falle, die diese Datei beim
   Megafon und im reduced-motion-Endblock schon dokumentiert.
   Unter 344px passten die beiden Knoepfe (145 + 14 + 137 = 296px) nicht mehr in
   die 272px-Spalte. Die Reihe brach um, der zweite Knopf rutschte 65px tiefer —
   genau in die Zone, die .hero-social mit bottom:38px und z-index:3 besetzt.
   Gemessen bei 320px: "BUECHER" y 593-644, X-Icon y 627-671, 17px Ueberlappung;
   elementFromPoint in der unteren Knopfhaelfte lieferte den Twitter-Link. Der
   Knopf tat also etwas anderes, als er sagte.
   Statt die Kollision zu verschieben, wird der Umbruch verhindert: kompaktere
   Knoepfe ergeben 2 x 118 + 14 = 250px und passen. 44px Mindesthoehe bleibt. */
@media (max-width:380px){
  .hero-cta{flex-wrap:nowrap}
  /* nowrap auch INNEN: ohne das brach der Pfeil auf eine zweite Zeile und die
     Knoepfe wurden doppelt so hoch — der Umbruch war nur nach aussen verhindert. */
  .btn-cta{padding:15px 14px;font-size:13px;gap:6px;min-height:44px;box-sizing:border-box;white-space:nowrap}
}

/* ---------- EU BAND (compact, sticky under the header) ---------- */
.eu{position:sticky;top:87px;z-index:40;display:block;background:var(--red-500);color:#fff;text-decoration:none;
  box-shadow:0 8px 20px rgba(20,18,16,.16);transition:background var(--dur-fast) var(--ease-out)}
.eu:hover{text-decoration:none}
/* Nur Farbe, bewusst kein Transform: .eu ist sticky und dockt unter dem Header —
   einen angehefteten Vollbreiten-Balken unter dem Finger zu verschieben, kämpft
   gegen den Scroll. background liegt bereits in der Transition oben. */
.eu:active{background:var(--accent-press)}
.eu .wrap{display:flex;align-items:center;justify-content:space-between;gap:28px;padding:clamp(24px,3vw,36px) var(--gutter)}
.eu-kicker{font:var(--fw-bold) 12px/1.2 var(--font-sans);text-transform:uppercase;letter-spacing:.16em;color:rgba(255,255,255,.85);margin:0 0 5px}
.eu-title{font-family:var(--font-poster);font-weight:var(--fw-regular);text-transform:uppercase;font-size:clamp(24px,3.4vw,40px);line-height:1;margin:0}
.eu-arrow-inline{display:inline-block;margin-left:.1em;transition:transform var(--dur-base) var(--ease-out)}
.eu-nobreak{white-space:nowrap}
/* Nennt das Ziel des Bandes. Gepinnt faellt sie zusammen mit dem Kicker weg
   (s.u.) — dort traegt das » im Titel das Signal allein. */
.eu-extern{font:var(--fw-medium) 11.5px/1.3 var(--font-sans);color:rgba(255,255,255,.78);
  letter-spacing:.04em;margin:6px 0 0}
/* ---------- BAND IM GEPINNTEN ZUSTAND ----------
   Ungeschrumpft belegten Header und Band zusammen 218px von 900 (24%) bzw.
   202px von 812 (25%) — dauerhaft, ueber einen Scrollweg von 3.100 bis 4.100px.
   Man las die Terminliste durch einen Schlitz, waehrend ein Banner, das man
   bereits abgelehnt hatte, ein Viertel des Glases hielt.
   Gepinnt wechselt das Band deshalb auf position:fixed und wird flach: Kicker
   raus, Titel auf 20px, einzeilig. Der Platzhalter darunter uebernimmt im
   selben Moment die urspruengliche Hoehe — das Band verlaesst den Fluss (minus
   H) und der Platzhalter tritt ein (plus H), macht netto null. Ohne ihn
   spraenge der gesamte Inhalt darunter um die Bandhoehe nach oben. */
.eu-spacer{height:0}
body.eu-pinned .eu{position:fixed;top:87px;left:0;right:0}
body.eu-pinned .eu .wrap{padding:0 var(--gutter);height:var(--eu-pinned-h)}
body.eu-pinned .eu-kicker,
body.eu-pinned .eu-extern{display:none}
body.eu-pinned .eu-title{font-size:20px}

/* Spielerei: Megafon-Cut-out wächst aus der Band-Unterkante in den Header,
   sobald der Hero rausgescrollt ist (Höhe/Top per JS, über dem Header). */
/* AUFTRITT UND ABGANG SIND VERSCHIEDEN, und das ist der ganze Punkt.
   Auftritt: waechst in 550ms aus der Bandunterkante — das ist der Gag.
   Abgang: blendet in 220ms weg. Frueher schrumpfte es zurueck, und weil das Band
   im selben Moment von 56 auf 131px aufklappt, loeste sich das Megafon dabei
   sichtbar von der Unterkante und hing kurz frei in der Luft, bevor es
   verschwand. Ausblenden hat dieses Problem nicht.
   Der Kniff fuer zwei verschiedene Wege: `transform` bekommt auf der RUHE-Regel
   eine Dauer von 0s mit 220ms VERZOEGERUNG. Beim Abgang laeuft also erst die
   Blende durch, und erst wenn nichts mehr zu sehen ist, springt die Skalierung
   zurueck auf 0 — bereit fuer den naechsten Auftritt. */
.band-cutout{position:fixed;z-index:55;right:19%;height:0;width:auto;pointer-events:none;
  transform:scale(0);transform-origin:center bottom;opacity:0;
  filter:drop-shadow(0 12px 20px rgba(20,18,16,.4));
  transition:opacity var(--dur-gag-out) var(--ease-out),transform 0s linear var(--dur-gag-out)}
body.show-bandcutout .band-cutout{transform:scale(1);opacity:1;
  transition:transform var(--dur-gag-in) var(--ease-out),opacity var(--dur-base) var(--ease-out)}
/* ---------- Handy-Fassung: klein oben rechts IM HEADER ----------
   Unter 700px gibt es das Wachsen aus dem Band nicht mehr — der Fuss braeuchte
   ein Band, das hoeher ist als das Totband der Beobachter. Stattdessen faehrt
   das Megafon hier von oben in die Header-Ecke ein, ausgeloest vom selben
   Signal. Hoehe UND top setzt das JS, sodass die Fuesse exakt auf der
   Unterkante des Headers stehen; der Wert hier ist nur der Rueckfall.
   right haengt am Gutter, damit es mit dem Header-Inhalt fluchtet. */
@media (max-width:700px){
  /* calc statt Prozent: -135% liessen die Unterkante bei -14px liegen, der
     Schlagschatten reicht aber 5px nach unten plus 10px Weichzeichnung — auf dem
     iPhone stand deshalb ein grauer Streifen am oberen Rand, bevor sich
     ueberhaupt etwas bewegte. -100% minus 60px setzt die Unterkante auf -48px,
     der Schatten endet bei -33px. Der Wert haengt nicht mehr an der Bildhoehe. */
  /* Breite gedeckelt, damit der Trichter nicht auf die Wortmarke laeuft:
     bei 320px endete .brand bei x=231 und das Cut-out begann bei x=197, also
     34px Ueberlappung auf z-index 55 gegen 50 — die Marke las sich als
     "MARTIN SONNEBOR". --band-cutout-max setzt das Skript aus dem gemessenen
     Abstand zur Wortmarke (site.js), analog zum Desktop-Zweig, der den
     Nachbarn schon immer gemessen statt geraten hat. */
  .band-cutout{top:12px;right:var(--gutter);max-width:var(--band-cutout-max, 40vw);
    transform:translateY(calc(-100% - 60px));transform-origin:center top;
    filter:drop-shadow(0 5px 10px rgba(20,18,16,.45))}
  /* Gleiche Aufteilung wie am Desktop: einfahren, ausblenden. Die verzoegerte
     transform-Regel steht schon oben und gilt hier mit. */
  body.show-bandcutout .band-cutout{transform:translateY(0);opacity:1;
    transition:transform var(--dur-gag-in) var(--ease-out),opacity var(--dur-base) var(--ease-out)}
}
/* SPEZIFITÄTSFALLE, doppelt: `body.show-bandcutout .band-cutout` ist (0,2,1),
   `.band-cutout` nur (0,1,0), und Media Queries erhöhen die Spezifität NICHT.
   Daraus folgen zwei Pflichten. Erstens müssen hier beide Selektoren stehen,
   sonst bekäme der gedrückte Zustand still das volle Wachsen zurück. Zweitens
   muss dieser Block HINTER der Handy-Fassung stehen — stünde er davor, gäbe die
   Handy-Regel bei gleicher Spezifität die Bewegung wieder frei.
   transform:none ist für beide Fassungen der Ruhezustand (scale(1) bzw.
   translateY(0)), deshalb genügt eine Regel für beide. */
@media (prefers-reduced-motion:reduce){
  .band-cutout{transform:none;opacity:0;transition:opacity var(--dur-fast) var(--ease-out)}
  body.show-bandcutout .band-cutout{transform:none;opacity:1;transition:opacity var(--dur-slow) var(--ease-out)}
}

/* ---------- TERMINE ---------- */
.termine{scroll-margin-top:200px}
.termine .wrap{padding:clamp(56px,7vw,88px) var(--gutter)}
.termine-kicker{font:var(--fw-bold) 13px/1.3 var(--font-sans);text-transform:uppercase;letter-spacing:.18em;color:var(--red-500);margin:0}
.termine-title{font-family:var(--font-poster);font-weight:var(--fw-regular);text-transform:uppercase;font-size:clamp(40px,6vw,64px);line-height:.95;color:var(--ink-900);margin:8px 0 20px}
.termine-filter{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 22px}
.filter-chip{font:var(--fw-bold) 12px/1 var(--font-sans);text-transform:uppercase;letter-spacing:.06em;color:var(--ink-700);
  /* --ink-300 auf --paper ergab 1,51:1. WCAG 1.4.11 verlangt 3:1 fuer die
     Begrenzung eines Bedienelements — die drei inaktiven Chips lasen sich
     als freistehender Text, nicht als Knoepfe. --ink-500 liefert 3,17:1
     und bleibt zurueckhaltend genug, dass der aktive rote Chip fuehrt. */
  background:transparent;border:1.5px solid var(--ink-500);border-radius:var(--radius-pill);padding:0 16px;min-height:44px;cursor:pointer;
  transition:background var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out),transform var(--dur-fast) var(--ease-out)}
.filter-chip.is-active{background:var(--red-500);border-color:var(--red-500);color:#fff}
/* Nur translateY: der Chip hat keinen Offset-Block, in den er diagonal hinein-
   rücken könnte, und ein Scale würde seine 1.5px-Border ins Subpixel schieben. */
.filter-chip:active{transform:translateY(2px);border-color:var(--accent-press);color:var(--accent-press)}
/* PFLICHT, nicht Kür: .filter-chip:active und .filter-chip.is-active sind beide
   (0,2,0). Ohne diese (0,3,0)-Regel malte der Press dunkelrote Schrift auf die
   rote Fläche des aktiven Chips. */
.filter-chip.is-active:active{background:var(--accent-press);border-color:var(--accent-press);color:#fff}
@media (prefers-reduced-motion:reduce){.filter-chip:active{transform:translateY(1px)}}
/* Doppelring, weil der aktive Chip selbst rot ist (roter Ring darauf = 1,00:1). */
.filter-chip:focus-visible{outline:none;box-shadow:0 0 0 2px var(--paper),0 0 0 5px rgba(152,20,54,.85)}
.termine-list{list-style:none;margin:0;padding:0;border-top:3px solid var(--ink-900)}
.termin{display:grid;grid-template-columns:78px 1fr auto;align-items:center;gap:22px;padding:13px 6px;border-bottom:1px solid var(--ink-200)}
.termin[hidden]{display:none}
/* Filter-Umschalten, Teil 1: die Zeilen blenden, statt zu springen.
   Takt und Kurve sind NICHT die des Chips — der quittiert in --dur-fast
   (110ms), die Liste laeuft in --dur-filter (170ms) mit eigener Kurve. Hier
   stand frueher das Gegenteil; das galt, solange beide an --dur-fast hingen,
   und war nach der Entkopplung ein Kommentar, der in die Irre fuehrt.
   .motion-ready haengt das Skript erst NACH dem ersten apply() an die Liste —
   ohne diese Sperre zoege @starting-style beim Seitenaufbau alle dreizehn
   Zeilen einzeln ein, eine Ladeanimation, die niemand bestellt hat.
   display:none oben BLEIBT stehen: Browser ohne allow-discrete ignorieren die
   Transition und bekommen exakt das heutige Verhalten, den harten Schnitt. */
.termine-list.motion-ready .termin{opacity:1;transform:none;
  /* transform:none, NICHT translateY(0): beide rechnen zur Identitaet, aber
     `none` ist auch der Wert VOR dem Anhaengen von .motion-ready. Mit
     translateY(0) startete das Setzen der Klasse dreizehn Transitionen ueber
     null Distanz — unsichtbar, aber tote Bewegung. */
  transition:opacity var(--dur-filter) var(--ease-filter),
             transform var(--dur-filter) var(--ease-filter),
             display var(--dur-filter) var(--ease-filter) allow-discrete;
  /* Der Staffel-Vorlauf steht bewusst NUR hier, in der sichtbaren Zielregel.
     Eine Transition liest ihre Zeiten am ZIEL-Zustand: eintretende Zeilen
     landen auf dieser Regel und staffeln, austretende landen auf der
     [hidden]-Regel darunter und gehen dort ohne Vorlauf. Ein Verzoegern des
     Abgangs waere nur Zaehigkeit — verschwinden soll sofort passieren. */
  transition-delay:calc(var(--stagger-filter) * var(--i, 0))}
.termine-list.motion-ready .termin[hidden]{opacity:0;transform:translateY(calc(-1 * var(--shift-filter)));
  transition-delay:0s}
@starting-style{
  .termine-list.motion-ready .termin{opacity:0;transform:translateY(calc(-1 * var(--shift-filter)))}
}
.termin-date{display:flex;flex-direction:column;line-height:1;font-variant-numeric:tabular-nums}
.termin-day{font:var(--fw-black) 24px/1 var(--font-sans);color:var(--red-600);
  /* Filter-Umschalten, Teil 2: beim Filtern wandert .is-next auf eine andere
     Zeile. Der Tickets-Knopf blendet dabei laengst um (s.u.), die Ziffer sprang
     hart — dieselbe Zustandsaenderung, halb animiert. Reine Farbe, deshalb
     bewusst NICHT im reduced-motion-Endblock. */
  transition:color var(--dur-filter) var(--ease-filter)}
.termin-mon{font:var(--fw-bold) 12px/1 var(--font-sans);text-transform:uppercase;letter-spacing:.1em;color:var(--ink-700);margin-top:4px}
.termin-year{font:var(--fw-medium) 11px/1 var(--font-sans);color:var(--ink-600);margin-top:3px}
.termin-main{min-width:0}
.termin-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:10px}
/* Einheitlich: bricht IRGENDEINE Kategorie unter den Ort um (zu schmal),
   werden via JS ALLE Kategorien unter den Ort gestellt (Klasse cats-stacked). */
.termine-list.cats-stacked .termin-head{flex-direction:column;align-items:flex-start;gap:6px}
.termin-place{font:var(--fw-bold) clamp(17px,2vw,20px)/1.2 var(--font-sans);color:var(--ink-900)}
.termin-sub{font:var(--fw-regular) 14px/1.35 var(--font-sans);color:var(--ink-600);margin-top:3px}
/* category chip — brand black / white / red, one style per programme */
.termin-cat{display:inline-block;max-width:100%;font:var(--fw-bold) 11.5px/1.25 var(--font-sans);text-transform:uppercase;letter-spacing:.08em;
  border:1.5px solid transparent;border-radius:var(--radius-pill);padding:4px 11px;transform:translateY(-1px)}
.termin-cat--solo{background:var(--red-500);color:#fff;border-color:var(--red-500)}
.termin-cat--boygroup{background:transparent;color:var(--red-600);border-color:var(--red-300)}
.termin-cat--gysi{background:var(--ink-900);color:#fff;border-color:var(--ink-900)}
/* [hidden] allein genuegt nicht: .termin-cat setzt display:inline-block und
   schlaegt bei gleicher Spezifitaet die UA-Regel. */
.termin-cat[hidden]{display:none}
/* Filter-Umschalten, Teil 3: in den Zeilen, die STEHEN BLEIBEN, verschwand die
   Pille schlagartig. Nur Deckkraft, kein Versatz — die Pille sitzt in der Zeile,
   die sich unter Teil 1 ohnehin schon bewegt; zwei Bewegungen uebereinander
   waeren eine zu viel. display:none oben ist auch hier der Fallback. */
.termine-list.motion-ready .termin-cat{opacity:1;
  transition:opacity var(--dur-filter) var(--ease-filter),
             display var(--dur-filter) var(--ease-filter) allow-discrete}
.termine-list.motion-ready .termin-cat[hidden]{opacity:0}
@starting-style{
  .termine-list.motion-ready .termin-cat{opacity:0}
}
/* ---------- MONATSBALKEN ----------
   Leichte Abgrenzung, kein Kapitelkopf: eine schmale rote Leiste mit Monat und
   Jahr. Sie kostet 25px je Gruppe — das kompakte Zeilenlayout darunter bleibt
   unangetastet. Die Balken baut das JS aus den vorhandenen data-date-Attributen
   und blendet sie aus, wenn der aktive Filter in dem Monat nichts uebriglaesst. */
.termin-monat{display:block;margin:0;padding:5px 10px;background:var(--red-500);color:#fff;
  font:var(--fw-bold) 12px/1.3 var(--font-sans);text-transform:uppercase;letter-spacing:.14em;
  border-radius:var(--radius-0)}
.termin-monat[hidden]{display:none}
/* Der erste Balken sitzt direkt unter der 3px-Oberkante der Liste — dort waere
   die Doppelkante zu schwer, deshalb dort kein zusaetzlicher Abstand.
   Hier stand :not(:first-child). Das zaehlt die DOM-Position, nicht die
   Sichtbarkeit: sobald ein Filter den September-Balken ausblendet, war der
   dann oberste Balken (Dezember bei "Gysi") nicht mehr :first-child und bekam
   10px — der Abstand unter dem schwarzen Strich hing also am aktiven Filter.
   Welcher Balken oben steht, weiss nur apply(); die Klasse kommt von dort. */
.termine-list > .termin-monat + .termin{border-top:0}
.termine-list > .termin-monat{margin-top:10px}
.termine-list > .termin-monat.is-first-visible{margin-top:0}
/* Filter-Umschalten, Teil 4: die Balken waren bis 2026-09-03 von der Blende
   AUSGENOMMEN — die Regel oben trifft .termin, nicht .termin-monat. Beim
   Filtern verschwanden deshalb zuerst bis zu drei rote Balken schlagartig und
   die Liste sprang (gemessen 106px), bevor die Zeilen ueberhaupt anfingen zu
   blenden. Das lauteste Element der Liste ging als einziges ohne Uebergang.
   margin-top steht bewusst MIT in der Liste: beim Filtern wechselt
   is-first-visible auf einen anderen Balken, dessen Abstand also von 10px auf
   0 springt — dieselbe Zustandsaenderung, halb animiert, waere derselbe
   Fehler noch einmal. */
.termine-list.motion-ready > .termin-monat{opacity:1;transform:none;
  transition:opacity var(--dur-filter) var(--ease-filter),
             transform var(--dur-filter) var(--ease-filter),
             margin-top var(--dur-filter) var(--ease-filter),
             display var(--dur-filter) var(--ease-filter) allow-discrete}
.termine-list.motion-ready > .termin-monat[hidden]{opacity:0;transform:translateY(calc(-1 * var(--shift-filter)))}
@starting-style{
  .termine-list.motion-ready > .termin-monat{opacity:0;transform:translateY(calc(-1 * var(--shift-filter)))}
}
/* Ein Primaer statt dreizehn. Nur der naechste Termin traegt den gefuellten
   Knopf; die uebrigen zwoelf bleiben Kontur. Ohne das konkurrieren dreizehn
   gleich laute Ziele miteinander und keines gewinnt. */
.termin.is-next .termin-tickets{background:var(--red-500);color:#fff;border-color:var(--red-500)}
.termin.is-next .termin-day{color:var(--red-500)}
.termin-tickets{font:var(--fw-bold) 13px/1 var(--font-sans);text-transform:uppercase;letter-spacing:.06em;color:var(--red-600);
  border:2px solid var(--red-500);border-radius:var(--radius-0);padding:13px 18px;white-space:nowrap;min-height:44px;display:inline-flex;align-items:center;
  transition:background var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out),transform var(--dur-fast) var(--ease-out)}
/* Kein border-color im :active — es fehlt bewusst in der Transition oben und
   würde als Einziges hart umspringen. */
.termin-tickets:active{background:var(--accent-press);color:#fff;transform:translate(3px,3px)}
/* 2px, nicht 1px: der Hover steht bereits auf translate(2px,2px) ohne eigenen
   reduce-Override — bei 1px liefe der Press auf dem Desktop rückwärts. */
@media (prefers-reduced-motion:reduce){.termin-tickets:active{transform:translate(2px,2px)}}
.termine-empty{font:var(--text-column);color:var(--ink-700);padding:24px 6px}
/* Nur fuer Hilfstechnik sichtbar. Die Ansage des Filters darf keinen Platz
   belegen und keinen Fokus fangen; display:none waere falsch, das nimmt den
   Knoten aus dem Baum und eine Live-Region daraus sagt nichts mehr. */
.vh{position:absolute!important;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
  /* Versalien zuruecknehmen: der Zusatz im Entfernen-Knopf erbt sonst das
     text-transform des Knopfes. Sichtbar aendert das nichts (der Text ist ja
     versteckt), aber manche Screenreader buchstabieren durchgaengige Versalien
     Zeichen fuer Zeichen. */
  text-transform:none;letter-spacing:normal}

/* Sichtbarer Filterzustand in der Liste. Bewusst kein Chip-Rund: das hier ist
   kein Filterknopf, sondern eine Meldung mit Ausweg. */
/* Erklaerzeile ueber der Chip-Reihe. Sans wie der Rest der Sektion, eine Stufe
   unter dem Fliesstext, damit sie die Ueberschrift nicht bedraengt. Lesebreite
   gedeckelt: der Satz steht sonst quer ueber 1132px.
   Bewusst OHNE Uebergang beim Textwechsel — ein Kreuzblenden von Text braucht
   zwei Knoten und bringt hier nichts, was den Aufwand und die zusaetzliche
   reduced-motion-Gegenregel rechtfertigt. */
/* Ortsfilter neben den Programm-Chips. Natives select: Tastatur, Screenreader
   und Handy-Rad koennen es von Haus aus, und es kostet eine Zeile statt drei. */
.termine-ort{display:inline-flex;align-items:center;gap:8px;margin:0 0 18px}
/* Sichtbare Beschriftung statt nur .vh: Sehende lasen bisher allein "ALLE ORTE"
   im Steuerelement und mussten erraten, was es tut. */
.termine-ort-label{font:var(--fw-bold) 12px/1 var(--font-sans);text-transform:uppercase;
  letter-spacing:var(--ls-caps);color:var(--ink-600)}
.termine-ort-select{font:var(--fw-bold) 12px/1 var(--font-sans);text-transform:uppercase;letter-spacing:var(--ls-caps);
  color:var(--ink-700);background:transparent;border:1.5px solid var(--ink-500);border-radius:var(--radius-pill);
  padding:0 34px 0 16px;min-height:44px;cursor:pointer;appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-700) 50%),linear-gradient(135deg,var(--ink-700) 50%,transparent 50%);
  background-position:calc(100% - 18px) 50%,calc(100% - 13px) 50%;background-size:5px 5px,5px 5px;background-repeat:no-repeat}
.termine-ort-select:focus-visible{outline:none;box-shadow:0 0 0 2px var(--paper),0 0 0 5px rgba(152,20,54,.85)}

/* Zaehler und Stand. Die Zahl stand bisher nur in der Live-Region. */
.termine-meta{display:flex;flex-wrap:wrap;gap:4px 14px;font:var(--text-caption);color:var(--ink-600);margin:14px 0 0}
.termine-zaehler{font-weight:var(--fw-bold);color:var(--ink-800)}
/* Kurzmeldung nach dem Kalender-Export, sichtbar wie fuer Hilfstechnik. */
.termine-hinweis{color:var(--red-600);font-weight:var(--fw-bold)}
.termine-hinweis[hidden]{display:none}

/* Kalender-Export je Zeile. Kontur und kleiner als der Ticket-Knopf: er ist
   die Nebenhandlung, nicht die Konversion. */
/* Beide Aktionen in einer Zelle, damit das dreispaltige Grid der Zeile
   dreispaltig bleibt. Ein vierter direkter Nachkomme hatte den Tickets-Knopf in
   eine zweite Rasterzeile unter das Datum geschoben (Zeilenhoehe 147 statt 80). */
.termin-aktionen{display:flex;align-items:center;gap:8px;flex-wrap:nowrap}
.termin-ics{font:var(--fw-bold) 12px/1 var(--font-sans);text-transform:uppercase;letter-spacing:var(--ls-caps);
  /* --ink-300 auf Papier ergab 1,5:1. Der Rahmen traegt hier die Abgrenzung
     gegen den Nachbarknopf allein, WCAG 1.4.11 verlangt 3:1. */
  color:var(--ink-700);background:transparent;border:1.5px solid var(--ink-500);border-radius:var(--radius-0);
  padding:13px 12px;min-height:44px;white-space:nowrap;cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out)}
.termin-ics:focus-visible{outline:none;box-shadow:0 0 0 2px var(--paper),0 0 0 5px rgba(152,20,54,.85)}

/* Buchtitel unter dem Cover. Die Strings standen bisher nur im aria-label —
   fuer Screenreader da, fuer Sehende nicht. Die seltene Umkehrung. */
/* width:0 + min-width:100% ist der entscheidende Griff, nicht Kosmetik.
   .book ist ein Flex-Element mit flex:0 0 auto, seine Breite ist also die
   max-content-Breite des Inhalts. Der Titel brach deshalb GAR NICHT um und
   machte das Element breiter als sein Cover: gemessen 325px Element zu 165px
   Cover bei "99 Ideen...", 280 zu 146 bei "Gysi vs. Sonneborn". Der Gap steht
   zwar auf 24px, die sichtbaren Luecken zwischen den Covern waren dadurch
   67 / 73 / 184 / 158 / 24px.
   Prozentwerte bleiben bei der intrinsischen Breitenrechnung ausser Betracht:
   width:0 nimmt den Titel also aus der max-content-Rechnung heraus, danach
   spannt min-width:100% ihn auf die Breite, die das Cover vorgegeben hat, und
   dort bricht er um. */
.book-titel{display:block;font:var(--fw-bold) 13px/1.35 var(--font-sans);color:rgba(243,239,232,.92);
  margin-top:10px;width:0;min-width:100%;
  /* Platz fuer drei Zeilen reservieren, damit die Regalkante unter ALLEN
     Titeln denselben Abstand hat. Der laengste Titel braucht drei Zeilen; ein
     kuerzerer laesst den Rest leer, statt die Reihe zu verziehen. Ist ein
     Titel doch einmal laenger, bleibt die Reihe trotzdem bündig — dafuer
     sorgt flex-start oben, nicht diese Reserve. */
  min-height:calc(3 * 1.35em)}

.termine-programm{font:var(--fw-regular) 15px/1.55 var(--font-sans);color:var(--ink-700);
  max-width:62ch;margin:0 0 18px}

.termine-zustand{display:flex;align-items:center;flex-wrap:wrap;gap:8px 12px;margin:0 0 12px;
  font:var(--fw-bold) 12px/1 var(--font-sans);text-transform:uppercase;letter-spacing:.06em}
.termine-zustand[hidden]{display:none}
.termine-zustand-label{color:var(--ink-600)}
.termine-zustand-text{background:var(--ink-900);color:#fff;padding:6px 11px}
.termine-zustand-weg{font:inherit;text-transform:inherit;letter-spacing:inherit;
  background:transparent;border:1.5px solid var(--ink-500);border-radius:var(--radius-pill);
  color:var(--red-600);padding:7px 14px;min-height:36px;cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out)}
/* Leerzustand: Meldung und gezielter Ausweg nebeneinander. */
.termine-empty{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px}
/* PFLICHT, keine Kuer. Eine Autoren-display-Deklaration schlaegt die
   [hidden]-Regel des Browsers unabhaengig von der Spezifitaet — ohne diese
   Zeile stand die Leermeldung dauerhaft unter der vollen Terminliste und
   behauptete "Zur Zeit keine Termine", waehrend zwoelf danebenstanden.
   Dieselbe Falle wie bei .termin-cat, .termin[hidden] und .termin-monat[hidden];
   die Datei wendet die Gegenregel achtmal an, hier fehlte sie. */
.termine-empty[hidden]{display:none}
.termine-empty-weg{font:var(--fw-bold) 12px/1 var(--font-sans);text-transform:uppercase;letter-spacing:var(--ls-caps);
  background:transparent;border:1.5px solid var(--ink-500);border-radius:var(--radius-pill);
  color:var(--red-600);padding:7px 14px;min-height:44px;cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease-out)}
.termine-empty-weg[hidden]{display:none}
.termine-empty-weg:focus-visible{outline:none;box-shadow:0 0 0 2px var(--paper),0 0 0 5px rgba(152,20,54,.85)}
/* Gesperrte Orte: im aktiven Programm gibt es dort nichts. */
.termine-ort-select option:disabled{color:var(--ink-400)}

.termine-zustand-weg::before{content:"\00d7";margin-right:6px;font-size:15px;line-height:0}
.termine-zustand-weg:focus-visible{outline:none;box-shadow:0 0 0 2px var(--paper),0 0 0 5px rgba(152,20,54,.85)}

/* Buchungsanfragen. Stand vorher nur im Impressum. */
.termine-booking{font:var(--text-caption);color:var(--ink-700);margin:10px 0 0}
.termine-booking a{color:var(--red-600);border-bottom:1px solid var(--red-100)}
.extern-pfeil{display:inline-block;margin-left:.15em}
.termine-source{font:var(--text-caption);color:var(--ink-600);margin:24px 0 0}
.termine-source a{color:var(--red-600)}

/* ---------- BÜCHER (Karussell) ---------- */
.books{background:var(--black);scroll-margin-top:200px;scroll-padding-top:230px}
.books .wrap{padding:clamp(48px,6vw,80px) var(--gutter)}
.books-kicker{font:var(--fw-bold) 13px/1.3 var(--font-sans);text-transform:uppercase;letter-spacing:.18em;color:var(--red-on-dark);margin:0}
.books-title{font-family:var(--font-poster);font-weight:var(--fw-regular);text-transform:uppercase;font-size:clamp(40px,6vw,64px);line-height:.95;color:#fff;margin:18px 0 6px}
/* Echter Link (war ein <p>, sah aber aus wie die fuenf echten Links der Seite). */
.books-sub{display:inline-block;font:var(--fw-bold) 13px/1 var(--font-sans);text-transform:uppercase;letter-spacing:.06em;
  color:rgba(243,239,232,.75);margin:0 0 28px;padding-bottom:3px;border-bottom:1px solid var(--red-on-dark);
  transition:color var(--dur-fast) var(--ease-out)}
.books-viewport{position:relative}
/* dunkle Regal-Bühne: Cover stehen auf einer Regalkante */
/* overscroll-behavior-x:contain — ohne das kann ein Wisch zurück zum ersten Cover
   die Overscroll-Navigation auslösen und die Seite verlassen (Chrome Android
   braucht dafür nicht einmal einen Start am Rand). */
/* align-items war flex-end, weil die Cover frueher unmittelbar auf der
   Regalkante standen. Seit unter jedem Cover ein Titel haengt, zog das die
   Cover-Oberkanten auseinander: ein- bis dreizeilige Titel ergaben 35px
   Versatz. flex-start haelt sie bündig — alle Cover haben dieselbe Hoehe
   (clamp oben), also fluchten damit Ober- UND Unterkante. Die Titel haengen
   darunter wie Schilder an der Regalkante. */
.books-track{display:flex;align-items:flex-start;gap:24px;overflow-x:auto;scroll-snap-type:x proximity;scroll-behavior:smooth;overscroll-behavior-x:contain;list-style:none;margin:0;
  padding:14px 2px 0;border-bottom:2px solid rgba(243,239,232,.22);scrollbar-width:none}
/* html bekommt bei reduced-motion oben scroll-behavior:auto — .books-track deklariert
   sein smooth aber selbst und wäre sonst die einzige Motion, die die Präferenz ignoriert. */
@media (prefers-reduced-motion: reduce){.books-track{scroll-behavior:auto}}
.books-track::-webkit-scrollbar{display:none}
.book{flex:0 0 auto;scroll-snap-align:start}
.book a{display:block;text-decoration:none}
.book img{height:clamp(190px,25vw,250px);width:auto;display:block;border:1px solid rgba(243,239,232,.25);
  transition:transform var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out)}
/* Hover hebt das Cover vom Regal, der Press drückt es zurück. Steht bewusst VOR
   :focus-visible (beide (0,2,2), Quellreihenfolge entscheidet): so behält eine
   Tastaturaktivierung ihren Ring, ein Mausklick schlägt trotzdem den Hover. */
.book a:active img{transform:translate(-1px,-2px);box-shadow:4px 4px 0 var(--accent-press)}
/* Der Hover-Guard hier ist zwingend: auf Zeigergeräten startet der Press beim
   Hover-Wert (-3px,-5px), der Weg wird also kürzer — richtig. Ungegatet gälte er
   auch auf Touch, wo es keinen Hover gibt und der Weg WACHSEN würde. */
@media (prefers-reduced-motion:reduce) and (hover:hover) and (pointer:fine){
  .book a:active img{transform:translate(-2px,-3px)}
}
.book a:focus-visible img{outline:none;box-shadow:0 0 0 3px var(--paper)}
.books-nav{position:absolute;top:48%;transform:translateY(-50%);z-index:2;width:44px;height:44px;border-radius:var(--radius-circle);
  border:1.5px solid rgba(243,239,232,.35);background:var(--ink-900);color:#fff;font:var(--fw-bold) 22px/1 var(--font-sans);cursor:pointer;
  display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow-md);
  transition:opacity var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out)}
/* Statt inline-visibility (die hart wegblinkt und sich nicht überblenden lässt):
   echtes disabled. Blendet aus, sperrt Klick UND Enter ohne JS-Wächter und meldet
   den Zustand an Hilfstechnik. Kein Transform — der transform-Kanal trägt hier
   das statische translateY(-50%) zur Zentrierung. */
.books-nav[disabled]{opacity:0;pointer-events:none;cursor:default}
/* Die Pfeile waren die einzigen Bedienelemente der Seite ohne Druckzustand.
   Kein transform — der Kanal traegt hier das statische translateY(-50%) zur
   Zentrierung; stattdessen faerbt der Rahmen durch, wie bei .filter-chip. */
.books-nav:active{border-color:var(--red-on-dark);background:var(--accent-press)}
.books-nav--prev{left:-12px}
.books-nav--next{right:-12px}
@media (hover:none){.books-nav{display:none}}

/* ---------- FOOTER ---------- */
.site-footer{background:var(--black);color:rgba(243,239,232,.7)}
.site-footer .wrap{padding:40px var(--gutter)}
.footer-disclaimer{font:var(--text-caption);color:rgba(243,239,232,.6);max-width:680px;line-height:1.6;margin:0 0 22px}
.footer-bar{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:18px;padding-top:20px;border-top:1px solid rgba(243,239,232,.15)}
.footer-legal{font:var(--fw-medium) 13px/1.5 var(--font-sans)}
.footer-legal a{color:rgba(243,239,232,.95);border-bottom:1px solid var(--red-500)}
/* Die Regel muss auf das a greifen, nicht auf das nav: .social a (Zeile 109)
   setzt color direkt am a und schlaegt jede Vererbung. Hier stand die Farbe
   jahrelang am nav und hat deshalb NIE gewirkt — die sechs Icons standen auf
   var(--ink-700) ueber var(--black) = 1,62:1, gefordert sind 3:1 (WCAG 1.4.11).
   Der Hero-Klon (Zeile 180) hatte genau diese Falle bereits abgefangen, der
   Footer wurde uebersehen. Jetzt tragen alle drei Instanzen der Komponente
   ihre eigene Farbe: Header --ink-700 auf Papier (10,78:1), Hero-Klon und
   Footer hell auf dunkel (13,4:1 bzw. 8,5:1). */
.site-footer .social a{color:rgba(243,239,232,.8)}

/* ---------- FOKUSRING ----------
   Ein roter Ring auf rotem Band ergibt 1,00:1 — für Tastaturnutzer unsichtbar.
   Deshalb überall ein zweifarbiger Ring: heller Kern gegen dunkle/rote Flächen,
   roter Saum gegen das Papier. Einer der beiden hat immer Kontrast (>=3:1). */
a:focus-visible,.btn-cta:focus-visible{outline:none;
  box-shadow:0 0 0 3px var(--paper),0 0 0 6px rgba(152,20,54,.85)}
/* Auf den dunklen Flächen (EU-Band, Bücher, Footer) genügt der helle Ring allein —
   dort hat er 9,9:1 gegen Rot und wirkt ruhiger als der doppelte. */
.eu:focus-visible,.site-footer a:focus-visible,.books a:focus-visible{
  box-shadow:0 0 0 3px var(--paper)}

/* ---------- RESPONSIVE ---------- */
@media (max-width:900px){
  /* Mehr Hoehe auf dem Handy: der Zitatblock ist fuer das laengste Zitat
     reserviert (bis 233px) und schiebt Ueberschrift, Lead und Buttons weit
     nach unten. Ohne Zusatzhoehe bleibt unter den Buttons kein Platz fuer
     das Gesicht — und Text auf der Person ist ausgeschlossen. */
  /* Die Rechnung war unvollstaendig: abgezogen wurde nur der Header, nicht die
     eigene padding-top des Heros (clamp) und nicht seine 3px Unterkante. Der Hero
     lief dadurch 17px UNTER die Falz, obwohl der Kommentar oben „Header + Hero +
     Band = 100vh" behauptet — auf dem Desktop stimmt die Rechnung, hier nicht.
     Die 114 sind 87 Header + 3 Rahmen + 24 fuer einen sichtbaren Streifen des
     roten Bandes: er zeigt, dass darunter etwas kommt.
     Warum nicht das GANZE Band ueber die Falz holen: dafuer muesste der Hero auf
     610px, dann bleiben unter dem Text nur 159px, und das Gesicht liegt entweder
     hinter dem Lead oder ist auf eine Kopfhaut-Sichel beschnitten. Beides
     ausprobiert und verworfen — die Regel „Text liegt nie auf der Person" wiegt
     schwerer als ein vollstaendig sichtbares Band. */
  /* Der Untergrenzwert stand auf 620px. Zusammen mit Header (87) + Strich
     (3) + Abstand (14) ergibt das 724px — bei einem 720px hohen Fenster
     lag die Oberkante des roten Bandes damit 4px UNTER der Falz und der
     Streifen, der zeigen soll, dass darunter etwas kommt, war restlos
     weg. 596 + 87 + 3 + 14 = 700, der Streifen bleibt im Bild. */
  .hero-grid{grid-template-columns:1fr;align-items:start;min-height:max(596px, calc(100svh - 114px - clamp(14px,2.6vw,28px)));gap:0}
  .hero-text{align-self:start;padding:clamp(24px,6vw,40px) 0 0}
  /* Ausschnitt nachgezogen, nachdem der Zitatblock feste Hoehe bekam: staerker
     skaliert und vom oberen Rand aus, damit das Gesicht unter Lead und Buttons
     rutscht. Vorgabe: Text liegt nie auf der Person. */
  .hero-bg img{object-position:50% 0%;transform:scale(1.55);transform-origin:50% 0%}
  .hero::after{background:
    linear-gradient(180deg, rgba(20,18,16,.9) 0%, rgba(20,18,16,.72) 30%, rgba(20,18,16,.4) 52%, rgba(20,18,16,.16) 68%, rgba(20,18,16,0) 82%),
    linear-gradient(0deg, rgba(20,18,16,.72) 0%, rgba(20,18,16,0) 26%),
    linear-gradient(0deg, rgba(152,20,54,.34) 0%, rgba(152,20,54,0) 14%)}
  /* ---------- WISCHKARUSSELL ----------
     Volle Breite, kein eigener Schleier: der Hero-Verlauf darueber ist hier oben
     zu 90% deckend, ein zweiter Verlauf war nur eine graue Platte im Bild.
     Die Folien liegen in einer Flex-Zeile und rasten per scroll-snap ein — damit
     folgt das Wischen dem Finger nativ, mit Schwung und Gummiband, und die Spur
     ist automatisch so hoch wie die hoechste Folie. scroll-snap-stop:always
     verhindert, dass ein Schwung drei Zitate weiterspringt.
     touch-action:pan-x pan-y laesst das senkrechte Scrollen der Seite in Ruhe. */
  .hero-quote{position:static;max-width:none;margin:0 0 18px;text-align:center}
  .hero-quote.is-fading{opacity:1}          /* auf dem Handy wird gewischt, nicht geblendet */
  .hero-quote-track{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;
    overscroll-behavior-x:contain;touch-action:pan-x pan-y;
    scrollbar-width:none;-ms-overflow-style:none}
  .hero-quote-track::-webkit-scrollbar{display:none}
  /* padding-bottom haelt den Platz fuer die Steuerung frei, die weiter unten aus
     dem Fluss genommen und an den Fuss geheftet wird. position:relative macht
     die Folie zu deren Bezugsrahmen. */
  .hero-quote-slide{display:block;flex:0 0 100%;min-width:0;
    scroll-snap-align:center;scroll-snap-stop:always}
  .hero-quote-inner{display:block;padding:0;background:none}
  /* ZWISCHENLOESUNG, bis die Handy-Steuerung entschieden ist.
     Der Glyph steht hier bewusst auf einer eigenen, zentrierten Zeile. Die
     beiden naheliegenderen Wege scheitern beide an derselben Stelle — dass die
     Quelle hier zentriert und mehrzeilig sein darf:
       Textfluss (inline): folgt zwar huebsch dem letzten Wort, rutscht aber bei
         zwei der vierzehn Quellen auf eine eigene Zeile, sobald deren letzte
         Zeile die Breite fast ausfuellt (gemessen 27px tiefer). Die
         Umbruchstelle laesst sich nicht schliessen: ein atomarer Inline-Kasten
         bringt sie nach den Umbruchregeln selbst mit — Leerraum im Markup
         entfernen und geschuetztes Leerzeichen wurden geprueft, beides half nicht.
       Flex-Zeile: bricht konstruktiv nie um, haengt den Glyph aber an den Rand
         des Quellenkastens statt hinter das letzte Wort — gemessene Luecke bis
         zu 140px bei „Marie-Agnes Strack-Rheinmetall (FDP)".
     Eine eigene Zeile ist bei allen vierzehn gleich und sieht gewollt aus statt
     verrutscht. Kostet rund 14px Hoehe; die sind zurueckzuholen, sobald wir uns
     fuer eine endgueltige Steuerung entschieden haben. */
  .hero-quote-byline{display:block;text-align:center;margin-top:11px}
  /* Auf voller Breite darf die Quelle wieder umbrechen — nowrap ist eine
     Desktop-Vorgabe. hyphens:auto, weil „Victor Negrescu (Vizepraesident des
     Europaeischen Parlaments)" sonst laenger ist als jeder Handybildschirm. */
  .hero-quote-cite{white-space:normal;min-width:0;-webkit-hyphens:auto;hyphens:auto}
  /* Bedienleiste unter der Spur: Striche als Positionsanzeige plus das rote
     Quadrat als Steuerung. Der Knopf IN der Folie ist hier abgeschaltet — er
     wackelte mit der Zitatlaenge und beruehrte den Textumbruch. Die Leiste
     erfuellt WCAG 2.2.2 (Anhalten) und schliesst zugleich die Luecke, dass man
     im Karussell nicht sieht, an welcher von vierzehn Stellen man steht. */
  .hero-quote-slide .quote-toggle{display:none}
  .quote-nav{display:flex;align-items:center;justify-content:center;gap:12px;margin-top:12px}
  .quote-dots{display:flex;align-items:center;gap:4px}
  /* Striche, keine Punkte: der Rest der Seite kennt Haarlinien und harte Kanten,
     keine Kreise. Der aktive ist heller UND breiter — Farbe allein darf die
     Information nicht tragen (WCAG 1.4.1). */
  /* Der Strich waechst per transform, NICHT per width. Vorher lief hier
     eine Transition auf der Breite: das ist eine Layout-Eigenschaft, jeder Frame liess den
     Browser die Reihe aus vierzehn Geschwistern neu setzen. Feste Breite 16px,
     Ruhezustand auf scaleX(.5625) = 9px — optisch identisch, aber reine
     Compositor-Arbeit. transform-origin links, sonst waechst er nach beiden
     Seiten und die Reihe wirkt unruhig. */
  /* 16px feste Breite je Strich ist der Preis fuer transform statt width (der
     Ruhezustand skaliert auf 9px herunter, belegt aber weiter 16px Layout).
     14 x 16 + 13 x 4 = 276px plus Gap und 44px-Knopf = 332px — das liefe in
     einer 272px-Spalte 60px in den Gutter. Unter 400px daher schmaler:
     14 x 10 + 13 x 4 = 192px, mit Knopf 248px. Ueber 400px ist die Spalte
     mindestens 353px breit (401 - 2 x 24), die 332px passen also gerade
     noch; jede weitere Pressestimme kostet dort 20px. Siehe Regel unten. */
  .quote-dot{display:block;width:16px;height:2px;background:rgba(243,239,232,.32);
    transform:scaleX(.5625);transform-origin:left center;
    transition:background var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out)}
  .quote-dot.is-on{transform:scaleX(1);background:var(--paper)}
  /* Siehe Rechnung oben: unter 400px passt die Reihe sonst nicht in die Spalte. */
  @media (max-width:400px){ .quote-dot{width:10px} }
  /* Gleiche Marke wie der Eckknopf am Desktop: 26px rotes Quadrat, sichtbar
     ueber background-clip, 44px Trefferflaeche. Die negativen Raender halten
     den Layoutbeitrag der Zeile bei 18px. */
  /* Kein rotes Quadrat mehr: neben vierzehn hellen Haarstrichen wirkte der
     gefuellte Block wie ein Fremdkoerper. Der Knopf traegt jetzt denselben Ton
     wie der aktive Strich und gehoert damit sichtbar zur selben Gruppe. Die
     Trefferflaeche bleibt volle 44px, nur die Farbflaeche verschwindet.
     Der Glyph waechst leicht (10x13), damit er neben dem 16px-Strich nicht
     verloren wirkt. Am Desktop bleibt das rote Eckquadrat, wie es ist — dort
     sitzt es in einer Ecke und nicht in einer Reihe heller Striche. */
  .quote-toggle-spur{position:static;flex:0 0 auto;width:44px;height:44px;
    margin:-13px 0;padding:0;transform:none;background:none;color:var(--paper)}
  .quote-toggle-spur .quote-toggle-glyph{width:10px;height:13px}
  .quote-toggle-spur[aria-pressed="true"] .quote-toggle-glyph{width:0;height:0;
    border-left:12px solid currentColor;border-top:7px solid transparent;border-bottom:7px solid transparent}
  .quote-toggle-spur:active{background:none;color:rgba(243,239,232,.5)}
  .termin{grid-template-columns:62px 1fr;gap:14px;row-gap:8px;align-items:start}
  .termin-tickets{grid-column:2;justify-self:start;margin-top:2px}
}
/* ---------- KURZE VIEWPORTS: Text lag auf dem Gesicht ----------
   Ab hier greift min-height:620px statt 100svh-87px, der Hero wird also nicht
   mehr kuerzer, waehrend das Foto weiter mit scale(1.55) vom oberen Rand
   skaliert — das Gesicht wandert in den Lead. Gemessen bei 320x720: Zeile 3 auf
   2,56:1, Zeile 4 auf 2,25:1 gegen #f3efe8; gefordert sind 4,5:1. Das ist die
   Pruefbreite von WCAG 1.4.10 Reflow, also 400% Zoom auf einem 1280er Schirm.
   620 + 87 = 707, deshalb 720 als Grenze mit etwas Reserve.
   Der Schleier bleibt hier laenger deckend statt das Bild umzurechnen: das
   Foto behaelt seinen Ausschnitt, nur die Textzone wird dunkler gehalten. */
@media (max-width:900px) and (max-height:720px){
  .hero::after{background:
    linear-gradient(180deg, rgba(20,18,16,.93) 0%, rgba(20,18,16,.88) 38%, rgba(20,18,16,.74) 60%, rgba(20,18,16,.4) 78%, rgba(20,18,16,.1) 92%, rgba(20,18,16,0) 100%),
    linear-gradient(0deg, rgba(20,18,16,.78) 0%, rgba(20,18,16,0) 26%),
    linear-gradient(0deg, rgba(152,20,54,.34) 0%, rgba(152,20,54,0) 14%)}
}
@media (max-width:520px){
  .brand-name{font-size:18px}
  /* Stand auf 9,5px. Das ist die Markenzeile im klebenden Header, also
     dauerhaft im Bild, und lag unter jedem sinnvollen Boden fuer
     funktionalen Text. 11px ist der Boden; die Laufweite geht dafuer
     etwas zurueck, damit die Zeile in derselben Breite bleibt. */
  .brand-sub{font-size:11px;letter-spacing:.12em}
  /* Der Filterapparat kostete auf 375px 261px, bevor das erste Datum kam: drei
     umgebrochene Chip-Reihen plus Erklaerzeile. Eine waagerecht scrollende Reihe
     macht daraus eine Zeile. Das Muster kennt die Seite bereits zweimal
     (Zitatspur, Buecherregal), es ist also kein neues Vokabular.
     scroll-padding, damit der erste Chip nicht am Rand klebt. */
  /* Aktionen auf dem Handy in eine eigene volle Zeile: der ICS-Knopf hatte
     sonst die 62px-Datumsspalte geerbt und lief 28px ueber seine Rahmenkante. */
  .termin-aktionen{grid-column:1 / -1;justify-content:flex-start}
  .termine-filter{flex-wrap:nowrap;overflow-x:auto;scroll-snap-type:x proximity;
    scroll-padding-left:var(--gutter);scrollbar-width:none;overscroll-behavior-x:contain;
    margin-left:calc(-1 * var(--gutter));margin-right:calc(-1 * var(--gutter));
    padding-left:var(--gutter);padding-right:var(--gutter)}
  .termine-filter::-webkit-scrollbar{display:none}
  .filter-chip{flex:0 0 auto;scroll-snap-align:start}
  .social{gap:14px}
  .termin-cat{font-size:11px;letter-spacing:.05em}
}

/* ══════════════════════════════════════════════════════════════════════════
   REDUZIERTE BEWEGUNG — LETZTE INSTANZ
   Dieser Block steht bewusst ganz am Dateiende. Die Datei dokumentiert die
   Spezifitaetsfalle bereits zweimal beim Megafon, und sie hat trotzdem ein
   drittes Mal zugeschlagen: `.quote-dot{transition:none}` stand oben im
   reduced-motion-Block, die Mobil-Regel deklarierte die Transition 332 Zeilen
   spaeter bei gleicher Spezifitaet neu — und gewann. Die Striche animierten
   also trotz Systemeinstellung.
   Media Queries erhoehen die Spezifitaet NICHT. Wer weiter unten Bewegung
   deklariert, muss sie hier abschalten. Neue Bewegung also immer gegen diesen
   Block gegenpruefen.
   Was hier NICHT steht, ist Absicht: reine Farb- und Deckkraft-Uebergaenge
   bleiben. Reduzierte Bewegung heisst weniger und sanfter, nicht tot. */
@media (prefers-reduced-motion: reduce){
  /* 1) Die Positionsstriche unter dem Handy-Karussell. */
  .quote-dot{transition:none}
  /* 2) Der Pfeil im EU-Band faehrt beim Hover 7px nach rechts (site.css:65).
        Selektor und Spezifitaet muessen die Hover-Regel treffen: (0,3,0). */
  .eu:hover .eu-arrow-inline{transform:none}
  /* 3) Der Skip-Link faehrt beim Fokus 68px ein (top:-56px auf top:12px).
        Er erscheint jetzt sofort — sichtbar ist er dadurch genauso. */
  .skip-link{transition:none}
  /* 4) Filter-Umschalten: Termin-Zeilen (translateY + Deckkraft) und
        Kategorie-Pille (Deckkraft). Beide Deklarationen oben sind (0,3,0),
        diese Gegenregeln treffen dieselbe Spezifitaet und stehen dahinter.
        transition:none nimmt auch das display aus dem Uebergang — die Zeile
        verschwindet damit wieder hart, also exakt wie vor der Aenderung.
        Der Staffel-Vorlauf faellt hier mit weg: transition ist die Kurzform,
        sie setzt transition-delay auf 0s zurueck. Die Gegenregel muss also
        NICHT um ein eigenes transition-delay ergaenzt werden — aber wer die
        Kurzform hier je durch Einzeleigenschaften ersetzt, muss den Vorlauf
        von Hand mit abraeumen.
        Die @starting-style-Werte muessen mit zurueckgenommen werden: sonst
        setzte der Browser beim Wiedereinblenden weiter opacity:0 als
        Ausgangswert und die Zeile bliebe ohne Transition unsichtbar. */
  .termine-list.motion-ready .termin,
  .termine-list.motion-ready .termin-cat{transition:none}
  /* Teil 4, seit die Monatsbalken mitblenden. Der Selektor ist (0,3,0) wie
     die Deklaration oben und steht dahinter — Media Queries erhoehen die
     Spezifitaet nicht, das ist die in der Vorbemerkung beschriebene Falle. */
  .termine-list.motion-ready > .termin-monat{transition:none}
  @starting-style{
    .termine-list.motion-ready .termin{opacity:1;transform:none}
    .termine-list.motion-ready .termin-cat{opacity:1}
    .termine-list.motion-ready > .termin-monat{opacity:1;transform:none}
  }
  /* NICHT hier: die color-Transition der Tagesziffer (.termin-day). Reine
     Farbe, kein Versatz — siehe die Vorbemerkung oben. */
}
