Files
dogfather-universe/workspace/assets/css/reaktion.css
T
DogFatherGit dcd0298700 Spenden: vier Knoepfe, eine Karte im Bild -- und die Wahrheit ueber PayPal
Filipe: "ich will dass das richtig perfekt gemacht wird so dass die
leute so einfach wie moeglich eine spende aufs paypal machen koennen.
und wenn jemand spendet soll auch der betrag erscheinen mit einem
bild."

WAS GEHT UND WAS NICHT -- NACHGESEHEN, NICHT ANGENOMMEN

Hinterlegt ist ein PayPal.me-Link auf ein PRIVATES Konto. Daraus
folgt zweierlei, und beides bestimmt den ganzen Aufbau:

  ES GEHT: `paypal.me/<name>/5EUR` oeffnet PayPal mit schon
  eingetragenem Betrag. Ein Tipp, fertig. Belegt an PayPals eigener
  Hilfeseite zu PayPal.Me.

  ES GEHT NICHT VON SELBST: PayPal meldet eine Zahlung nur, wenn ein
  Webhook oder IPN eingerichtet ist -- beides braucht Zugangsdaten,
  die nur Filipe selbst anlegen kann. Ob ein PRIVATES Konto das
  ueberhaupt kann, sagt PayPals eigene Doku nicht eindeutig; ich habe
  es gesucht und nicht gefunden, und etwas zu behaupten, das ich
  nicht belegen kann, waere hier das Gefaehrlichste.

DESHALB DREI HERKUENFTE UND NICHT EINE

  "hand"      Filipe sieht die PayPal-Meldung auf dem Handy und tippt
              den Betrag ins Pult. Geht immer, braucht nichts, ist in
              drei Sekunden getan, und die Karte laeuft sofort.
  "gemeldet"  Der Zuschauer sagt nach dem Spenden selbst Bescheid.
              Landet als OFFEN und wird erst gezeigt, wenn die
              Leitung es bestaetigt.
  "paypal"    Kommt automatisch, sobald ein Webhook eingerichtet ist.
              Bis dahin steht dieser Weg leer da -- die Tabelle und
              die Sperre gegen doppelte Zahlungsnummern sind schon
              fertig.

WARUM EINE MELDUNG NICHT SOFORT ERSCHEINT: Sonst tippt irgendwer
"500 Euro" und steht damit gross im Bild. Eine Spende ist eine
Aussage ueber Geld; die gehoert bestaetigt, bevor sie oeffentlich
wird. Der Weg dahin ist EIN Tipp -- billig genug, dass niemand in
Versuchung kommt, ihn abzukuerzen. Beim Bestaetigen darf der Betrag
berichtigt werden: Die Leitung hat die PayPal-Meldung vor sich und
weiss es besser als die Behauptung.

FUER DIE ZUSCHAUER

Vier Betraege im Chat (2, 5, 10, 25 EUR) statt eines Links. Wer eine
Liste sieht, rechnet; wer vier Knoepfe sieht, tippt. Die Adresse wird
NICHT zweimal gepflegt -- sie steht auf der Unterstuetzen-Seite, und
von dort wird sie gelesen. Steht dort nichts oder ist der Weg auf
unsichtbar, gibt es hier auch keine Knoepfe. An einer Adresse, die
kein paypal.me ist, wird kein Betrag angehaengt: Er fuehrte sonst zu
einer Seite, auf der etwas anderes steht als auf dem Knopf.

DIE KARTE

Betrag gross, Name, Gruss, ein Bild dazu -- und eine Farbe, die von
der Stufe kommt. Drei Stufen ab Werk: Danke (ab 1), Starke Runde (ab
5), Rudel-Legende (ab 20), je mit eigener Vorlage, Farbe und Dauer.
Gilt immer die HOECHSTE, die noch passt; mit Ober- UND Untergrenze je
Stufe waere die doppelte Gelegenheit, eine Luecke zu lassen -- durch
die faellt dann ausgerechnet der grosse Betrag.

EINE NACH DER ANDEREN. Drei Spenden in zehn Sekunden sind keine
Seltenheit; uebereinander gelegt waere keine mehr lesbar, und
ausgerechnet die groesste ginge unter. Bei voller Schlange werden die
Zeiten gekuerzt, nicht die Karten weggeworfen -- wer gegeben hat,
soll es sehen.

DIE KARTE IST EIN EIGENES STUECK (spendenkarte.js/.css) und haengt an
nichts aus der Reaction. Dieselbe Karte laeuft spaeter als eigene
Seite fuer OBS und TikTok Studio; zweimal gebaut hiesse, sie sieht
nach der naechsten Aenderung an einem der beiden Orte anders aus --
und man merkt es erst im Livestream.

DER BETRAG STEHT IN CENT

Nie als Kommazahl. 0.1 + 0.2 ist in keiner Programmiersprache 0.3,
und bei Geld faellt das irgendwann jemandem auf -- meistens dem, der
zahlt. Formatiert wird erst auf dem Bildschirm.

DREI EIGENE FEHLER, VON DEN PRUEFUNGEN GEFUNDEN

1. Ein Weg aus einer Verzweigung: `/spenden/${id}/${ja ?
   "bestaetigen" : "ablehnen"}`. `pruef-struktur` hat das zu Recht
   beanstandet -- ein Tippfehler im selteneren Zweig faellt erst auf,
   wenn er mitten in einer Sendung gebraucht wird. Beide Wege stehen
   jetzt ausgeschrieben da.

2. "Genau 5 Register" -- zweimal am selben Tag dieselbe feste Zahl,
   in der Messung UND in der Pruefung. Beim sechsten Register wurden
   beide rot, obwohl nichts kaputt war. Jetzt wird gezaehlt: zu jedem
   Reiter gehoert eine Tafel, und keine steht ohne Reiter da.

3. Die Messung war zu ungeduldig: Die erste Karte laeuft elf
   Sekunden (die hoechste Stufe steht am laengsten), die zweite
   wartet in der Schlange -- richtig so. Die Messung wartete 1,6
   Sekunden und meldete "laeuft nicht". Jetzt wird auf das Merkmal
   gewartet, nicht auf die Uhr.

GEMESSEN

  mess-reaktion   4 Betragsknoepfe mit richtiger Adresse.
                  25 EUR von Hand -> Karte "Rudel-Legende" bei der
                  Zuschauerin. 500 EUR gemeldet -> steht NICHT im
                  Bild, wartet im Pult. Bestaetigt mit berichtigten
                  10 EUR -> Karte "Starke Runde". Stufe passt zum
                  Betrag, beide Male.
  pruef-spenden   46 Punkte, 0 Fehler (neu) -- darunter die
                  Gegenprobe, dass ohne Zahlungsnummer beliebig viele
                  Zeilen nebeneinander stehen duerfen (sonst liesse
                  sich nur EINE Spende von Hand eintragen).
  pruef-reaktion  154, unterstuetzung 70, aufbewahrung 45,
                  struktur 35, css-klassen 33, portnummern 15,
                  tippziele 11, ports 8, meldungen 8 -- alle 0 Fehler.

SCHEMA: zwei Tabellen (spenden, spenden_stufen) mit einem
Einmalig-Index auf die Zahlungsnummer. Auf einer Kopie der echten
Datenbank durchgespielt: 20 Personen, 227 Chatnachrichten, keine
Tabelle verliert eine Spalte.
2026-09-28 08:34:42 +02:00

1449 lines
49 KiB
CSS

/* =====================================================================
DIE REACTION (28.09.2026)
Diese Seite ist absichtlich anders gebaut als jede andere im Haus.
Überall sonst gilt: Kacheln, Karten, Listen -- man liest etwas,
entscheidet und geht wieder. Hier sitzt man. Eine Stunde lang, mit
anderen zusammen, und schaut auf EINE Sache.
Daraus folgen drei Entscheidungen, die sonst nirgends gelten:
1. DIE SEITE SCROLLT NICHT. Sie füllt genau den Bildschirm. Ein
Video, das beim Tippen im Chat nach oben rutscht, ist der
schnellste Weg, dass jemand aufhört zu schreiben.
2. DIE FLÄCHE IST DUNKLER ALS ÜBERALL SONST. Der Rest des Hauses
steht auf #07060f mit Licht in den Ecken; hier ist es fast
schwarz. Nicht als Stil, sondern weil daneben ein Video läuft:
Alles, was selbst leuchtet, zieht den Blick vom Bild weg.
3. DIE FARBE IST ROT -- und zwar nur hier und nur beim Senden.
Das Haus ist augenschonend gebaut, und Rot ist das Gegenteil
davon. Es ist aber kein Dauerzustand: ein bis zwei Stunden im
Monat, und in dieser Zeit SOLL es rufen. Gedeckt (#d8404a statt
reinem Rot), und was pulst, pulst in vier Sekunden -- das ist
Atmen und kein Blinken.
---------------------------------------------------------------------
DREI HÄUTE, EINE SEITE
`data-stand` am `.saal` schaltet um: zu / vorbereitung / live.
Alle drei stehen im Dokument. Beim Wechsel von „gleich" auf „live"
wird deshalb nichts neu geladen -- weder der Chat, in dem jemand
mitten im Satz ist, noch die Verbindung zur Kamera.
===================================================================== */
.reaktion-seite {
--saal: #050408;
--saal-hoch: #0b0a12;
--rand: rgba(150, 160, 190, .14);
--rand-hell: rgba(170, 180, 210, .26);
--schrift: #e9e6f2;
--schrift-leise: #a9a3bd;
--an: #d8404a;
--an-hell: #ff8b92;
--gleich: #e0a13a;
--zu: #8b93a4;
background: var(--saal);
/* Kein Scrollen: Der Saal ist so hoch wie das Fenster. `dvh` und
nicht `vh` -- auf dem Handy wandert die Adressleiste, und `vh`
rechnet mit dem Zustand von vorhin. */
min-height: 100dvh;
overflow: hidden;
}
.saal {
position: relative;
display: grid;
/* Die Kopfleiste ist 69 px hoch (gemessen, nicht geschätzt -- siehe
pruef-handy, das sie über alle Breiten abmisst). */
height: calc(100dvh - 69px);
padding: 0;
max-width: none;
}
/* ---------------------------------------------------------------------
DAS SCHILD
Oben mittig, in allen drei Zuständen. Es beantwortet die einzige
Frage, die jeder beim Öffnen hat: läuft schon was?
--------------------------------------------------------------------- */
.buehne-schild {
position: absolute;
top: 14px; left: 50%;
transform: translateX(-50%);
z-index: 40;
display: flex; align-items: center; gap: 9px;
padding: 7px 15px 8px;
border-radius: 999px;
background: rgba(8, 7, 14, .82);
border: 1px solid var(--rand);
backdrop-filter: blur(14px) saturate(1.2);
-webkit-backdrop-filter: blur(14px) saturate(1.2);
box-shadow: 0 16px 38px -18px #000;
font-size: .72rem; font-weight: 800;
letter-spacing: .14em; text-transform: uppercase;
color: var(--schrift-leise);
}
.buehne-schild__punkt {
width: 8px; height: 8px; border-radius: 50%;
background: var(--zu);
flex: none;
}
.buehne-schild__zahl {
padding-left: 9px;
border-left: 1px solid var(--rand);
color: var(--schrift);
letter-spacing: .06em;
}
.saal[data-stand="vorbereitung"] .buehne-schild {
border-color: color-mix(in srgb, var(--gleich) 40%, transparent);
color: color-mix(in srgb, var(--gleich) 30%, #ffffff);
}
.saal[data-stand="vorbereitung"] .buehne-schild__punkt { background: var(--gleich); }
.saal[data-stand="live"] .buehne-schild {
border-color: color-mix(in srgb, var(--an-hell) 50%, transparent);
color: #ffe9ea;
box-shadow: 0 0 30px -10px var(--an), 0 16px 38px -18px #000;
}
.saal[data-stand="live"] .buehne-schild__punkt {
background: var(--an);
box-shadow: 0 0 12px 1px var(--an);
animation: reakt-atem 4s ease-in-out infinite;
}
@keyframes reakt-atem {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: .5; transform: scale(.82); }
}
/* ---------------------------------------------------------------------
HÄUTE EIN- UND AUSBLENDEN
--------------------------------------------------------------------- */
#teil-zu, #teil-warte, #teil-live { display: none; }
.saal[data-stand="zu"] #teil-zu { display: grid; }
.saal[data-stand="vorbereitung"] #teil-warte { display: grid; }
.saal[data-stand="live"] #teil-live { display: grid; }
/* =====================================================================
ZU — der Vorhang
===================================================================== */
.vorhang {
position: relative;
place-items: center;
padding: 0 28px;
text-align: center;
}
.vorhang__licht {
position: absolute; inset: 0;
background:
radial-gradient(90% 55% at 50% 0%, rgba(120, 130, 165, .12), transparent 62%),
radial-gradient(120% 70% at 50% 104%, rgba(70, 80, 115, .10), transparent 60%);
pointer-events: none;
}
.vorhang__innen { position: relative; max-width: 30rem; }
.vorhang__marke {
display: flex; align-items: center; justify-content: center; gap: 10px;
font-size: .74rem; font-weight: 700;
letter-spacing: .38em; text-transform: uppercase;
color: var(--schrift-leise);
}
.vorhang__marke i {
display: block; width: 26px; height: 1px;
background: linear-gradient(90deg, transparent, var(--schrift-leise));
}
.vorhang__marke i + i { background: linear-gradient(90deg, var(--schrift-leise), transparent); }
.vorhang__titel {
margin: 16px 0 0;
font-size: clamp(1.9rem, 7vw, 2.7rem);
font-weight: 800; line-height: 1.08;
letter-spacing: -.024em;
color: var(--schrift);
text-wrap: balance;
}
.vorhang__satz {
margin: 14px 0 0;
font-size: .96rem; line-height: 1.6;
color: var(--schrift-leise);
text-wrap: pretty;
}
.vorhang__naechste {
margin: 22px 0 0;
display: inline-block;
padding: 9px 16px;
border-radius: 12px;
background: color-mix(in srgb, var(--gleich) 12%, transparent);
border: 1px solid color-mix(in srgb, var(--gleich) 30%, transparent);
color: color-mix(in srgb, var(--gleich) 24%, #ffffff);
font-size: .86rem; font-weight: 700;
}
/* =====================================================================
VORBEREITUNG — der Wartebereich
===================================================================== */
.warte { place-items: center; padding: 0 20px; }
.warte__buehne {
display: grid; gap: 26px;
width: min(54rem, 100%);
grid-template-columns: 1fr;
text-align: center;
}
.warte__bild {
aspect-ratio: 16 / 9;
border-radius: 20px;
background: linear-gradient(160deg, #131120, #08070e);
border: 1px solid var(--rand);
background-size: cover; background-position: center;
box-shadow: 0 40px 80px -46px #000;
}
.warte__kicker {
font-size: .74rem; font-weight: 800;
letter-spacing: .34em; text-transform: uppercase;
color: color-mix(in srgb, var(--gleich) 26%, #ffffff);
}
.warte__titel {
margin: 12px 0 0;
font-size: clamp(1.6rem, 6vw, 2.3rem);
font-weight: 800; line-height: 1.1;
letter-spacing: -.022em; color: var(--schrift);
text-wrap: balance;
}
.warte__satz { margin: 14px 0 0; color: var(--schrift-leise); font-size: .92rem; }
/* Was nach dem ersten Stück kommt. Eine Zeile, kein Programmheft --
der Abend soll nicht vorher im Netz stehen. */
.warte__danach {
margin: 12px 0 0;
display: inline-block;
padding: 6px 13px;
border-radius: 999px;
background: rgba(255, 255, 255, .05);
border: 1px solid var(--rand);
color: var(--schrift-leise);
font-size: .78rem;
max-width: 100%;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.countdown {
display: inline-flex; align-items: baseline; gap: 10px;
margin: 18px 0 0; padding: 10px 20px 12px;
border-radius: 16px;
background: color-mix(in srgb, var(--gleich) 10%, rgba(8, 7, 14, .7));
border: 1px solid color-mix(in srgb, var(--gleich) 32%, transparent);
}
.countdown__zahl {
font-size: 2rem; font-weight: 800;
letter-spacing: -.03em;
color: color-mix(in srgb, var(--gleich) 22%, #ffffff);
/* Tabellenziffern: Ohne sie springt die ganze Zeile bei jedem
Sekundenwechsel, weil die 1 schmaler ist als die 8. */
font-variant-numeric: tabular-nums;
}
.countdown__wort { font-size: .78rem; color: var(--schrift-leise); letter-spacing: .04em; }
/* =====================================================================
LIVE — der Kinosaal
===================================================================== */
.kino {
grid-template-columns: 1fr minmax(19rem, 23rem);
gap: 0;
height: 100%;
min-height: 0; /* sonst wächst das Raster über das Fenster */
}
.leinwand {
position: relative;
min-width: 0; min-height: 0;
display: grid; place-items: center;
background: #000;
overflow: hidden;
}
.leinwand__video { position: relative; width: 100%; height: 100%; }
.leinwand__video iframe {
position: absolute; inset: 0;
width: 100%; height: 100%;
border: 0;
}
.leinwand__warte {
position: absolute; inset: 0;
display: grid; place-items: center;
color: var(--schrift-leise); font-size: .9rem;
}
/* ---- Die Kamerafenster ----------------------------------------------
Sie liegen ÜBER dem Video. Genau so sieht eine Reaction aus: das
Bild groß, das Gesicht klein davor.
`pointer-events: none` am Behälter und `auto` an den Fenstern: Der
Bereich dazwischen gehört dem Video (Pause, Lautstärke), die
Fenster selbst nehmen Klicks an. Ohne das läge eine unsichtbare
Scheibe über der ganzen Leinwand.
--------------------------------------------------------------------- */
.kameras {
position: absolute;
right: 16px; bottom: 16px;
display: flex; flex-direction: column; gap: 12px;
pointer-events: none;
z-index: 20;
}
.kamera {
position: relative;
width: clamp(120px, 17vw, 208px);
aspect-ratio: 4 / 3;
border-radius: 16px;
overflow: hidden;
background: #0b0a12;
border: 1px solid var(--rand-hell);
box-shadow: 0 24px 50px -22px #000;
pointer-events: auto;
}
.kamera video {
width: 100%; height: 100%;
object-fit: cover;
display: block;
background: #0b0a12;
}
.kamera__name {
position: absolute; left: 8px; bottom: 8px;
padding: 3px 9px 4px;
border-radius: 999px;
font-size: .72rem; font-weight: 700;
background: rgba(6, 5, 11, .76);
border: 1px solid var(--rand);
color: var(--schrift);
backdrop-filter: blur(6px);
max-width: calc(100% - 16px);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kamera[data-host="ja"] { border-color: color-mix(in srgb, var(--an-hell) 46%, transparent); }
.kamera[data-stumm="ja"]::after {
content: "stumm";
position: absolute; right: 8px; top: 8px;
padding: 3px 8px 4px; border-radius: 999px;
font-size: .72rem; font-weight: 800; letter-spacing: .08em;
background: rgba(216, 64, 74, .82); color: #fff;
}
.kamera--leer {
display: grid; place-items: center;
font-size: .72rem; color: var(--schrift-leise);
border-style: dashed;
}
/* Anordnung „gleich": Video und Kameras nebeneinander statt übereinander. */
.kino[data-layout="gleich"] .kameras {
position: static;
flex-direction: row;
justify-content: center;
padding: 10px;
background: #07060d;
}
.kino[data-layout="gleich"] .leinwand {
grid-template-rows: 1fr auto;
align-content: stretch;
}
/* Anordnung „kamera": die Kameras groß, das Video klein in der Ecke. */
.kino[data-layout="kamera"] .kamera { width: clamp(160px, 30vw, 380px); }
.kino[data-layout="kamera"] .kameras {
right: auto; left: 50%; top: 50%; bottom: auto;
transform: translate(-50%, -50%);
flex-direction: row;
}
.kino[data-layout="kamera"] .leinwand__video {
position: absolute; right: 14px; bottom: 14px;
width: clamp(140px, 22vw, 260px); height: auto; aspect-ratio: 16/9;
border-radius: 14px; overflow: hidden;
border: 1px solid var(--rand-hell);
z-index: 25;
}
/* ---- Die Chatschiene ------------------------------------------------- */
.schiene {
display: grid;
grid-template-rows: auto 1fr auto auto;
min-height: 0;
background: #07060d;
border-left: 1px solid var(--rand);
}
.schiene__kopf {
display: flex; align-items: center; gap: 10px;
padding: 14px 16px 12px;
border-bottom: 1px solid var(--rand);
}
.schiene__titel {
margin: 0; font-size: .74rem; font-weight: 800;
letter-spacing: .16em; text-transform: uppercase;
color: var(--schrift-leise);
}
.schiene__zahl {
margin-left: auto;
font-size: .72rem; font-weight: 700;
padding: 2px 9px 3px; border-radius: 999px;
background: rgba(255, 255, 255, .06);
border: 1px solid var(--rand);
color: var(--schrift-leise);
font-variant-numeric: tabular-nums;
}
.schiene__zu { display: none; }
.schiene__liste {
margin: 0; padding: 12px 14px;
list-style: none;
overflow-y: auto;
min-height: 0;
display: flex; flex-direction: column; gap: 9px;
scrollbar-width: thin;
}
.beitrag {
display: grid; gap: 2px;
padding: 8px 11px 9px;
border-radius: 12px;
background: rgba(255, 255, 255, .035);
border: 1px solid transparent;
font-size: .86rem; line-height: 1.42;
color: var(--schrift);
overflow-wrap: anywhere;
}
.beitrag__wer {
font-size: .72rem; font-weight: 800;
letter-spacing: .02em;
color: var(--schrift-leise);
display: flex; align-items: center; gap: 7px;
}
.beitrag__weg {
margin-left: auto;
appearance: none; border: 0; background: none;
color: var(--schrift-leise);
cursor: pointer; padding: 2px 4px; border-radius: 6px;
font-size: .72rem;
}
.beitrag__weg:hover { color: var(--an-hell); background: rgba(216, 64, 74, .12); }
.beitrag[data-host="ja"] {
background: color-mix(in srgb, var(--an) 12%, transparent);
border-color: color-mix(in srgb, var(--an) 30%, transparent);
}
.beitrag[data-host="ja"] .beitrag__wer { color: var(--an-hell); }
.beitrag[data-team="ja"] .beitrag__wer { color: #9ab7ff; }
.schiene__form {
display: flex; gap: 8px;
padding: 12px 14px;
border-top: 1px solid var(--rand);
}
.schiene__feld {
flex: 1 1 auto; min-width: 0;
appearance: none;
padding: 11px 13px;
border-radius: 12px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
color: var(--schrift);
font: inherit; font-size: .9rem;
}
.schiene__feld:focus-visible {
outline: none;
border-color: var(--rand-hell);
box-shadow: 0 0 0 3px rgba(154, 183, 255, .16);
}
.schiene__senden {
flex: none;
width: 44px; height: 44px;
display: grid; place-items: center;
border-radius: 12px;
border: 1px solid color-mix(in srgb, var(--an) 42%, transparent);
background: color-mix(in srgb, var(--an) 24%, transparent);
color: #ffd9db; cursor: pointer;
}
.schiene__senden svg { width: 19px; height: 19px; fill: currentColor; }
/* =====================================================================
DAS GEBEN-FELD
Vier Betraege statt eines Links. Ein Tipp oeffnet PayPal mit schon
eingetragener Summe; danach fragt das Feld EINMAL nach, ob es
geklappt hat -- mehr koennen wir von hier aus nicht wissen.
ES IST GRUEN UND ES BLEIBT GRUEN. Das ist die einzige Stelle im
ganzen Saal mit dieser Farbe: Rot heisst „auf Sendung", Bernstein
heisst „gleich", und was hier steht, ist weder das eine noch das
andere -- es ist das Einzige, was Geld betrifft.
===================================================================== */
.geben {
display: grid; gap: 8px;
margin: 0 14px 14px;
padding: 12px;
border-radius: 14px;
background: linear-gradient(180deg, rgba(125, 226, 168, .14), rgba(71, 201, 127, .07));
border: 1px solid rgba(125, 226, 168, .3);
}
.geben__kopf {
display: flex; align-items: center; gap: 8px;
font-size: .82rem; font-weight: 800;
color: #9ff0c2;
}
.geben__kopf svg { width: 17px; height: 17px; fill: currentColor; flex: none; }
.geben__betraege { display: flex; gap: 6px; flex-wrap: wrap; }
.geben__betrag {
flex: 1 1 4.2rem;
min-height: 44px;
display: grid; place-items: center;
border-radius: 11px;
text-decoration: none;
font-size: .92rem; font-weight: 800;
color: #0a2a1c;
background: linear-gradient(180deg, #7de2a8, #47c97f);
box-shadow: 0 10px 22px -14px #47c97f;
}
.geben__frei {
justify-self: start;
min-height: 34px; display: inline-flex; align-items: center;
font-size: .76rem; color: #9ff0c2;
text-decoration: underline; text-underline-offset: 3px;
}
/* Die eine Frage danach. Sie erscheint erst, wenn jemand einen
Betrag angetippt hat -- vorher waere sie eine Frage auf etwas,
das nicht passiert ist. */
.geben__nach { display: grid; gap: 7px; }
.geben__frage { margin: 0; font-size: .78rem; color: #e9e6f2; }
.geben__nach-knoepfe { display: flex; gap: 6px; }
.geben__melden, .geben__abbruch {
appearance: none; cursor: pointer;
flex: 1 1 auto; min-height: 40px; padding: 0 12px;
border-radius: 11px; font-size: .8rem; font-weight: 700;
}
.geben__melden {
border: 1px solid rgba(125, 226, 168, .5);
background: rgba(125, 226, 168, .18);
color: #9ff0c2;
}
.geben__abbruch {
flex: 0 1 auto;
border: 1px solid var(--rand);
background: none;
color: var(--schrift-leise);
}
.geben__danke { margin: 0; font-size: .78rem; color: #9ff0c2; }
/* ---- Die Spendenliste im Pult --------------------------------------- */
.spendenliste { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.spendenzeile {
display: flex; align-items: center; gap: 10px;
padding: 8px 10px;
border-radius: 11px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .03);
}
.spendenliste--still .spendenzeile { background: none; border-color: transparent; }
.spendenzeile__betrag {
flex: none; min-width: 4.4rem;
font-size: .98rem; font-weight: 900;
font-variant-numeric: tabular-nums;
color: #9ff0c2;
}
.spendenzeile__mitte { flex: 1 1 6rem; min-width: 0; display: grid; gap: 1px; }
.spendenzeile__wer {
font-size: .84rem; color: var(--schrift);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.spendenzeile__gruss {
font-size: .74rem; color: var(--schrift-leise);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.spendenzeile__ja, .spendenzeile__nein, .spendenzeile__nochmal {
appearance: none; cursor: pointer; flex: none;
min-height: 36px; padding: 0 11px;
border-radius: 9px;
font-size: .76rem; font-weight: 700;
}
.spendenzeile__ja {
border: 1px solid rgba(125, 226, 168, .45);
background: rgba(125, 226, 168, .16);
color: #9ff0c2;
}
.spendenzeile__nein, .spendenzeile__nochmal {
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
color: var(--schrift-leise);
}
.spendenliste__leer {
padding: 10px 2px;
font-size: .78rem; color: var(--schrift-leise);
}
/* =====================================================================
DIE REGIE
Sie ist nach dem Vorbild eines echten Regieplatzes gebaut und
nicht nach dem eines Formulars. Drei Dinge machen den Unterschied:
1. EINE LEISTE, DIE IMMER STEHT. Lampe, Laufzeit, Zahlen und die
drei grossen Knoepfe liegen ausserhalb des einklappbaren
Teils. Wer mitten in der Sendung „Beenden" drueckt, drueckt es,
weil etwas passiert ist -- das darf nicht hinter einer
Bewegung liegen.
2. REGISTER STATT STAPEL. Vorher lagen fuenf Kaesten untereinander
in einem Bereich, der hoechstens die halbe Bildschirmhoehe hat.
Man sah fuenf halbe Dinge. Jetzt eines ganz.
3. RUHIGE FLAECHEN. Ein Regieplatz, der selbst leuchtet, kaempft
mit dem Bild um die Aufmerksamkeit. Farbe gibt es nur dort, wo
sie etwas SAGT: rot heisst auf Sendung, bernstein heisst
gleich, alles andere ist grau.
===================================================================== */
/* ==== DAS PULT SCHIEBT, ES DECKT NICHT ZU =========================
(28.09.2026, gefunden im ersten Bild.)
Erst lag es als `position: fixed` ueber der Seite. Aufgeklappt
verdeckte es die untere Haelfte: Das Video war abgeschnitten, der
Chat auch -- ausgerechnet fuer den, der sendet und beides im Blick
haben muss.
Jetzt ist es die zweite Zeile des Saals. Der Saal ist ein Raster
mit `1fr auto`; klappt das Pult auf, wird der Kinosaal darueber
von selbst kleiner. Nichts wird verdeckt, und niemand muss eine
Hoehe ausrechnen, die spaeter nicht mehr stimmt. */
/* 197 PIXEL ZUM SCROLLEN -- gemessen am 28.09.2026, sobald die Regie
aufgeklappt war.
`1fr` heisst nicht „nimm, was uebrig ist", sondern
`minmax(auto, 1fr)`: Die Zeile darf nie kleiner werden als ihr
Inhalt. Der Kinosaal hat aber einen Mindestinhalt, und mit
aufgeklapptem Pult passte beides nicht mehr in die Hoehe -- also
wuchs die Seite nach unten. Wer sendet, scrollte dann mitten in
der Sendung, um an das Bild oder an die Knoepfe zu kommen.
`minmax(0, 1fr)` erlaubt der Zeile zu schrumpfen. Der Kinosaal
wird kleiner, der Chat rollt in sich -- was er ohnehin tut. */
.saal { grid-template-rows: minmax(0, 1fr) auto; }
.pult {
z-index: 60;
background:
linear-gradient(180deg, rgba(255, 255, 255, .045), transparent 90px),
rgba(7, 6, 13, .95);
backdrop-filter: blur(18px) saturate(1.2);
-webkit-backdrop-filter: blur(18px) saturate(1.2);
border-top: 1px solid var(--rand-hell);
box-shadow: 0 -30px 70px -40px #000;
}
/* ---- Die Leiste, die immer steht ------------------------------------- */
.pult__leiste {
display: flex; align-items: center; flex-wrap: wrap;
gap: 10px 16px;
padding: 11px 16px;
border-bottom: 1px solid var(--rand);
}
/* Die Lampe. In jedem Studio haengt sie ueber der Tuer, und sie ist
dort das Erste, was man sieht -- deshalb steht sie hier ganz
links und ist das Einzige, was Farbe traegt. */
.lampe {
display: inline-flex; align-items: center; gap: 9px;
padding: 7px 14px 7px 12px;
border-radius: 999px;
border: 1px solid var(--rand-hell);
background: rgba(255, 255, 255, .04);
font-size: .74rem; font-weight: 800;
letter-spacing: .14em; text-transform: uppercase;
color: var(--zu);
white-space: nowrap;
}
.lampe__punkt {
width: 9px; height: 9px; border-radius: 50%;
background: currentColor;
flex: none;
}
.pult[data-stand="vorbereitung"] .lampe {
color: color-mix(in srgb, var(--gleich) 26%, #ffffff);
border-color: color-mix(in srgb, var(--gleich) 44%, transparent);
background: color-mix(in srgb, var(--gleich) 10%, transparent);
}
.pult[data-stand="live"] .lampe {
color: #ffe2e4;
border-color: color-mix(in srgb, var(--an) 62%, transparent);
background: color-mix(in srgb, var(--an) 22%, transparent);
box-shadow: 0 0 26px -12px var(--an);
}
.pult[data-stand="live"] .lampe__punkt {
background: var(--an-hell);
box-shadow: 0 0 10px 1px var(--an);
animation: lampe-puls 4s ease-in-out infinite;
}
/* Vier Sekunden, und nur zwischen zwei nahen Werten. Ein schnelles
Blinken waere auf einem dunklen Bild ein Stroboskop. */
@keyframes lampe-puls {
0%, 100% { opacity: 1; }
50% { opacity: .45; }
}
/* Die Laufzeit. Der Grund, warum in Regieraeumen ueberall Uhren
haengen: Ohne sie verschaetzt man sich um Viertelstunden. */
.laufzeit { display: flex; align-items: baseline; gap: 7px; }
.laufzeit__zahl {
/* Tabellenziffern -- sonst wackelt die Zeile bei jeder Sekunde. */
font-variant-numeric: tabular-nums;
font-size: 1.06rem; font-weight: 800;
letter-spacing: .01em;
color: var(--schrift);
}
.laufzeit__wort {
font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
color: var(--schrift-leise);
}
/* Die Zahlen. Vier Werte, jeder in zwei Zeilen -- Wort klein
darueber, Zahl gross darunter. So liest man sie im Vorbeisehen. */
.messwerte {
display: flex; flex-wrap: wrap; gap: 4px 18px;
margin: 0;
}
.messwerte__paar { display: grid; gap: 1px; }
.messwerte dt {
font-size: .72rem; letter-spacing: .06em;
color: var(--schrift-leise);
white-space: nowrap;
}
.messwerte dd {
margin: 0;
font-size: .95rem; font-weight: 800;
font-variant-numeric: tabular-nums;
color: var(--schrift);
}
/* Wenn die Kameraplaetze voll sind, ist das keine Warnung, sondern
eine Tatsache -- aber eine, die man sehen muss, bevor jemand
fragt, warum er kein Bild hat. */
.messwerte dd[data-eng="ja"] { color: color-mix(in srgb, var(--gleich) 22%, #ffffff); }
.messwerte dd[data-eng="voll"] { color: var(--an-hell); }
/* Die drei Knoepfe. Sie stehen rechts und wachsen in die Luecke --
auf einem breiten Schirm liegen sie damit am rechten Rand, auf
einem schmalen in einer eigenen Zeile. Keine Schwelle noetig:
`flex-wrap` misst, statt zu rechnen. */
.pult__tun { display: flex; gap: 9px; margin-left: auto; flex-wrap: wrap; }
.tun {
appearance: none; cursor: pointer;
min-height: 44px; padding: 0 18px;
border-radius: 12px;
border: 1px solid var(--rand-hell);
background: rgba(255, 255, 255, .05);
color: var(--schrift);
font-size: .86rem; font-weight: 800;
letter-spacing: .01em;
white-space: nowrap;
}
.tun--vor {
border-color: color-mix(in srgb, var(--gleich) 44%, transparent);
background: color-mix(in srgb, var(--gleich) 13%, transparent);
color: color-mix(in srgb, var(--gleich) 24%, #ffffff);
}
.tun--live {
border-color: color-mix(in srgb, var(--an) 56%, transparent);
background: linear-gradient(180deg,
color-mix(in srgb, var(--an) 74%, #000),
color-mix(in srgb, var(--an) 46%, #000));
color: #fff3f3;
box-shadow: 0 14px 30px -20px var(--an);
}
.tun--aus { color: var(--schrift-leise); }
.tun[disabled] { opacity: .38; cursor: default; box-shadow: none; }
.pult__klapp {
appearance: none; cursor: pointer;
width: 44px; height: 44px;
display: grid; place-items: center;
border-radius: 12px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .03);
color: var(--schrift-leise);
}
.pult__klapp svg {
width: 20px; height: 20px;
fill: none; stroke: currentColor; stroke-width: 2;
stroke-linecap: round; stroke-linejoin: round;
transition: transform .18s ease;
}
.pult[data-auf="ja"] .pult__klapp svg { transform: rotate(180deg); }
/* ---- Der einklappbare Teil ------------------------------------------- */
.pult__innen {
display: none;
gap: 14px;
padding: 13px 16px 16px;
/* Hoechstens die halbe Hoehe -- darueber bleibt vom Saal nichts
mehr uebrig, und wer sendet, schaut auf das Bild und nicht auf
die Knoepfe. Was nicht hineinpasst, rollt. */
/* KLEINER ALS DAS BILD. Gemessen mit 46dvh: Kinosaal 372 Pixel,
Regie 459 -- die Knoepfe waren groesser als das, worum es geht.
Mit 19rem bleibt das Bild der groessere Teil, und die
Sendungs-Tafel (264 Pixel) passt trotzdem ohne Rollen hinein. */
max-height: min(40dvh, 19rem);
overflow-y: auto;
}
.pult[data-auf="ja"] .pult__innen { display: grid; }
/* ---- Die Register ----------------------------------------------------- */
.reiter {
display: flex; gap: 4px; flex-wrap: wrap;
padding: 4px;
border-radius: 13px;
background: rgba(0, 0, 0, .35);
border: 1px solid var(--rand);
}
.reiter__knopf {
appearance: none; cursor: pointer;
display: inline-flex; align-items: center; gap: 7px;
min-height: 38px; padding: 0 14px;
border: 0; border-radius: 10px;
background: none;
color: var(--schrift-leise);
font-size: .82rem; font-weight: 700;
}
.reiter__knopf[aria-selected="true"] {
background: rgba(255, 255, 255, .08);
color: var(--schrift);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
}
.reiter__zahl {
min-width: 20px; padding: 1px 6px;
border-radius: 999px;
background: rgba(255, 255, 255, .09);
font-size: .72rem; font-variant-numeric: tabular-nums;
text-align: center;
}
.reiter__zahl[data-leer="ja"] { opacity: .45; }
.pult-tafel { display: grid; gap: 12px; align-content: start; }
/* AUSDRUECKLICH. `display: grid` auf einer Klasse schlaegt die
eingebaute Regel `[hidden] { display: none }` des Browsers --
je nach Browser und Reihenfolge. Genau so ist in dieser Datei
schon einmal eine Chatschiene aufgegangen, die zu sein sollte.
Eine Zeile ist billiger als die Frage, wer gewinnt. */
.pult-tafel[hidden] { display: none; }
/* ---- Die Videospur ----------------------------------------------------
Vorher gab es fuer das laufende Video im Pult ueberhaupt keine
Bedienung. Wer spulen wollte, musste in das YouTube-Bild fassen --
und was dort passiert, passiert nur bei einem selbst, waehrend
alle anderen weiterlaufen.
--------------------------------------------------------------------- */
.spur {
display: grid; gap: 11px;
padding: 13px 14px 14px;
border-radius: 14px;
background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .02));
border: 1px solid var(--rand);
}
.spur__kopf { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.spur__marke {
flex: none;
padding: 3px 9px;
border-radius: 7px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .05);
font-size: .72rem; font-weight: 800;
letter-spacing: .1em; text-transform: uppercase;
color: var(--schrift-leise);
}
.spur[data-laeuft="ja"] .spur__marke {
color: #ffe2e4;
border-color: color-mix(in srgb, var(--an) 50%, transparent);
background: color-mix(in srgb, var(--an) 18%, transparent);
}
.spur__titel {
min-width: 0;
font-size: .94rem; font-weight: 700;
color: var(--schrift);
/* Ein Videotitel kann sehr lang sein. Eine Zeile mit Auslassung
ist hier richtig: Die Spur soll nicht wachsen, nur weil jemand
ein Video mit langem Namen eingetragen hat. */
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.spur__titel[data-roh="ja"] {
color: var(--schrift-leise);
font-family: ui-monospace, "Cascadia Mono", Menlo, monospace;
font-size: .82rem;
}
.spur__band { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.spur__knopf {
appearance: none; cursor: pointer;
min-height: 40px; min-width: 44px; padding: 0 12px;
border-radius: 11px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .05);
color: var(--schrift);
font-size: .8rem; font-weight: 700;
font-variant-numeric: tabular-nums;
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
}
.spur__knopf--gross {
min-width: 52px;
background: rgba(255, 255, 255, .1);
}
.spur__knopf--gross svg { width: 18px; height: 18px; fill: currentColor; }
.spur__knopf--weiter {
border-color: rgba(154, 183, 255, .34);
background: rgba(154, 183, 255, .12);
color: #cfe0ff;
}
.spur__knopf[disabled] { opacity: .35; cursor: default; }
.spur__zeit {
font-size: .78rem; font-variant-numeric: tabular-nums;
color: var(--schrift-leise);
white-space: nowrap;
}
.spur__schiene {
appearance: none; -webkit-appearance: none;
flex: 1 1 10rem; min-width: 8rem;
height: 30px; background: none; cursor: pointer;
}
.spur__schiene::-webkit-slider-runnable-track {
height: 5px; border-radius: 3px;
background: linear-gradient(90deg, var(--an) var(--fortschritt, 0%),
rgba(255, 255, 255, .12) var(--fortschritt, 0%));
}
.spur__schiene::-webkit-slider-thumb {
-webkit-appearance: none;
width: 15px; height: 15px; margin-top: -5px;
border-radius: 50%;
background: #f4f1fb;
border: 1px solid rgba(0, 0, 0, .4);
}
.spur__schiene::-moz-range-track {
height: 5px; border-radius: 3px;
background: rgba(255, 255, 255, .12);
}
.spur__schiene::-moz-range-progress {
height: 5px; border-radius: 3px; background: var(--an);
}
.spur__schiene::-moz-range-thumb {
width: 15px; height: 15px; border-radius: 50%;
background: #f4f1fb; border: 1px solid rgba(0, 0, 0, .4);
}
/* ---- Die Warteschlange ------------------------------------------------ */
.warteliste { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.warte-zeile {
display: flex; align-items: center; gap: 10px;
padding: 7px 9px 7px 7px;
border-radius: 12px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .03);
}
.warte-zeile__nr {
flex: none;
width: 22px; text-align: center;
font-size: .78rem; font-weight: 800;
font-variant-numeric: tabular-nums;
color: var(--schrift-leise);
}
/* Das Vorschaubild kommt von YouTube selbst -- ohne es sind zehn
Zeilen Text kaum auseinanderzuhalten. */
.warte-zeile__bild {
flex: none;
width: 68px; aspect-ratio: 16 / 9;
border-radius: 7px; object-fit: cover;
background: #12101a;
border: 1px solid var(--rand);
}
.warte-zeile__titel {
flex: 1 1 8rem; min-width: 0;
font-size: .84rem; color: var(--schrift);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.warte-zeile__titel[data-roh="ja"] {
color: var(--schrift-leise);
font-family: ui-monospace, "Cascadia Mono", Menlo, monospace;
font-size: .78rem;
}
.warte-zeile__knoepfe { display: flex; gap: 5px; flex: none; }
.warte-zeile__knoepfe button {
appearance: none; cursor: pointer;
min-height: 34px; min-width: 34px; padding: 0 9px;
border-radius: 9px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
color: var(--schrift-leise);
font-size: .78rem; font-weight: 700;
}
.warte-zeile__knoepfe button[data-was="jetzt"] {
border-color: rgba(154, 183, 255, .34);
color: #cfe0ff;
}
.warte-zeile__knoepfe button[disabled] { opacity: .3; cursor: default; }
.warte-leer {
margin: 0; padding: 14px 4px;
font-size: .82rem; color: var(--schrift-leise);
}
/* ---- Die Regler -------------------------------------------------------
Senkrecht, nebeneinander, mit Pegel daneben. Ein Mischpult sieht
so aus, und das ist kein Zitat: Vier waagerechte Regler
untereinander liest man als Formular, vier senkrechte nebeneinander
als EINEN Zustand.
DER PEGEL IST DAS EIGENTLICHE. Er beantwortet die Frage, die man
sich sonst erst nach der Sendung stellt: „War mein Mikro
ueberhaupt an?" Ein Regler auf 100 sagt darueber nichts.
--------------------------------------------------------------------- */
.regler-reihe { display: flex; gap: 10px; flex-wrap: wrap; }
.regler {
display: grid;
grid-template-columns: auto auto;
grid-template-areas: "wort wort" "schieber pegel" "zahl zahl" "stumm stumm";
justify-items: center; align-items: center;
gap: 7px 6px;
padding: 11px 11px 10px;
border-radius: 13px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .03);
}
.regler__wort {
grid-area: wort;
font-size: .72rem; font-weight: 800;
letter-spacing: .05em;
color: var(--schrift-leise);
white-space: nowrap;
}
.regler input[type="range"] {
grid-area: schieber;
appearance: none; -webkit-appearance: none;
writing-mode: vertical-lr; direction: rtl;
width: 26px; height: 92px;
background: none; cursor: pointer;
}
/* DER FADER IST GRAU, DER PEGEL IST FARBIG -- so herum, und nicht
umgekehrt. Ein roter Fader steht bei jedem auf 100 und schreit
dauerhaft „Achtung", ohne etwas zu sagen. Die Farbe gehoert
dorthin, wo sie eine Auskunft ist: an den gemessenen Ausschlag. */
.regler input[type="range"]::-webkit-slider-runnable-track {
width: 5px; border-radius: 3px;
background: linear-gradient(180deg, rgba(255, 255, 255, .28), rgba(255, 255, 255, .08));
}
.regler input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 22px; height: 13px; margin-left: -9px;
border-radius: 4px;
background: linear-gradient(180deg, #f6f3fc, #b9b3cc);
border: 1px solid rgba(0, 0, 0, .45);
}
.regler input[type="range"]::-moz-range-track {
width: 5px; border-radius: 3px;
background: linear-gradient(180deg, rgba(255, 255, 255, .28), rgba(255, 255, 255, .08));
}
.regler input[type="range"]::-moz-range-thumb {
width: 22px; height: 13px; border-radius: 4px;
background: linear-gradient(180deg, #f6f3fc, #b9b3cc);
border: 1px solid rgba(0, 0, 0, .45);
}
/* Der Pegel. Er waechst von unten und faellt langsam zurueck --
ein Balken, der sofort abfaellt, flackert und ist unlesbar. */
.pegel {
grid-area: pegel;
position: relative;
width: 7px; height: 92px;
border-radius: 4px;
background: rgba(255, 255, 255, .07);
overflow: hidden;
}
.pegel i {
position: absolute; left: 0; right: 0; bottom: 0;
height: var(--stand, 0%);
border-radius: 4px;
background: linear-gradient(0deg, #4fb27a 0%, #4fb27a 62%, var(--gleich) 84%, var(--an) 100%);
transition: height .09s linear;
}
.pegel[data-still="ja"] i { background: rgba(255, 255, 255, .16); }
.regler__zahl {
grid-area: zahl;
font-size: .74rem; font-variant-numeric: tabular-nums;
color: var(--schrift-leise);
}
.regler__stumm {
grid-area: stumm;
appearance: none; cursor: pointer;
width: 100%; min-height: 32px; padding: 0 9px;
border-radius: 9px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
color: var(--schrift-leise);
font-size: .74rem; font-weight: 700;
}
.regler[data-stumm="ja"] .regler__stumm {
background: color-mix(in srgb, var(--an) 30%, transparent);
border-color: color-mix(in srgb, var(--an) 50%, transparent);
color: #ffe2e4;
}
/* ---- Gäste ----------------------------------------------------------- */
.gast-reihe { display: flex; flex-wrap: wrap; gap: 9px; }
.gast-karte {
display: flex; align-items: center; gap: 9px;
padding: 8px 9px 8px 12px;
border-radius: 12px;
background: rgba(255, 255, 255, .04);
border: 1px solid var(--rand);
font-size: .82rem; color: var(--schrift);
}
.gast-karte__platz {
font-size: .72rem; font-weight: 800;
color: var(--schrift-leise); letter-spacing: .08em;
}
.gast-karte button {
appearance: none; cursor: pointer;
min-height: 32px; padding: 0 10px;
border-radius: 9px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
color: var(--schrift-leise);
font-size: .74rem; font-weight: 700;
}
.gast-leer { font-size: .8rem; color: var(--schrift-leise); margin: 0; }
/* ---- Anordnung ------------------------------------------------------- */
.layout-reihe { display: flex; gap: 9px; flex-wrap: wrap; }
.layout-knopf {
appearance: none; cursor: pointer;
min-height: 44px; padding: 9px 15px;
border-radius: 11px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
color: var(--schrift-leise);
font-size: .82rem; font-weight: 700;
}
.layout-knopf[aria-pressed="true"] {
background: rgba(154, 183, 255, .14);
border-color: rgba(154, 183, 255, .38);
color: #cfe0ff;
}
/* ---- Die Kürzel ------------------------------------------------------- */
.kuerzel {
margin: 0;
display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center;
font-size: .72rem; color: var(--schrift-leise);
}
.kuerzel kbd {
display: inline-block;
padding: 1px 6px; margin-right: 2px;
border-radius: 6px;
border: 1px solid var(--rand-hell);
border-bottom-width: 2px;
background: rgba(255, 255, 255, .05);
font-family: inherit; font-size: .72rem; font-weight: 700;
color: var(--schrift);
}
/* ---- Felder im Pult --------------------------------------------------- */
.pult__block {
display: grid; gap: 10px;
padding: 13px 14px 14px;
border-radius: 14px;
background: rgba(255, 255, 255, .03);
border: 1px solid var(--rand);
}
.pult__ueber {
margin: 0;
display: flex; align-items: baseline; gap: 9px;
font-size: .74rem; font-weight: 800;
letter-spacing: .12em; text-transform: uppercase;
color: var(--schrift-leise);
}
.pult__klein { margin: 0; font-size: .72rem; letter-spacing: .02em; text-transform: none; opacity: .85; }
.pult__zeile { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.pult__feld { display: grid; gap: 5px; flex: 1 1 14rem; min-width: 0; }
.pult__feld--kurz { flex: 0 1 12rem; }
.pult__feld > span {
font-size: .72rem; font-weight: 700;
color: var(--schrift-leise); letter-spacing: .04em;
}
.pult__feld input, .pult__wahl {
min-height: 44px; padding: 0 12px;
border-radius: 11px;
border: 1px solid var(--rand);
background: rgba(0, 0, 0, .34);
color: var(--schrift); font: inherit; font-size: .88rem;
min-width: 0;
}
.pult__wahl { flex: 1 1 12rem; }
/* =====================================================================
DAS HANDY
Aus zwei Spalten wird ein Stapel, und der Chat wird zur Lade. Das
Video bleibt oben und behält sein Seitenverhältnis -- es ist der
Grund, warum jemand hier ist.
===================================================================== */
@media (max-width: 860px) {
.kino {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
}
.leinwand {
aspect-ratio: 16 / 9;
height: auto;
width: 100%;
}
.schiene {
border-left: 0;
border-top: 1px solid var(--rand);
min-height: 0;
}
.kameras {
right: 10px; bottom: 10px;
flex-direction: row;
}
.kamera { width: clamp(88px, 26vw, 140px); }
/* ==== KEINE LADE, SONDERN EIN STAPEL =========================
(28.09.2026, nach der ersten Messung auf dem Handy.)
Hier stand eine Lade: Der Chat lag zugeklappt über allem und
fuhr auf Knopfdruck von unten ein. Gemessen war das Ergebnis
ein 390x775 großer Saal mit einem 219 Pixel hohen Video und
556 Pixeln Leere darunter -- weil der Knopf, der die Lade
öffnet, gar nicht erschien.
Statt den Knopf zu reparieren, ist die Lade weg. Sie war die
falsche Lösung für ein Problem, das es nicht gibt: Auf einem
844 Pixel hohen Telefon bleiben unter Kopfleiste und Video
rund 550 Pixel übrig. Das ist mehr Chat, als eine Lade je
zeigen würde -- und es gibt keinen Zustand, in dem etwas
klemmen kann.
Ein Zustand weniger ist besser als ein Zustand, der
funktioniert. */
.schiene { display: grid; }
.schiene__zu { display: none !important; }
/* Das Schild wird kleiner und rueckt hoch: Auf 390 Pixeln teilt es
sich den Platz mit der Titelzeile von YouTube, und zwei Zeilen
Grossbuchstaben sind dort ein Klotz. */
.buehne-schild {
top: 8px;
padding: 5px 11px 6px;
/* NICHT KLEINER ALS .72rem -- das sind 11,52 px, die Untergrenze
des Hauses. Gemessen wurden hier .64rem = 10,24 px. Den Platz
holt sich die engere Sperrung zurueck: Bei Grossbuchstaben
kostet .14em Abstand mehr Breite als die zwei fehlenden
Zehntel Schriftgroesse. */
font-size: .72rem;
letter-spacing: .06em;
gap: 7px;
white-space: nowrap;
}
.buehne-schild__zahl { padding-left: 7px; }
/* Der Ton-Knopf in die MITTE des Bildes. Unten liegen bei 219
Pixeln Hoehe schon die Kamerafenster -- der Knopf lag halb
darueber. In der Mitte steht er dort, wo ohnehin hingesehen
wird, und verdeckt nur das, was man gleich sowieso hoert. */
.ton-an {
bottom: auto;
top: 50%;
transform: translate(-50%, -50%);
}
.warte__buehne { gap: 18px; }
.pult__innen { max-height: 62dvh; }
/* ==== DIE REGIE AM HANDY ======================================
Die Leiste bleibt -- sie ist der Teil, den man im Notfall
braucht. Sie wird nur kleiner und legt die Knöpfe in eine
eigene Zeile, sobald es eng wird. Das macht `flex-wrap` von
selbst; hier steht nur, was dabei schrumpfen darf. */
.pult__leiste { gap: 8px 12px; padding: 9px 12px; }
.messwerte { gap: 3px 13px; }
.messwerte dd { font-size: .88rem; }
.laufzeit__zahl { font-size: .98rem; }
.tun { padding: 0 13px; font-size: .8rem; }
.pult__innen { padding: 11px 12px 14px; }
/* Die Register rollen waagerecht statt umzubrechen: Fünf Reiter in
zwei Zeilen sehen aus wie zehn Knöpfe. */
.reiter { flex-wrap: nowrap; overflow-x: auto; }
.reiter__knopf { white-space: nowrap; }
.regler-reihe { gap: 8px; }
.regler { padding: 9px 9px 8px; }
.regler input[type="range"], .pegel { height: 76px; }
.warte-zeile__bild { width: 54px; }
}
/* Wer weniger Bewegung eingestellt hat, bekommt keinen Puls. Die
Aussage bleibt -- der Punkt steht dann einfach da. */
@media (prefers-reduced-motion: reduce) {
.buehne-schild__punkt,
.lampe__punkt { animation: none !important; }
.pult__klapp svg,
.pegel i { transition: none !important; }
}
/* ---- Der Ton-Knopf ---------------------------------------------------
Er liegt über der Leinwand, mittig unten -- dort, wo der Blick
ohnehin ist, und weit genug von den Kamerafenstern entfernt. Er
verschwindet in dem Moment, in dem der Ton läuft; ein Knopf, der
bleibt, nachdem er getan hat, was er soll, wird zur Deko. */
.ton-an {
position: absolute;
left: 50%; bottom: 20px;
transform: translateX(-50%);
z-index: 30;
display: flex; align-items: center; gap: 9px;
appearance: none; cursor: pointer;
min-height: 44px; padding: 10px 18px;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--an-hell) 50%, transparent);
background: rgba(10, 8, 16, .88);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
color: #ffe9ea;
font-size: .88rem; font-weight: 700;
box-shadow: 0 18px 40px -18px #000, 0 0 26px -10px var(--an);
}
.ton-an svg {
width: 19px; height: 19px;
fill: none; stroke: currentColor; stroke-width: 1.8;
stroke-linecap: round; stroke-linejoin: round;
}
/* =====================================================================
DIE SENDERLEISTE (28.09.2026)
Kamera und Mikro gehoeren dem, der sendet -- Host wie Gast. Sie
liegen UEBER dem Bild und nicht im Regiepult: Waehrend einer
Sendung sieht man auf das Bild, und ein Gast hat ueberhaupt kein
Pult.
SIE IST LEISE, SOLANGE ALLES AN IST. Zwei dunkle Knoepfe am Rand.
Erst wenn etwas AUS ist, wird der Knopf rot -- dann ist es eine
Auskunft und keine Verzierung.
===================================================================== */
.senderleiste {
position: absolute;
left: 16px; bottom: 16px;
z-index: 30;
display: flex; align-items: center; gap: 8px;
padding: 6px;
border-radius: 999px;
background: rgba(10, 8, 16, .82);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--rand);
box-shadow: 0 16px 38px -20px #000;
}
.sender-knopf {
appearance: none; cursor: pointer;
display: inline-flex; align-items: center; gap: 8px;
min-height: 40px; padding: 0 14px 0 11px;
border-radius: 999px;
border: 1px solid transparent;
background: rgba(255, 255, 255, .06);
color: var(--schrift);
font-size: .8rem; font-weight: 700;
}
.sender-knopf svg {
width: 19px; height: 19px;
fill: none; stroke: currentColor; stroke-width: 1.7;
stroke-linecap: round; stroke-linejoin: round;
}
/* Der Schraegstrich erscheint nur, wenn es AUS ist -- dasselbe
Zeichen, das jedes Geraet dafuer benutzt. */
.sender-knopf__strich { opacity: 0; }
.sender-knopf[aria-pressed="true"] {
background: color-mix(in srgb, var(--an) 34%, transparent);
border-color: color-mix(in srgb, var(--an) 58%, transparent);
color: #ffe2e4;
}
.sender-knopf[aria-pressed="true"] .sender-knopf__strich { opacity: 1; }
/* Der Pegel in der Leiste: der kuerzeste Weg zur Antwort auf
„kommt mein Ton ueberhaupt an?". */
.sender-pegel {
display: block;
width: 5px; height: 26px;
margin: 0 8px 0 2px;
border-radius: 3px;
background: rgba(255, 255, 255, .1);
position: relative; overflow: hidden;
}
.sender-pegel i {
position: absolute; left: 0; right: 0; bottom: 0;
height: var(--stand, 0%);
border-radius: 3px;
background: linear-gradient(0deg, #4fb27a 0%, #4fb27a 64%, var(--gleich) 86%, var(--an) 100%);
transition: height .09s linear;
}
/* ---- „Kamera aus" im Fenster ----------------------------------------
Ein abgeschaltetes Bild ist nicht dasselbe wie ein kaputtes. Ohne
diese Beschriftung sind beide ein schwarzes Rechteck -- und dann
fragt jemand im Chat, ob die Technik hakt. */
.kamera__aus {
position: absolute; inset: 0;
display: grid; place-items: center;
background: rgba(8, 7, 14, .88);
color: var(--schrift-leise);
font-size: .74rem; font-weight: 700;
letter-spacing: .06em;
border-radius: inherit;
}
.kamera[data-kamera="aus"] video { opacity: 0; }
/* ---- Der Mikro-Schalter im Pult -------------------------------------
Dieselbe Spalte wie die drei Regler, nur ohne Schieber: Die eigene
Lautstaerke laesst sich nicht am Regler aendern. Was man braucht,
ist an/aus -- und der Pegel daneben. */
.regler--schalter {
grid-template-areas: "wort" "pegel" "stumm";
grid-template-columns: auto;
}
.regler--schalter .pegel { width: 9px; }
/* ---- Die Chat-Stufe --------------------------------------------------
Drei Schalter im Kopf der Schiene. Man moderiert, wo man liest.
===================================================================== */
.stufen {
display: flex; gap: 3px;
margin-left: auto;
padding: 3px;
border-radius: 10px;
background: rgba(0, 0, 0, .35);
border: 1px solid var(--rand);
}
.stufe {
appearance: none; cursor: pointer;
min-height: 28px; padding: 0 9px;
border: 0; border-radius: 7px;
background: none;
color: var(--schrift-leise);
font-size: .72rem; font-weight: 700;
}
.stufe[aria-pressed="true"] {
background: rgba(255, 255, 255, .1);
color: var(--schrift);
}
/* Ist der Chat eingeschraenkt, sieht man es der ganzen Schiene an --
nicht nur dem kleinen Schalter oben. */
.schiene[data-chat="team"] .schiene__form,
.schiene[data-chat="zu"] .schiene__form {
border-top-color: color-mix(in srgb, var(--gleich) 40%, transparent);
background: color-mix(in srgb, var(--gleich) 7%, transparent);
}
.schiene__feld[disabled] { opacity: .75; cursor: not-allowed; }
.schiene__senden[disabled] { opacity: .4; cursor: not-allowed; }
@media (max-width: 860px) {
/* Am Handy liegen unten rechts die Kamerafenster -- die Leiste
rueckt nach oben links unter das Schild. */
.senderleiste { left: 10px; bottom: auto; top: 46px; padding: 4px; gap: 5px; }
.sender-knopf { min-height: 38px; padding: 0 11px 0 9px; font-size: .74rem; }
.sender-pegel { height: 22px; margin: 0 5px 0 1px; }
}