Files
dogfather-universe/workspace/assets/css/reaktion.css
T
DogFatherGit a9e0834cfb Nichts wird mehr nach links oder rechts geschoben
Filipe, 28.09.2026: "ich will auch nicht dass man sachen nach links
und rechts schieben muss. perfektion das untereinander. ich will
niemals irgendwas nach links oder rechts swippen muessen." Dazu ein
Bildschirmfoto der Tafel "Gestaltung" mit waagerechter Rollleiste.

GEMESSEN, NICHT GERATEN

Ein grep nach `overflow-x` findet nur die absichtlichen Roller. Er
findet nicht die Stelle, an der ein Inhalt breiter ist als sein
Kasten und der Browser von sich aus eine Rollleiste anhaengt -- und
genau das war auf dem Bild zu sehen. `server/mess-quer.mjs` geht
deshalb im echten Browser jedes Element durch, auf fuenf
Bildschirmgroessen, in allen sieben Registern, bei offener und
zugeklappter Regie und in allen fuenf Anordnungen.

Erster Lauf: 78 Stellen. Davon waren 54 KEINE -- `overflow-x: hidden`
ist abgeschnittener Text, dort laesst sich nichts schieben. Die
Messung trennt das jetzt; wer es mitzaehlt, findet die echten nicht
mehr. Uebrig blieben vier Ursachen:

  1. DIE REGISTER rollten absichtlich waagerecht. Auf 412 px standen
     von 605 px Registern 193 rechts ausserhalb -- dass es
     "Gestaltung" und "Spenden" gibt, erfuhr man nur beim Wischen auf
     Verdacht. Sie brechen jetzt um. Das kostet oben rund 45 Pixel
     und bringt Gewissheit dafuer.

  2. `.stufen` STAND ZWEIMAL IN reaktion.css -- einmal fuer die
     Stufenleiter der Spenden (`display: grid`), 600 Zeilen spaeter
     fuer die Chat-Leiste Offen/Team/Zu (`display: flex`). Die
     spaetere gewinnt: Die Stufenleiter stellte ihre drei Stufen
     NEBENEINANDER, 572 Pixel in einer 327 Pixel schmalen Spalte.
     Das ist die Rollleiste auf Filipes Bild. Die Chat-Leiste heisst
     jetzt `.chatstufen` / `.chatstufe`.
     Dritter Fall dieser Art nach `.tafel` und `.stufe-knopf`.

  3. DIE TAFELN KONNTEN NICHT SCHRUMPFEN. Ein Gitterfeld hat von
     sich aus `min-width: auto` und besteht auf seinem unteilbarsten
     Inhalt. Mit `minmax(0, 1fr)` und `min-width: 0` bricht jetzt
     alles um, statt hinauszulaufen.

  4. DIE TRANSPORTLEISTE ragte am Handy 76 Pixel ueber beide Kanten
     ("Naechstes" war nur halb zu sehen). Zwei Gruende: `.transport__teil`
     hatte kein `flex-wrap` (die mittlere Gruppe schon -- zwei Regeln
     fuer dieselbe Sache, eine vergessen), und im Umschalter steht
     ein ganzer Videotitel, der als Flex-Kind auf seiner vollen
     Breite bestand.

NEBENBEFUND: EINE FESTE ZAHL VON GESTERN

Der Saal stand auf `height: calc(100dvh - 69px)` -- 69 war einmal
die gemessene Hoehe der Kopfleiste. Sie ist 73 geworden, und der
Saal endete damit 4 Pixel unter dem Fensterrand: Der Play-Knopf war
nur mit Scrollen zu erreichen. Die Antwort ist keine neue Zahl,
sondern eine Regel, die misst -- der Koerper ist jetzt eine Spalte,
die Kopfleiste nimmt, was sie braucht, der Saal bekommt den Rest.
(Dabei noch ein Spezifitaetsunfall: `.reaktion-seite` (0,1,0)
verliert gegen `body.start` (0,1,1) aus start.css.)

NEUE WACHEN

  - `mess-quer.mjs` mit Gegenprobe (ohne die Reparaturen findet sie
    47 px, mit ihnen nichts).
  - pruef-reaktion: kein absichtliches `overflow-x: auto` mehr; und
    zwei Grundregeln derselben Klasse mit verschiedenem `display`
    sind ein Namensstreit. Der bisherige Waechter verglich nur
    ZWISCHEN Stilvorlagen -- `.stufen` stand zweimal in DERSELBEN.
  - pruef-css-klassen: jede Klammer hat ihr Gegenstueck. Beim
    Umschreiben blieb heute das Ende einer Regel ohne ihren Anfang
    stehen; der Browser wirft die Zeile weg und schliesst dafuer den
    naechsten @media-Block zu frueh. Drei Befunde sahen daraufhin wie
    Programmfehler aus.

MESSUNG NACHGEZOGEN

`mess-reaktion` stammte noch aus der Zeit vor "Regie links" und
"drei Kacheln" und meldete drei Dinge, die keine Fehler waren --
gemessen gegen den Stand von HEAD: identisch rot. Sie misst ausserdem
seit heute mit FINGER statt Mauszeiger; ohne `hasTouch` greift keine
einzige Regel aus `@media (pointer: coarse)`, und dort stehen alle
44-Pixel-Beruehrziele des Hauses.

OFFEN UND AUFGESCHRIEBEN

Am Handy bleibt bei offener Regie vom Bild nichts (0 px). Der Mangel
besteht seit dem Umbau "Regie links"; drei Versuche, ihn heute zu
loesen, haben Knoepfe verdeckt -- und ein verdeckter Knopf ist
schlimmer als ein kleines Bild. Die Versuche und der richtige Weg
(Tempo-Gruppe hinter einen Knopf, wie "Aa" im Chat) stehen in
reaktion.css. `mess-reaktion` meldet ihn als dritten Ausgang: nicht
als Fehler und nicht als bestanden.

GEPRUEFT
  pruef-reaktion     384 / 0   (vorher 379)
  pruef-spenden      172 / 0
  pruef-buehne        36 / 0
  pruef-css-klassen, -tippziele, -struktur, -handy: ohne Befund
  mess-quer          EXIT 0 -- 28 Stellen, fuenf Groessen, nichts rollt
  mess-reaktion      EXIT 0, 1 benannter offener Punkt
  mess-buehne        EXIT 0
2026-09-29 02:34:09 +02:00

3083 lines
116 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.
===================================================================== */
/* `body.reaktion-seite`, NICHT NUR `.reaktion-seite`.
`start.css` setzt `body.start { display: block; min-height: 100svh }`
-- Staerke (0,1,1). Eine Regel mit nur einer Klasse ist (0,1,0)
und verliert, ganz gleich welche Datei spaeter geladen wird.
Gemessen: Die Spalte kam gar nicht zustande, der Saal wuchs auf
1615 Pixel. Vierter Fall dieser Art an einem Tag; deshalb steht
der Grund hier und nicht nur die Loesung. */
body.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.
EINE SPALTE, KEINE RECHNUNG. Der Saal stand bis zum 28.09.2026
auf `height: calc(100dvh - 69px)` -- 69 war einmal die Hoehe
der Kopfleiste. Sie ist inzwischen 73 Pixel hoch, und der Saal
ragte damit 4 Pixel unter den Fensterrand; die Transportleiste
mit dem Play-Knopf war nur noch mit Scrollen zu erreichen.
Als Spalte misst es sich von selbst: Die Kopfleiste nimmt, was
sie braucht, der Saal bekommt den Rest. Waechst sie wieder,
rechnet niemand nach. */
display: flex;
flex-direction: column;
/* `height`, nicht `min-height`: Mit einer Mindesthoehe hat der
Saal als Flex-Kind nichts, wogegen er schrumpfen koennte --
gemessen wuchs er auf 1615 Pixel. Erst eine feste Hoehe am
Container gibt ihm die Grenze, innerhalb derer er sich
einrichtet. */
height: 100dvh;
overflow: hidden;
}
/* Der Saal bekommt den Rest -- `min-height: 0`, sonst besteht er
als Flex-Kind auf der Hoehe seines Inhalts und schiebt die
Rechnung wieder auf. */
body.reaktion-seite > .saal { flex: 1 1 auto; min-height: 0; }
body.reaktion-seite > .kopfleiste { flex: none; }
.saal {
position: relative;
display: grid;
/* ==== DREI ZEILEN, UND NUR DIE MITTLERE DEHNT SICH ===============
Vorher standen hier nur zwei Kinder und gar keine Zeilenangabe --
der Browser verteilte den Platz zwischen Saal und Regie, wie er
wollte. Mit der Regieleiste oben wären es drei, und das Bild
hätte gegen zwei Leisten um Platz gekämpft.
`minmax(0, 1fr)` und nicht `1fr`: Ein Raster-Kind mit `1fr` hat
eine Mindestgröße von `auto` — es kann also größer werden als
sein Anteil, wenn sein Inhalt das verlangt, und schiebt dann
alles darunter aus dem Fenster. Genau das ist am 28.09. mit der
Regie passiert (197 px Überlauf). Die Null nimmt ihm das Recht.
DIESE ANGABE STEHT NUR HIER — und das ist der eigentliche
Punkt. Bis zum 28.09.2026 gab es 900 Zeilen weiter unten eine
ZWEITE (`minmax(0, 1fr) auto`, aus der Zeit, als der Saal zwei
Zeilen hatte). Sie stand später in der Datei und gewann: Die
Regieleiste landete in der `1fr`-Zeile, bekam null Pixel, und
ihre Register ragten über das Video.
WIE MICH DAS FAST IN DIE FALSCHE REPARATUR GEFÜHRT HÄTTE: Ich
habe im Browser vier Möglichkeiten durchprobiert und dabei
`style.gridTemplateRows` gesetzt — ein Stilattribut am Element
schlägt JEDE Regel im Stilblatt. Damit sah es so aus, als läge
es an `auto` gegen `min-content`; beide „funktionierten", weil
beide die zweite Regel aushebelten. Erst nachdem die Doppelung
weg war, hat die Gegenprobe gezeigt: `auto` tut es genauso.
Eine Probe, die mehr ändert als das, wonach man sucht,
beantwortet eine andere Frage. */
grid-template-rows: auto minmax(0, 1fr) auto auto;
/* KEINE HOEHE MEHR. Bis zum 28.09.2026 stand hier
`height: calc(100dvh - 69px)`; die 69 waren die damals
gemessene Kopfleiste. Sie ist 73 geworden. Jetzt ist der
Koerper eine Spalte und der Saal ihr dehnbares Kind -- die
Hoehe ergibt sich, statt gerechnet zu werden. */
height: auto;
padding: 0;
max-width: none;
}
.regieleiste { grid-row: 1; }
#teil-zu, #teil-warte, #teil-live { grid-row: 2; }
.pult { grid-row: 3; }
.transport { grid-row: 4; }
.transport[hidden] { display: none; }
/* =====================================================================
DIE REGIE STEHT LINKS -- NICHT NUR UNTEN (28.09.2026)
Filipe: „anstatt alles nur unten zu haben wieso nicht rechts und
links noch ausnutzen um mehr ueberblick zu haben."
Die Regie klebte als 272 Pixel hoher Streifen unten, waehrend
darueber das ganze Bild frei war. Man sah entweder das Video oder
die Bedienung.
AUFGEKLAPPT steht sie jetzt LINKS neben dem Video, ueber die volle
Hoehe. Rechts der Chat, unten die Senderleiste und der Transport.
Das ist die Anordnung jedes Sendepults: Was man bedient, liegt
neben dem, was man dabei ansieht.
ZUGEKLAPPT bleibt alles, wie es war -- eine schmale Leiste unten.
Wer die Regie zumacht, will das Bild gross, und dann waere eine
leere Spalte daneben genau das Gegenteil.
`:has()` UND KEINE KLASSE AM KOERPER. Der Zustand steht schon am
Pult (`data-auf`); ein zweiter Merker am `body` waere die zweite
Antwort auf dieselbe Frage -- und die laeuft irgendwann von der
ersten weg.
ERST AB 1100 PIXELN. Darunter bliebe fuer das Video keine Breite
mehr uebrig: 26rem Regie plus 23rem Chat sind schon 784 Pixel. Die
Zahl ist gerechnet, nicht geraten. */
@media (min-width: 1100px) {
.saal:has(.pult[data-auf="ja"]) {
grid-template-columns: clamp(21rem, 25vw, 27rem) minmax(0, 1fr);
grid-template-areas:
"leiste leiste"
"pult kino"
"pult kino"
"transport transport";
grid-template-rows: auto minmax(0, 1fr) auto auto;
}
.saal:has(.pult[data-auf="ja"]) .regieleiste { grid-area: leiste; }
.saal:has(.pult[data-auf="ja"]) #teil-zu,
.saal:has(.pult[data-auf="ja"]) #teil-warte,
.saal:has(.pult[data-auf="ja"]) #teil-live { grid-area: kino; }
.saal:has(.pult[data-auf="ja"]) .transport { grid-area: transport; }
.saal:has(.pult[data-auf="ja"]) .pult {
grid-area: pult;
display: grid;
/* Der Kopf oben, der Inhalt darunter -- und der Inhalt nimmt,
was uebrig ist. `minmax(0, 1fr)` und nicht `1fr`: Sonst kann
die Spalte von ihrem Inhalt aufgezogen werden, statt zu
rollen. Genau diese Falle hat am selben Tag der Regieleiste
null Pixel gegeben. */
grid-template-rows: auto minmax(0, 1fr);
border-top: 0;
border-right: 1px solid var(--rand);
}
/* ENDLICH PLATZ. Unten waren es 272 Pixel fuer drei Felder
untereinander -- sie passten nicht, und der Transport verdeckte
den Rest. Hier ist die Hoehe die des Saals. */
.saal:has(.pult[data-auf="ja"]) .pult__innen {
max-height: none;
height: 100%;
overflow-y: auto;
}
/* In einer schmalen Spalte stehen die Kacheln UNTEREINANDER. Zwei
nebeneinander waeren auf 21rem je 10rem breit -- dort passt kein
Videotitel und kein Datumsfeld hinein. */
.saal:has(.pult[data-auf="ja"]) .regieplatz {
grid-template-columns: minmax(0, 1fr);
grid-template-areas: "laeuft" "sendung" "bereit";
}
/* Die Senderleiste des Pults bleibt oben in der Spalte stehen,
damit „Auf Sendung" nicht wegrollt. */
.saal:has(.pult[data-auf="ja"]) .pult__leiste {
position: sticky; top: 0; z-index: 2;
}
}
/* =====================================================================
DIE REGIELEISTE — über dem Saal (28.09.2026)
Filipe: „ich hätte das gerne oben also nicht in dieser kachel
sondern über der kachel wo die videos laufen werden."
SIE IST FLACH UND DUNKEL. Eine Leiste am oberen Rand steht neben
dem Video und über allem, was im Saal passiert — alles, was dort
selbst leuchtet, zieht den Blick vom Bild weg. Sie bekommt deshalb
keine Farbe, nur eine Kante nach unten und einen Hauch Licht
darüber, damit sie als Körper lesbar bleibt und nicht als Strich.
===================================================================== */
.regieleiste {
position: relative;
z-index: 50;
min-width: 0;
/* Schild und Register nebeneinander. Das Schild steht AUSSERHALB
des rollenden Teils -- es soll stehenbleiben, wenn die Register
unter dem Finger wandern. */
display: flex; align-items: stretch;
padding: 0;
background:
linear-gradient(180deg, rgba(255, 255, 255, .05), transparent 60%),
rgba(7, 6, 13, .96);
border-bottom: 1px solid var(--rand-hell);
box-shadow: 0 10px 26px -20px #000;
backdrop-filter: blur(16px) saturate(1.15);
-webkit-backdrop-filter: blur(16px) saturate(1.15);
}
.regieleiste[hidden] { display: none; }
/* Das Schild. Klein, gesperrt, leise -- es soll benennen, nicht
rufen. Rechts eine haarfeine Kante als Trennung; ein Abstand
allein liest sich bei sieben Wörtern daneben nicht als Grenze. */
.regieleiste__schild {
flex: none;
display: flex; align-items: center;
padding: 0 14px 0 16px;
margin-right: 4px;
border-right: 1px solid var(--rand);
font-size: .68rem; font-weight: 800;
letter-spacing: .22em; text-transform: uppercase;
color: color-mix(in srgb, var(--schrift-leise) 72%, transparent);
user-select: none;
}
/* AM HANDY WEG. Dort zählt jeder Millimeter für die Register
selbst -- und wer die Regie auf dem Handy öffnet, weiß, was er
geöffnet hat. */
@media (max-width: 560px) {
.regieleiste__schild { display: 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;
}
/* Links oben und nicht rechts: Rechts unten liegen die Kamerafenster,
rechts oben das Stumm-Schild. Gedeckt und klein -- es soll
beantworten, nicht rufen. */
.leinwand__tempo {
position: absolute; left: 14px; top: 14px;
z-index: 22;
padding: 3px 9px 4px;
border-radius: 999px;
font-size: .72rem; font-weight: 800;
font-variant-numeric: tabular-nums;
letter-spacing: .04em;
background: rgba(6, 5, 11, .76);
border: 1px solid var(--rand);
color: var(--schrift-leise);
backdrop-filter: blur(6px);
}
.leinwand__tempo[hidden] { display: none; }
/* ---- 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.
--------------------------------------------------------------------- */
/* ==== EINE GRUNDBREITE FUER ALLE ANORDNUNGEN ======================
`--kam` ist die Breite EINES Kamerafensters. Sie steht an einer
Stelle und wird von den Anordnungen nur nachjustiert; `--kam-gross`
ist der Faktor, den die Regie setzt (0,6 bis 2).
WARUM EINE VARIABLE UND NICHT FUENF ZAHLEN: Vorher stand die
Breite zweimal im Stilblatt -- einmal als Grundregel, einmal für
„Kameras gross". Wer die Größe einstellbar macht, müsste beide
Stellen mitdenken, und die zweite wird vergessen. Das ist genau
die Doppelung, die am selben Tag der Regieleiste null Pixel
gegeben hat. */
.kino {
/* `--kam-grund` wie breit ein Fenster ohne Zutun ist.
`--kam-gross` der Faktor, den die Regie setzt (0,6 bis 2).
`--kam` das Ergebnis -- an EINER Stelle gerechnet.
`--kam-rand` wie weit der Stapel von der Kante der Leinwand
wegsitzt; am Handy enger, weil dort jeder
Pixel Video zählt.
Wer etwas ändern will, ändert `--kam-grund` oder `--kam-rand`.
Wer `--kam` selbst überschreibt, baut die zweite Antwort auf
dieselbe Frage -- und die gewinnt dann irgendwo still. */
--kam-gross: 1;
--kam-grund: clamp(120px, 17vw, 208px);
--kam: calc(var(--kam-grund) * var(--kam-gross));
--kam-rand: 16px;
}
.kameras {
position: absolute;
/* Standardecke: unten rechts. `inset` statt `right`/`bottom`
einzeln -- die Ecken-Regeln weiter unten setzen dann ALLE vier
Werte auf einmal, statt drei zurückzunehmen und einen zu
setzen. Ein halb zurückgenommener Rand ist eine Ecke, die
manchmal klebt. */
inset: auto var(--kam-rand) var(--kam-rand) auto;
width: var(--kam);
/* NIE MEHR ALS FAST DIE HAELFTE. Bei Faktor 2 auf einem schmalen
Bildschirm deckte ein einzelnes Fenster sonst das halbe Video
zu -- und auf dem Handy mehr. Der Prozentwert bezieht sich auf
die Leinwand, weil der Behälter absolut darin liegt. */
max-width: 46%;
display: flex; flex-direction: column; gap: 12px;
pointer-events: none;
z-index: 20;
}
/* ---- Die vier Ecken ---------------------------------------------------
Filipe: „die verschiedenen groessen von kamera und so."
WOFUER DAS DA IST: Unten rechts liegt bei TikTok die Knopfreihe,
bei YouTube die Fortschrittsleiste, und Untertitel stehen fast
immer unten. Eine feste Ecke ist eine, die bei jeder zweiten
Plattform genau im Weg steht.
Sie stehen VOR den Anordnungen: „Kameras gross" und „nur Kamera"
setzen den Behälter ohnehin in die Mitte, und bei gleicher
Stärke gewinnt die spätere Regel. */
.kino[data-ecke="ol"] .kameras { inset: var(--kam-rand) auto auto var(--kam-rand); }
.kino[data-ecke="or"] .kameras { inset: var(--kam-rand) var(--kam-rand) auto auto; }
.kino[data-ecke="ul"] .kameras { inset: auto auto var(--kam-rand) var(--kam-rand); }
.kino[data-ecke="ur"] .kameras { inset: auto var(--kam-rand) var(--kam-rand) auto; }
.kamera {
position: relative;
width: 100%;
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;
}
/* ==== EIN GETEILTER BILDSCHIRM WIRD NICHT ZUGESCHNITTEN ============
Filipe: „waere es nicht einfach eine bildschirm uebertragung zu
installieren?"
`cover` ist fuer ein Gesicht richtig: Es fuellt den Rahmen, und
was an den Seiten fehlt, fehlt niemandem. Bei einem Bildschirm
faellt genau das weg, worum es geht -- 16:9 in einem 4:3-Fenster
verliert links und rechts je ein Achtel, und dort steht die
Werkzeugleiste.
`contain` UND EIN SCHWARZER GRUND. Die schwarzen Streifen sind
kein Schoenheitsfehler, sondern die einzige Art, ein Bild ganz zu
zeigen, dessen Form man nicht kennt.
UND DAS SEITENVERHAELTNIS GEHT AUF 16:9. Ein Bildschirm ist fast
nie 4:3; das Fenster passt sich an, statt den Rahmen mit Schwarz
zu fuellen. */
.kamera[data-bildschirm="ja"] { aspect-ratio: 16 / 9; }
.kamera[data-bildschirm="ja"] video {
object-fit: contain;
background: #000;
}
/* Ein Schild, damit niemand ein stehendes Bild fuer eine
eingefrorene Kamera haelt. */
.kamera[data-bildschirm="ja"] .kamera__name::before {
content: "Bildschirm · ";
color: var(--schrift-leise);
}
.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;
width: 100%; max-width: none;
padding: 10px;
background: #07060d;
}
/* Hier bestimmt das Fenster seine Breite selbst -- der Behälter ist
die ganze Zeile. `min-width: 0` erlaubt dem Flexraster, sie bei
zwei Gästen zu kürzen, statt die Zeile breiter zu machen. */
.kino[data-layout="gleich"] .kamera {
width: var(--kam);
flex: 0 1 auto;
min-width: 0;
}
.kino[data-layout="gleich"] .leinwand {
grid-template-rows: 1fr auto;
align-content: stretch;
}
/* Anordnung „kamera": die Kameras groß, das Video klein in der Ecke.
DER BEHAELTER LIEGT AUF DER GANZEN LEINWAND (`inset: 0`) und nicht
mehr an einem Punkt mit `transform`. Grund: Ein absolut gesetzter
Behälter mit nur EINER Kante bemisst sich nach seinem Inhalt und
kann ihn überlaufen -- am 28.09. waren das bei „nur Kamera"
2175 px in einer 1072 px breiten Leinwand, und ein Gast stand
komplett außerhalb. Mit `inset: 0` gibt es eine feste Breite, auf
die sich `max-width` beziehen kann. */
/* Nur die GRUNDBREITE ist hier eine andere -- der Faktor der Regie
gilt weiter, und gerechnet wird trotzdem nur an der einen Stelle
oben. */
.kino[data-layout="kamera"] { --kam-grund: clamp(160px, 30vw, 380px); }
.kino[data-layout="kamera"] .kamera {
width: var(--kam);
flex: 0 1 auto;
min-width: 0;
max-width: calc(50% - 8px);
}
.kino[data-layout="kamera"] .kameras {
inset: 0;
width: auto; max-width: none;
transform: none;
flex-direction: row;
justify-content: center; align-items: center;
gap: 14px; padding: 16px;
}
.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;
}
/* ==== WEGLASSEN IST KEINE ANORDNUNG MEHR, SONDERN EINE ANDERE FRAGE
Filipe: „nur mein bild, nur das video, möglichkeit zwischen allem
zu wechseln so wie ich will."
Die drei oben verschieben Größenverhältnisse. Diese zwei nehmen
etwas GANZ weg — und dafür gibt es einen sehr praktischen Grund:
In OBS liegt Filipes Kamera ohnehin als eigene Quelle (schärfer,
frei zu schieben). Die Bühnenseite soll dann nur noch das Video
zeigen, sonst steht sein Gesicht zweimal im Bild. Umgekehrt beim
Reden zwischen zwei Videos: Dann soll das stehengebliebene
YouTube-Bild verschwinden und nicht nur kleiner werden.
`display: none` UND NICHT `opacity: 0`. Ein unsichtbares
Videofenster spielt weiter, verbraucht Rechenzeit und — der
eigentliche Punkt — hält bei einem `iframe` den Ton. Man hörte
dann ein Video, das niemand sieht. */
.kino[data-layout="nur_video"] .kameras { display: none; }
.kino[data-layout="nur_kamera"] .leinwand__video { display: none; }
.kino[data-layout="nur_kamera"] .leinwand__warte { display: none; }
/* Die Kameras füllen die ganze Leinwand, nebeneinander und gleich
groß.
==== WARUM `absolute` UND `flex: 1 1 0` UND NICHT DAS NAHELIEGENDE
Der erste Versuch war `position: static; width: 100%; height: 100%`
und an den Fenstern `height: 100%; aspect-ratio: 4/3;
max-width: calc(50% - 8px)`. Klingt richtig. GEMESSEN war der
Behälter dann 2175 px breit in einer 1072 px breiten Leinwand, und
von zwei Gästen stand nur einer im Bild — der zweite lag komplett
außerhalb, hinter `overflow: hidden`.
Zwei Fehler auf einmal, und beide sind lehrreich:
1. `.leinwand` ist ein Raster mit einer Spalte nach Inhaltsbreite.
Ein im Fluss stehendes Kind, das zu breit wird, ZIEHT DIE SPALTE
MIT — und `width: 100%` bezieht sich danach auf die gewachsene
Spalte. Die Begrenzung wuchs also mit dem, was sie begrenzen
sollte. `position: absolute; inset: 0` nimmt das Kind aus dem
Fluss: Es kann das Raster nicht mehr aufziehen.
2. `max-width: calc(50% - 8px)` rechnete gegen denselben
gewachsenen Behälter und war damit wirkungslos.
`flex: 1 1 0` mit `min-width: 0` kann gar nicht überlaufen: Jedes
Fenster bekommt denselben Anteil des vorhandenen Platzes, bei
einem Gesicht alles, bei zweien die Hälfte. Das feste 4:3 fällt
dafür weg — das Bild darin steht auf `object-fit: cover` und füllt
den Rahmen, egal wie er steht. Eine Regel, die nicht rechnet,
kann sich nicht verrechnen. */
.kino[data-layout="nur_kamera"] .kameras {
position: absolute; inset: 0;
/* DER DECKEL MUSS HIER WEG. `.kameras` trägt seit dem 28.09. ein
`max-width: 46%` — richtig für „Video groß", wo ein Fenster
sonst bei doppelter Größe das halbe Video zudeckt. Hier füllen
die Kameras die ganze Leinwand, und der Deckel machte daraus
493 px in einer 1072 px breiten Leinwand. Gefunden hat das nicht
das Auge, sondern die Messung, die die Breite mit „Video groß"
vergleicht: 208 px gegen 225 px, wo ein Vielfaches stehen müsste.
Die Breite kommt aus `inset: 0`, nicht aus `width` — sonst
stünden wieder zwei Angaben für dieselbe Kante da. */
width: auto; height: auto; max-width: none;
flex-direction: row;
justify-content: center; align-items: stretch;
gap: 12px;
padding: 16px;
background: #050408;
}
.kino[data-layout="nur_kamera"] .kamera {
flex: 1 1 0;
min-width: 0;
width: auto; height: auto;
aspect-ratio: auto;
max-width: none;
}
/* ---- 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; }
/* ==== WER SPRICHT ==================================================
Filipe: „die modis, linke hand und rechte hand soll im chat extra
aussehen."
EIN WORT UND NICHT NUR EINE FARBE. Rund acht Prozent der Männer
unterscheiden Rot und Grün schlecht -- und genau hier hängt an der
Unterscheidung etwas: Ist das jemand vom Team oder irgendwer? Eine
Auskunft, die nur in der Farbe steckt, ist für sie keine.
KLEIN, ABER NICHT ZU KLEIN. 11,5 px ist die Untergrenze des
Hauses; .72rem sind 11,52 px. Darunter wird aus einer Auskunft
eine Andeutung.
UND NICHT GRELL. Der Chat steht neben einem laufenden Video.
Alles, was hier selbst leuchtet, zieht den Blick vom Bild weg --
deshalb gedeckte Töne auf einer sehr schwachen Fläche, kein
Vollton. */
.beitrag__rolle {
font-size: .72rem;
font-weight: 800;
letter-spacing: .06em;
text-transform: uppercase;
padding: 1px 7px 2px;
border-radius: 999px;
border: 1px solid transparent;
white-space: nowrap;
line-height: 1.5;
}
.beitrag__rolle[data-rolle="dogi"] {
color: var(--an-hell);
background: rgba(216, 64, 74, .16);
border-color: rgba(216, 64, 74, .34);
}
.beitrag__rolle[data-rolle="team"] {
color: #9ab7ff;
background: rgba(122, 156, 235, .14);
border-color: rgba(122, 156, 235, .30);
}
.beitrag__rolle[data-rolle="modi"] {
color: #86cdb2;
background: rgba(96, 175, 145, .14);
border-color: rgba(96, 175, 145, .30);
}
/* ---- Der Name als Angriffspunkt der Moderation -------------------
Er sieht aus wie der Name daneben und verrät sich nur beim
Darüberfahren. Ein Knopf, der wie ein Knopf aussieht, stünde in
jeder Zeile des Chats und würde ihn unruhig machen -- und die
Moderation weiß ohnehin, dass sie ihn hat. */
.beitrag__name {
appearance: none;
border: 0; background: none; padding: 0;
font: inherit; color: inherit;
letter-spacing: inherit;
cursor: pointer;
border-bottom: 1px dotted rgba(170, 180, 210, .34);
}
.beitrag__name:hover,
.beitrag__name:focus-visible { color: var(--schrift); border-bottom-color: currentColor; }
.beitrag__melden {
margin-left: auto;
appearance: none; border: 0; background: none;
color: rgba(169, 163, 189, .55);
cursor: pointer; padding: 2px 4px; border-radius: 6px;
font-size: .72rem;
}
.beitrag__melden:hover { color: var(--gleich); background: rgba(224, 161, 58, .12); }
.beitrag__melden:disabled { color: var(--gleich); cursor: default; opacity: .8; }
/* Stehen „weg" und „melden" zusammen, schiebt nur das erste. */
.beitrag__weg ~ .beitrag__melden { margin-left: 0; }
/* ---- Das Menü am Namen -------------------------------------------
Es liegt ÜBER dem Chat und schiebt ihn nicht auseinander. Ein
Menü, das die Liste aufklappt, verschiebt alle Beiträge darunter --
und im Live liest man gerade weiter. */
/* Lage und Groesse setzt das Skript -- siehe `menueHinstellen()`.
Hier steht nur, WIE es aussieht, nicht WO es liegt. */
.modmenue {
position: fixed;
z-index: 400;
overflow-y: auto;
min-width: 13.5rem;
max-width: min(20rem, 78vw);
display: grid;
padding: 5px;
border-radius: 12px;
background: #100e18;
border: 1px solid var(--rand-hell);
box-shadow: 0 14px 34px rgba(0, 0, 0, .55);
}
.modmenue--liste {
min-width: 17rem;
gap: 4px;
}
.modmenue__knopf {
appearance: none; border: 0; background: none;
display: block; width: 100%;
text-align: left;
/* 44 px hoch. Das ist keine Formsache: Hier wird jemand stumm
geschaltet, und ein Fehlgriff trifft den Falschen. */
min-height: 44px;
padding: 10px 12px;
border-radius: 9px;
font: inherit; font-size: .84rem; font-weight: 600;
color: var(--schrift);
cursor: pointer;
text-decoration: none;
}
.modmenue__knopf:hover,
.modmenue__knopf:focus-visible { background: rgba(255, 255, 255, .07); }
.modmenue__knopf--weg { color: var(--schrift-leise); font-weight: 500; }
.modmeldung {
display: grid; gap: 3px;
padding: 9px 10px;
border-radius: 10px;
background: rgba(255, 255, 255, .035);
border: 1px solid var(--rand);
}
.modmeldung__wer {
font-size: .72rem; font-weight: 800;
letter-spacing: .02em; color: var(--schrift-leise);
}
.modmeldung__text {
font-size: .84rem; line-height: 1.4; color: var(--schrift);
overflow-wrap: anywhere;
}
.modmeldung__schon { font-size: .72rem; color: var(--zu); }
.modmeldung__knoepfe { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.modmeldung__knoepfe .modmenue__knopf {
width: auto; flex: 1 1 auto; text-align: center;
font-size: .78rem; padding: 10px 9px;
}
/* ---- Die Zahl im Kopf der Schiene --------------------------------
Sie steht nur da, wenn etwas offen ist. In Gold und nicht in Rot:
Rot gehört in diesem Haus dem Senden, und eine zweite rote Fläche
daneben würde beides entwerten. */
.schiene__meldungen {
appearance: none;
font-size: .72rem; font-weight: 800;
letter-spacing: .04em;
padding: 4px 10px 5px;
min-height: 28px;
border-radius: 999px;
background: rgba(224, 161, 58, .16);
border: 1px solid rgba(224, 161, 58, .38);
color: var(--gleich);
cursor: pointer;
white-space: nowrap;
}
.schiene__meldungen:hover { background: rgba(224, 161, 58, .26); }
.schiene__meldungen[hidden] { display: none; }
/* ==== WER MIT DEM FINGER MODERIERT =================================
Nicht die Bildschirmbreite fragt hier, sondern womit jemand tippt:
Ein Tablet ist 1024 px breit und wird trotzdem mit dem Finger
bedient.
DIE ZWEI ZEICHEN AM BEITRAG WERDEN NICHT GROESSER, SIE BEKOMMEN
EINE FLAECHE. Ein 44 px hoher Knopf in jeder Chatzeile würde die
Schiene aufblähen und den Chat unlesbar machen; eine unsichtbare
Fläche darum herum kostet nichts und trifft genauso.
Nachgerechnet: 20 px hoch plus zweimal 12 px sind 44. */
@media (pointer: coarse) {
.schiene__meldungen { min-height: 44px; }
.beitrag__weg, .beitrag__melden { position: relative; }
.beitrag__weg::after, .beitrag__melden::after {
content: ''; position: absolute; inset: -12px;
}
/* Der Name ist der Angriffspunkt der Moderation -- und in einer
Chatzeile das kleinste Ziel überhaupt. */
.beitrag__name { position: relative; }
.beitrag__name::after { content: ''; position: absolute; inset: -12px -6px; }
}
/* ---- Aus der Sendung ---------------------------------------------
Eine ganze Fläche und kein Hinweisstreifen. Wer rausgenommen ist,
soll nicht daneben weiter zusehen -- und soll auch nicht raten, ob
gerade die Technik hakt. */
.raus {
position: fixed; inset: 0; z-index: 900;
display: grid; align-content: center; justify-items: center;
gap: 10px;
padding: 28px 24px;
text-align: center;
background: #050408;
}
.raus__titel {
margin: 0;
font-size: 1.24rem; font-weight: 800;
color: var(--schrift);
}
.raus__text {
margin: 0; max-width: 34rem;
font-size: .95rem; line-height: 1.6;
color: var(--schrift-leise);
}
.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; }
/* Auf dem Knopf darf die Muenze deutlich groesser sein als in einer
Textzeile: Hier ist sie das Erkennungszeichen und nicht die
Einheit hinter einer Zahl. */
.geben__betrag .dogen__zeichen { width: 1.6em; height: 1.6em; }
.geben__betrag {
/* Breiter als vorher: Auf dem Knopf steht jetzt ein Zeichen neben
der Zahl, und „0,2" mit Muenze braucht mehr Platz als „2 €".
Zwei passen weiter nebeneinander, vier brechen auf zwei Reihen
um -- das entscheidet `flex-wrap` und nicht eine Zahl, die man
beim naechsten Knopf vergisst. */
flex: 1 1 5.6rem;
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;
}
/* ==== DER PREIS AM KAUFKNOPF ======================================
Filipe: „die leute sollen nur sehen was dogen kosten. sonst wissen
die ja nicht wie viel es kosten wird."
Klein und ruhig UNTER der Dogenzahl. Die Dogen sind die Waehrung
des Hauses, der Preis ist die Auskunft dazu -- andersherum waere
es ein Geldknopf mit Dogen als Beiwerk. Die Farbe ist dieselbe wie
der Knopftext, nur schwaecher: Ein zweiter Farbton auf einem Knopf
von 44 Pixeln ist einer zu viel. */
.geben__preis {
display: block;
margin-top: 1px;
font-size: .72rem; font-weight: 700;
font-variant-numeric: tabular-nums;
opacity: .62;
}
/* ==== UND DIE UMRECHNUNG FUER DIE LEITUNG =========================
Filipe: „damit ich auch immer weiss was es ist. aber nur ich."
Sie steht ueberall, wo er eine Dogenzahl EINTRAEGT oder PRUEFT --
an der Stufenleiter, beim Eintragen, in den Listen. Immer leise:
Sie ist die Nebenauskunft, nicht die Zahl, um die es geht.
Es gibt sie nur, wenn der Server den Kurs mitgeschickt hat -- und
den bekommt nur die Leitung. Ein Zuschauer sieht diese Klasse nie,
weil die Zeichenkette leer bleibt und `if (preis)` sie gar nicht
erst anlegt. */
.preis {
font-size: .72rem; font-weight: 600;
font-variant-numeric: tabular-nums;
color: var(--schrift-leise);
letter-spacing: 0; text-transform: none;
}
.preis--unter { display: block; margin-top: 1px; }
.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; }
/* ==== WAS DIE LEUTE SELBST SCHREIBEN ===============================
Filipe: „der text der dazu erscheint sollen die leute selber
schreiben koennen ... es sollen personalisierte texte sein von den
leuten selbst."
Zwei kleine Felder, und beide sind freiwillig. Sie stehen im
gruenen Kasten und nicht in einem eigenen -- wer gerade gespendet
hat, soll nicht das Gefuehl haben, jetzt komme noch ein Formular. */
.geben__feld { display: grid; gap: 4px; }
.geben__feld > span {
display: flex; justify-content: space-between; align-items: baseline;
gap: 8px;
font-size: .72rem; font-weight: 700;
color: #9ff0c2; letter-spacing: .03em;
}
.geben__feld input, .geben__feld textarea {
min-height: 40px; padding: 9px 11px;
border-radius: 11px;
border: 1px solid rgba(125, 226, 168, .3);
background: rgba(0, 0, 0, .3);
color: var(--schrift); font: inherit; font-size: .84rem;
min-width: 0; width: 100%; box-sizing: border-box;
}
.geben__feld textarea { resize: vertical; line-height: 1.4; }
.geben__feld input:focus-visible, .geben__feld textarea:focus-visible {
outline: 2px solid rgba(125, 226, 168, .6); outline-offset: 1px;
}
/* Der Zaehler steht erst da, wenn es eng wird -- ein Zaehler, der
von Anfang an mitlaeuft, macht aus einem Gruss eine Aufgabe. */
/* .72rem und nicht .7rem: 11,52 px ist die Untergrenze des Hauses,
11,2 waere darunter. Die Zahl ist nicht Geschmack -- sie steht in
`pruef-css-klassen`, und genau dort ist diese Zeile aufgefallen. */
.geben__rest { font-size: .72rem; font-weight: 600; opacity: .7; }
.geben__rest[data-eng="ja"] { color: var(--gleich); opacity: 1; }
/* Der eigene Stand. Er steht nur da, wenn er nicht null ist. */
.geben__stand {
margin: 0;
display: flex; align-items: center; gap: .4em;
font-size: .78rem; color: #9ff0c2;
}
.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: 4px; }
/* ==== DIE SCHRANKE VOR DEM STREAM ==================================
Name und Text sind hier FELDER und keine Beschriftung: Der Text
kommt seit dem 28.09. von dem, der gibt, und die Leitung sieht ihn
kurz bevor er im Livestream steht. Ohne die Moeglichkeit, ein Wort
zu aendern, bliebe nur „ganz ablehnen" -- und dann faellt wegen
eines Wortes eine echte Spende unter den Tisch. */
.spendenzeile__feld {
min-height: 34px; padding: 5px 9px;
border-radius: 9px;
border: 1px solid var(--rand);
background: rgba(0, 0, 0, .3);
color: var(--schrift); font: inherit; font-size: .82rem;
min-width: 0; width: 100%; box-sizing: border-box;
}
.spendenzeile__feld--gruss { font-size: .76rem; color: var(--schrift-leise); }
.spendenzeile__feld:focus-visible {
outline: 2px solid var(--rand-hell); outline-offset: 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);
}
/* ==== WER WIE VIELE DOGEN HAT ======================================
Filipe: „ich will dass die den leuten auch als punkte hinzugefuegt
werden."
NUR IM PULT. Oeffentlich waere das eine Rangliste darueber, wer wie
viel gibt -- und wer wenig geben kann, staende jeden Abend darin.
Sie ist absichtlich ruhig gestaltet: eine Auskunft, kein
Siegertreppchen. */
.dogenliste {
list-style: none; margin: 0; padding: 0;
display: grid; gap: 4px;
}
.dogenzeile {
display: flex; align-items: center; gap: 10px;
padding: 6px 10px;
border-radius: 9px;
background: rgba(255, 255, 255, .03);
}
.dogenzeile__wer {
flex: 1 1 auto; min-width: 0;
font-size: .82rem; color: var(--schrift);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dogenzeile__wert {
flex: none;
font-size: .92rem; font-weight: 800;
color: #9ff0c2;
}
/* =====================================================================
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. */
/* DIE ZEILEN DES SAALS STEHEN GANZ OBEN, BEI `.saal` -- und nur
dort. Hier stand bis zum 28.09.2026 eine zweite Angabe
(`minmax(0, 1fr) auto`), aus der Zeit, als der Saal zwei Zeilen
hatte. Sie stand SPAETER in der Datei und gewann damit gegen die
dreizeilige oben: Die Regieleiste landete in der `1fr`-Zeile,
bekam null Pixel, und ihre Register ragten ueber das Video.
Gemessen war das `0px 491px 340px` -- und im Quelltext oben stand
die ganze Zeit die richtige Angabe. Zwei Regeln, die dieselbe
Frage beantworten, sind keine Sicherheit, sondern die Garantie,
dass eine davon irgendwann falsch ist. */
.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. */
/* 17rem SEIT DEM 28.09., VORHER 19. Die Register sind aus diesem
Teil heraus nach oben gewandert; sie waren hier rund 47 Pixel
hoch. Die Sendungs-Tafel misst 264 Pixel und passt damit
weiterhin ohne Rollen hinein — die 32 Pixel Unterschied gehen
an das Bild zurück. */
max-height: min(40dvh, 17rem);
overflow-y: auto;
}
/* EINE SPALTE, DIE BIS AUF NULL SCHRUMPFEN DARF.
`grid-template-columns` steht hier ausdruecklich, obwohl es nur
eine Spalte gibt. Der Grund: Die Vorgabe waere `auto`, und eine
`auto`-Spalte richtet sich nach dem unteilbarsten Inhalt -- also
genau das, was in der schmalen Regiespalte die waagerechte
Rollleiste erzeugt hat. `minmax(0, 1fr)` sagt stattdessen: nimm
die Breite, die da ist, und bring den Inhalt darin unter.
ACHTUNG BEIM LESEN: `overflow-y: auto` allein reicht, damit der
Browser AUCH waagerecht rollt. Steht eine Achse auf `auto` und
die andere auf `visible`, macht er aus der `visible` ebenfalls
`auto` -- es gibt in dieser Datei also gar kein `overflow-x`,
und die Rollleiste war trotzdem da. Deshalb ist die Reparatur
hier, beim Platz, und nicht bei einem `overflow-x: hidden`:
Letzteres haette den Text still abgeschnitten, statt ihn
umbrechen zu lassen. */
.pult[data-auf="ja"] .pult__innen { display: grid; grid-template-columns: minmax(0, 1fr); }
/* ---- Die Register -----------------------------------------------------
SIE BRECHEN UM. SEIT DEM 28.09.2026.
Vorher rollten sie waagerecht, mit einer Begründung, die für sich
genommen stimmte: Sieben Register in zwei Zeilen kosten oben rund
45 Pixel, und zwar dem Video, um das es geht. Waagerecht rollen
kostet null.
Filipe hat das entschieden, und seine Entscheidung ist die
richtige: „ich will niemals irgendwas nach links oder rechts
swippen müssen." Waagerecht rollen kostet eben NICHT null --
es kostet die Gewissheit, alles gesehen zu haben. Auf einem
412-Pixel-Handy standen von 605 Pixeln Registern 193 rechts
ausserhalb; dass es „Gestaltung" und „Spenden" überhaupt gibt,
erfuhr man nur, wenn man auf Verdacht wischte. Ein Register, das
man nicht sieht, gibt es nicht.
GEMESSEN: Mit Umbruch stehen auf 412 px zwei Zeilen (rund 45 px
mehr), auf 360 px drei. Das ist der Preis, und er ist richtig
bezahlt -- umgekehrt gab es dafür null Gewissheit.
`flex-wrap: wrap` ist dabei eine Regel, die MISST: Sie bricht
genau dann um, wenn der Platz nicht reicht, und bei einem
achten Register von selbst eine Zeile später. Eine feste
Schwelle („ab 500 px umbrechen") wäre beim nächsten Register
still falsch. */
.reiter {
position: relative;
display: flex; gap: 4px; flex-wrap: wrap;
padding: 5px 10px 6px;
min-width: 0;
}
.reiter__knopf {
appearance: none; cursor: pointer;
position: relative;
display: inline-flex; align-items: center; gap: 7px;
/* 44 PX UND NICHT MEHR 38. In der Schublade war das ein Reiter
unter vielen; oben am Rand ist es das Erste, wonach ein Daumen
greift. Die Hausgröße für Fingerziele ist 44. */
min-height: 44px; padding: 0 15px;
flex: none;
scroll-snap-align: center;
border: 0; border-radius: 11px;
background: none;
color: var(--schrift-leise);
font-size: .82rem; font-weight: 700;
white-space: nowrap;
transition: color .16s ease, background-color .16s ease;
}
.reiter__knopf:hover { color: var(--schrift); }
/* DIE FLAECHE MACHT DIE MARKE, DIE FARBE MACHT DER KNOPF.
Zwei Anzeigen für dieselbe Sache -- aber nur eine davon rechnet.
Vorher trugen beide eine Füllung, und die feste verdeckte die
gleitende. */
.reiter__knopf[aria-selected="true"] {
color: #fff;
letter-spacing: .01em;
}
/* ---- Die gleitende Marke ----------------------------------------------
Sie liegt IN der rollenden Leiste, nicht darüber — dadurch wandert
sie beim Rollen von selbst mit, ohne dass jemand nachrechnen muss.
Ihre Lage setzt das Skript aus dem gemessenen Rechteck des
gewählten Knopfes.
UND SIE IST NICHT DIE EINZIGE ANZEIGE. Die Pille darunter bleibt
gefüllt. Sollte die Marke je aus dem Tritt geraten — Schrift lädt
nach, jemand zieht das Fenster —, ist die Auswahl trotzdem zu
sehen. Eine Anzeige, die rechnet, braucht eine daneben, die es
nicht tut. */
.reiter__marke {
position: absolute;
left: 0; top: 0;
width: 0; height: 0;
z-index: 0;
border-radius: 11px;
/* Glas mit Lichtkante oben und Tiefe unten -- dieselbe Sprache
wie überall im Haus: Was obenauf liegt, bekommt oben Licht. */
background:
linear-gradient(180deg, rgba(255, 255, 255, .11), rgba(255, 255, 255, .045));
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .16),
inset 0 -1px 0 rgba(0, 0, 0, .3),
0 6px 16px -10px #000;
transform: translate(0, 0);
transition:
transform .3s cubic-bezier(.22, 1, .3, 1),
width .3s cubic-bezier(.22, 1, .3, 1);
pointer-events: none;
}
/* Der Streifen darunter führt zur Tafel, die gerade offen ist --
das ist die einzige Farbe in der ganzen Leiste. */
.reiter__marke::after {
content: '';
position: absolute;
left: 12px; right: 12px; bottom: -5px;
height: 2px;
border-radius: 2px;
background: linear-gradient(90deg,
transparent,
var(--an-hell) 25%, var(--an-hell) 75%,
transparent);
box-shadow: 0 0 10px -1px var(--an-hell);
}
/* IST DIE REGIE ZUGEKLAPPT, IST DIE TAFEL NICHT DA -- dann führt
der Streifen nirgendwohin und wird leise. Eine Auskunft, die
nichts kostet: Man sieht am Rand, ob unten etwas offen ist. */
.saal:has(.pult[data-auf="nein"]) .reiter__marke::after { opacity: .28; }
/* Solange nichts gemessen ist, gibt es sie nicht — eine Marke, die
bei null anfängt und dann springt, sieht nach Fehler aus. */
.reiter__marke[hidden] { display: none; }
.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; }
/* `min-width: 0` IST HIER KEINE ZIERDE.
Ein Gitterfeld hat von sich aus `min-width: auto` -- es besteht
also darauf, mindestens so breit zu sein wie sein unteilbarster
Inhalt. In der 359 Pixel breiten Regiespalte hiess das: die Tafel
„Gestaltung" bestand auf 572 Pixeln, und `.pult__innen` haengte
eine waagerechte Rollleiste an. Genau das stand auf Filipes
Bildschirmfoto vom 28.09.2026.
Mit `min-width: 0` darf sie schrumpfen, und alles darin bricht
um -- untereinander statt nebeneinander. */
.pult-tafel {
display: grid; grid-template-columns: minmax(0, 1fr);
gap: 12px; align-content: start; min-width: 0;
}
/* 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.
--------------------------------------------------------------------- */
/* =====================================================================
DER REGIEPLATZ (28.09.2026)
Filipe: „kann das nicht bissl aufgeteilt sein auf links und rechts
und eine barre unten in der mitte. kannst du das nicht hoch
professionell machen und hochwertig vom aussehen?"
---------------------------------------------------------------------
DIE TEILUNG FOLGT DEM, WAS WANN GEBRAUCHT WIRD
LINKS Was läuft. Das liest man, man tippt es nicht.
RECHTS Was eingetragen wird. Das tippt man VOR der Sendung.
UNTEN Der Transport. Den fasst man WÄHREND der Sendung an --
und er liegt deshalb immer an derselben Stelle, über
die ganze Breite.
Vorher stand alles in einem Stapel untereinander, und wer im Live
an den Play-Knopf wollte, musste an den Eingabefeldern
vorbeiscrollen. Scrollen ist mitten in einer Sendung ein Griff
daneben.
`minmax(0, 1fr)` UND NICHT `1fr`: Ein langer Videotitel würde die
Spalte sonst aufziehen, statt abgeschnitten zu werden -- und dann
läuft die rechte Seite aus dem Pult. Dieselbe Falle wie bei den
Saalzeilen am selben Tag.
===================================================================== */
.regieplatz {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
/* DIE LINKE KACHEL GEHT UEBER BEIDE ZEILEN. Ohne das waere sie so
hoch wie ihr Inhalt, und daneben staenden zwei -- eine Seite,
die unten ausfranst. So schliessen beide auf derselben Linie ab. */
grid-template-areas:
"laeuft sendung"
"laeuft bereit";
gap: 12px;
align-items: stretch;
}
.regiekachel--laeuft { grid-area: laeuft; }
.regiekachel--sendung { grid-area: sendung; }
.regiekachel--bereit { grid-area: bereit; }
/* ==== EINE KACHEL ==================================================
Filipe: „wo rechts links und unten kacheln sind wo alles drin ist,
schoen verteilt."
Rahmen, Kopf, eigener Grund. Vorher standen hier zwei Spalten mit
einer Trennlinie dazwischen -- das ist eine Teilung, keine
Gliederung, und ohne Rahmen fehlt genau das, was eine Flaeche
aufgeraeumt aussehen laesst.
AUGENSCHONEND: kein Leuchten, kein harter Kontrast. Der Grund ist
wenige Prozent heller als die Umgebung; das reicht, damit das Auge
eine Flaeche sieht, und blendet niemanden, der abends sendet. */
.regiekachel {
display: grid; gap: 9px; align-content: start;
padding: 11px 13px 13px;
border-radius: 14px;
border: 1px solid var(--rand);
background: linear-gradient(180deg, rgba(255, 255, 255, .045), rgba(255, 255, 255, .015));
min-width: 0;
}
.regiekachel__kopf {
display: flex; align-items: center; justify-content: space-between;
gap: 8px; min-width: 0;
}
.regiekachel__ueber {
margin: 0;
/* .72rem und nicht weniger: 11,52 px ist die Untergrenze des
Hauses. Die Zahl ist nicht Geschmack -- sie steht in
`pruef-css-klassen`. */
font-size: .72rem; font-weight: 800;
letter-spacing: .14em; text-transform: uppercase;
color: var(--schrift-leise);
}
/* Zwei Felder nebeneinander, solange Platz ist -- und untereinander,
sobald keiner mehr da ist. Das entscheidet `wrap` und nicht eine
Zahl, die man beim naechsten Feld vergisst. */
.regiekachel__paar { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.regiekachel__paar > .pult__feld { flex: 1 1 11rem; }
/* ==== DAS VORSCHAUBILD ============================================
Es ist der Grund, warum die linke Kachel nie leer aussieht. Steht
noch kein Video da, liegt darin der Satz, der sagt, was zu tun ist
-- ein leerer Kasten sagt nur, dass etwas fehlt. */
.laufbild {
position: relative;
aspect-ratio: 16 / 9;
border-radius: 11px;
overflow: hidden;
background: #07060d;
border: 1px solid var(--rand);
display: grid; place-items: center;
}
.laufbild img { width: 100%; height: 100%; object-fit: cover; display: block; }
.laufbild[data-bild="nein"] img { display: none; }
.laufbild__leer {
position: absolute;
padding: 0 16px;
text-align: center;
font-size: .78rem; line-height: 1.45;
color: var(--schrift-leise);
}
.laufbild[data-bild="ja"] .laufbild__leer { display: none; }
/* ---- Die Transportleiste --------------------------------------------
Aufgebaut wie jeder Videospieler, den man kennt: Schiene über die
ganze Breite, darunter eine Reihe mit dem Transport in der MITTE.
Eine Anordnung, die man schon kennt, muss man nicht lernen.
Sie ist die einzige Fläche im Pult mit eigenem Grund -- weil sie
die einzige ist, die im Live gebraucht wird. */
.transport {
display: grid; gap: 10px;
padding: 12px 14px 13px;
border-radius: 15px;
border: 1px solid var(--rand-hell);
/* ==== SIE KLEBT UNTEN ==========================================
GEMESSEN, NICHT VERMUTET: Beim ersten Bau lag die Leiste bei
y=986 in einem 900 Pixel hohen Fenster -- unter dem Falz. Wer im
Live an den Play-Knopf wollte, haette also scrollen muessen, und
genau davon sollte der Umbau wegfuehren. Die Rechnung ging auf
(links, rechts, Leiste darunter), und das Ergebnis war trotzdem
falsch.
`sticky` loest beides auf einmal: Sie steht unten -- wie Filipe
es wollte -- und bleibt dabei immer sichtbar. Sie ist die
LETZTE Zeile des Rasters, also verdeckt sie nichts: Unter ihr
kommt nichts mehr.
Der Grund muss dafuer DICHT sein. Eine halbdurchsichtige Leiste,
durch die Text scrollt, ist genau die Art Flaeche, auf der man
sich im Live verliest. */
/* Er ist seit dem 28.09. eine eigene Zeile UNTER dem Saal und
nicht mehr das letzte Kind einer rollenden Tafel -- damit
braucht er kein `sticky` mehr, er steht ohnehin immer unten.
Ein `sticky`, das nichts mehr klebt, ist eine Regel, die man
beim naechsten Umbau falsch versteht. */
z-index: 3;
background:
linear-gradient(180deg, rgba(23, 20, 34, .95), rgba(15, 13, 24, .98));
backdrop-filter: blur(12px) saturate(1.1);
-webkit-backdrop-filter: blur(12px) saturate(1.1);
box-shadow: 0 -14px 26px -22px #000, inset 0 1px 0 rgba(255, 255, 255, .06);
}
.transport__schiene { display: flex; align-items: center; gap: 12px; }
.transport__schiene .spur__schiene { flex: 1 1 auto; min-width: 0; }
.transport__reihe {
display: grid;
/* Drei gleich breite Teile -- nur so steht der Transport wirklich
in der Mitte und nicht dort, wo die Nachbarn gerade Platz
lassen. */
grid-template-columns: 1fr auto 1fr;
align-items: center;
gap: 10px;
}
/* SIE BRECHEN UM. Ohne das ragte die rechte Gruppe auf einem
390er Handy 76 Pixel ueber beide Kanten hinaus, und „Nächstes"
war nur mit Wischen zu erreichen -- genau das, was Filipe am
28.09.2026 abgestellt haben wollte. Die mittlere Gruppe hatte
`wrap` schon; die beiden aeusseren nicht. */
.transport__teil {
display: flex; align-items: center; gap: 8px;
flex-wrap: wrap; min-width: 0;
}
.transport__teil--mitte { justify-content: center; gap: 10px; }
.transport__teil--rechts { justify-content: flex-end; }
/* ==== JEDE GRUPPE HAT EINEN NAMEN =================================
Auf Filipes Bildschirmfoto standen drei kleine Knopfgruppen in
einem 1400 Pixel breiten Kasten, und dazwischen war Luft. Leere
zwischen Knoepfen liest sich als „hier fehlt noch etwas". Ein Wort
davor bindet die Gruppe zusammen und fuellt den Raum mit Auskunft
statt mit Abstand. */
/* Die Taste am Knopf -- klein, ruhig, und nie unter 11,5 px: Die
Untergrenze des Hauses gilt auch fuer eine Nebenauskunft, sonst
ist sie keine Auskunft. */
.transport__teil kbd,
.transport__wort kbd,
.sender-taste {
font-size: .72rem; font-weight: 700;
font-family: inherit;
padding: 1px 5px;
border-radius: 5px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .06);
color: var(--schrift-leise);
line-height: 1.5;
}
.sender-taste { margin-left: 6px; }
/* Sie steht UNTER dem runden Play-Knopf. `order` statt einer neuen
Zeile: Die drei Knoepfe bleiben damit in einer Reihe, und die
Taste haengt darunter, ohne die Mitte zu verschieben. */
.transport__taste {
flex-basis: 100%;
display: flex; justify-content: center;
margin-top: -2px;
}
.transport__teil--mitte { flex-wrap: wrap; }
.transport__wort {
display: inline-flex; align-items: center; gap: 5px;
flex: none;
font-size: .72rem; font-weight: 800;
letter-spacing: .12em; text-transform: uppercase;
color: var(--schrift-leise);
}
.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__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;
}
/* DER PLAY-KNOPF IST DER GROESSTE KNOPF DES HAUSES -- und das ist
kein Geschmack: Er ist der einzige, den man mitten in einer
Sendung blind treffen muss. Rund, damit er sich schon in der
Form von allen anderen unterscheidet. */
.spur__knopf--gross {
min-width: 58px; min-height: 58px;
border-radius: 50%;
background: rgba(255, 255, 255, .12);
border-color: var(--rand-hell);
}
.spur__knopf--gross:hover { background: rgba(255, 255, 255, .17); }
.spur__knopf--gross svg { width: 22px; height: 22px; fill: currentColor; }
.spur__knopf--weiter {
border-color: rgba(154, 183, 255, .34);
background: rgba(154, 183, 255, .12);
color: #cfe0ff;
}
/* Der Umschalter zwischen den beiden Videos. In Gold und nicht in
Blau: „Nächstes" geht vorwärts und ist endgültig, „Wechseln" geht
hin und her. Zwei Knöpfe nebeneinander, die gleich aussehen und
Verschiedenes tun, sind im Live ein Griff daneben. */
.spur__knopf--tausch {
border-color: rgba(224, 161, 58, .36);
background: rgba(224, 161, 58, .13);
color: #f0cf9a;
/* Er steht seit dem 28.09. in der linken Spalte und nicht mehr in
einer eigenen Reihe: Dort ist die Breite der Spalte die Grenze,
nicht eine Zahl, die man beim naechsten Umbau vergisst. */
max-width: 100%;
justify-content: flex-start;
overflow: hidden;
}
/* DER TITEL DARF KUERZER WERDEN. `text-overflow: ellipsis` wirkt
erst, wenn das Kuerzen ueberhaupt erlaubt ist: Als Flex-Kind
steht das `span` von sich aus auf `min-width: auto` und besteht
damit auf der vollen Textbreite. Gemessen: 368 Pixel Knopf in
einem 390 Pixel breiten Fenster. */
.spur__knopf--tausch span {
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
min-width: 0; flex: 0 1 auto;
}
.spur__knopf--tausch[hidden] { display: none; }
/* ---- Geschwindigkeit ----
Eine Reihe kleiner Schalter, kein Schieberegler: Es gibt sechs
erlaubte Werte, und ein Regler, der zwischen ihnen einrastet, wäre
eine Bedienung, die etwas vortäuscht, das sie nicht kann.
Sie steht LINKS in der Transportleiste und nicht neben dem
Play-Knopf: Sie wird selten angefasst, und im Live fasst man in
die Mitte. */
.tempo { display: flex; gap: 4px; flex-wrap: wrap; }
.tempo__knopf {
appearance: none; cursor: pointer;
min-height: 34px; min-width: 44px; padding: 0 9px;
border-radius: 9px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
color: var(--schrift-leise);
font-size: .76rem; font-weight: 700;
font-variant-numeric: tabular-nums;
}
.tempo__knopf[aria-pressed="true"] {
background: rgba(154, 183, 255, .14);
border-color: rgba(154, 183, 255, .38);
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; }
/* SIE BRICHT UM. Vorher stand sie auf der Vorgabe `nowrap`: Nummer,
Vorschaubild, Titel und vier Knoepfe in einer starren Reihe, 554
Pixel breit. In der 359 Pixel schmalen Regiespalte hiess das eine
waagerechte Rollleiste -- und wer die vier Knoepfe erreichen
wollte, musste zu ihnen hinwischen.
Mit `wrap` rutschen die Knoepfe in eine zweite Zeile, sobald es
eng wird, und stehen auf dem breiten Bildschirm weiterhin daneben.
Die Regel MISST also, statt eine Schwelle zu raten. */
.warte-zeile {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
min-width: 0;
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 ------------------------------------------------------- */
/* ==== DIE STUFENLEITER =============================================
Eine Zeile je Stufe, alle Felder nebeneinander. Umbrechen statt
rollen: Am Handy wird aus der Zeile ein Block, und die Regie
bleibt bedienbar, ohne dass man seitwaerts schieben muss. */
.stufen { display: grid; gap: 9px; }
.stufe-zeile {
display: flex; flex-wrap: wrap; align-items: flex-end; gap: 9px;
padding: 11px 12px 12px;
border-radius: 13px;
background: rgba(255, 255, 255, .035);
border: 1px solid var(--rand);
}
.stufe-feld { display: grid; gap: 3px; min-width: 0; }
.stufe-feld > span {
font-size: .72rem; font-weight: 700;
letter-spacing: .06em; text-transform: uppercase;
color: var(--schrift-leise);
}
.stufe-feld input, .stufe-feld select {
appearance: none;
min-height: 44px; padding: 9px 11px;
border-radius: 10px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .05);
color: var(--schrift);
font: inherit; font-size: .84rem;
min-width: 0;
}
.stufe-feld input[type="color"] { width: 56px; padding: 4px; }
.stufe-ab, .stufe-dauer, .stufe-groesse { width: 5.5rem; }
.stufe-name { width: 10rem; }
.stufe-vorlage { width: 7.5rem; }
.stufe-bild { display: flex; align-items: center; gap: 7px; }
.stufe-bild img {
width: 44px; height: 44px;
object-fit: contain;
border-radius: 9px;
background: rgba(255, 255, 255, .05);
border: 1px solid var(--rand);
}
.stufe-tun {
appearance: none; cursor: pointer;
display: inline-flex; align-items: center; justify-content: center;
min-height: 44px; padding: 9px 13px;
border-radius: 10px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .05);
color: var(--schrift);
font: inherit; font-size: .8rem; font-weight: 700;
white-space: nowrap;
}
.stufe-tun:hover { background: rgba(255, 255, 255, .09); }
.stufe-tun--weg { color: var(--schrift-leise); font-weight: 500; }
.stufe-tun--weg:hover { color: var(--an-hell); background: rgba(216, 64, 74, .12); }
.stufe-tun--aus { opacity: .45; cursor: default; }
/* ==== DIE DREI MUENZSAETZE =========================================
Filipe: „alle drei varianten will ich drauf so dass ich sie
aussuchen kann wie ich will."
Jeder Satz zeigt seine DREI Muenzen nebeneinander, von links nach
rechts aufsteigend -- der Unterschied zwischen niedrig und hoch
ist hier die eigentliche Aussage, und den sieht man nur im
Vergleich.
AUGENSCHONEND: Der gewaehlte Satz wird nicht heller, sondern
bekommt einen ruhigen Rahmen und einen leichten Grund. Ein
leuchtender Rahmen neben neun glaenzenden Muenzen waere zu viel
auf einmal. */
.muenzwahl { display: grid; gap: 8px; }
.muenzsatz {
appearance: none; cursor: pointer; text-align: left;
display: flex; align-items: center; gap: 14px;
padding: 8px 12px;
border-radius: 13px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .03);
color: var(--schrift-leise);
}
.muenzsatz[aria-pressed="true"] {
border-color: rgba(154, 183, 255, .45);
background: rgba(154, 183, 255, .11);
color: var(--schrift);
}
.muenzsatz__reihe { display: flex; gap: 6px; flex: none; }
.muenzsatz__bild {
/* GROSS GENUG, UM ZU ENTSCHEIDEN. Bei 40 px sahen „Amethyst" und
„Neon" auf dem Bildschirmfoto praktisch gleich aus -- und genau
sie auseinanderzuhalten ist der Zweck dieser Liste. Eine
Auswahl, in der man den Unterschied nicht sieht, ist keine. */
width: 56px; height: 56px;
object-fit: contain;
filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .5));
}
/* Die mittlere und die hohe stehen etwas groesser -- so sieht man
die Rangfolge, noch bevor man die Bilder erkannt hat. */
.muenzsatz__bild:nth-child(2) { width: 64px; height: 64px; }
.muenzsatz__bild:nth-child(3) { width: 72px; height: 72px; }
.muenzsatz__text { display: grid; gap: 2px; min-width: 0; }
.muenzsatz__name { font-size: .86rem; font-weight: 800; }
/* NICHT NUR DIE FARBE SAGT, WAS GEWAEHLT IST. Neben neun glaenzenden
Muenzen geht ein ruhiger Rahmen unter, und wer Farben schlecht
unterscheidet, sieht ihn gar nicht. Ein Wort kann man nicht
uebersehen. Fuer Hilfsmittel steht daneben `aria-pressed`. */
.muenzsatz[aria-pressed="true"] .muenzsatz__name::after {
content: " · gewählt";
color: #9ab7ff; font-weight: 700;
}
.muenzsatz__wort {
font-size: .72rem; color: var(--schrift-leise);
overflow: hidden; text-overflow: ellipsis;
}
.zeichenwahl__tun { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
/* „Noch nicht übernommen" in Gold: Es ist keine Störung, sondern
eine Erinnerung -- Rot gehört in diesem Haus dem Senden. */
#stufen-stand[data-offen="ja"] { color: var(--gleich); font-weight: 700; }
#stufen-stand[data-offen="nein"] { color: var(--schrift-leise); }
/* ==== GRÖSSE UND ECKE DER KAMERAFENSTER ============================
Zwei Gruppen nebeneinander, beide klein — sie stehen unter der
Anordnung und sind deren Feinjustierung, nicht ihresgleichen. */
.kamerawahl { display: flex; flex-wrap: wrap; gap: 14px 22px; align-items: flex-start; }
.kamerawahl__teil { display: grid; gap: 5px; }
.kamerawahl__wort {
font-size: .72rem; font-weight: 700;
letter-spacing: .06em; text-transform: uppercase;
color: var(--schrift-leise);
}
.kamgroesse { display: flex; gap: 4px; flex-wrap: wrap; }
.kamgroesse__knopf {
appearance: none; cursor: pointer;
min-height: 38px; min-width: 44px; padding: 0 9px;
border-radius: 9px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
color: var(--schrift-leise);
font-size: .76rem; font-weight: 700;
font-variant-numeric: tabular-nums;
}
.kamgroesse__knopf[aria-pressed="true"] {
background: rgba(154, 183, 255, .14);
border-color: rgba(154, 183, 255, .38);
color: #cfe0ff;
}
/* ---- Die vier Ecken --------------------------------------------------
Jeder Knopf ist ein kleines Abbild der Leinwand mit einem Feld in
der Ecke, die er meint. Ein Wort wäre länger zu lesen, als das
Bild zu erfassen ist — und vier Wörter nebeneinander passen am
Handy nicht in eine Zeile.
Der Name steht trotzdem da: als `aria-label` für Hilfsmittel und
als Hinweis unter dem Zeiger. */
.kamecke { display: flex; gap: 6px; }
.kamecke__knopf {
appearance: none; cursor: pointer;
position: relative;
width: 44px; height: 38px;
padding: 5px;
border-radius: 8px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .04);
}
.kamecke__feld {
position: absolute;
width: 12px; height: 9px;
border-radius: 2px;
background: var(--schrift-leise);
opacity: .5;
}
.kamecke__knopf[data-ecke="ol"] .kamecke__feld { top: 5px; left: 5px; }
.kamecke__knopf[data-ecke="or"] .kamecke__feld { top: 5px; right: 5px; }
.kamecke__knopf[data-ecke="ul"] .kamecke__feld { bottom: 5px; left: 5px; }
.kamecke__knopf[data-ecke="ur"] .kamecke__feld { bottom: 5px; right: 5px; }
.kamecke__knopf[aria-pressed="true"] {
border-color: rgba(154, 183, 255, .38);
background: rgba(154, 183, 255, .14);
}
.kamecke__knopf[aria-pressed="true"] .kamecke__feld {
background: #cfe0ff; opacity: 1;
}
/* Ein Knopf, der gerade nichts tun kann, sieht auch so aus — und
der Satz darunter sagt, warum. Gilt für beide Gruppen: die Ecke
wirkt nur bei „Video groß", die Größe überall außer bei „Nur
Video", wo es gar keine Kamerafenster gibt. */
.kamecke__knopf:disabled,
.kamgroesse__knopf:disabled { opacity: .38; cursor: default; }
/* Am Finger werden beide Gruppen auf Hausgröße gehoben.
`min-height`/`min-width` und nicht `height`/`width` — das ist
nicht Geschmack: `pruef-tippziele` leitet daraus ab, dass ein
Element gedeckt ist, und hat den Eckwähler zu Recht gemeldet,
solange dort nur eine feste Höhe stand. Eine feste Höhe sagt
„genau so groß"; die Regel will wissen „mindestens so groß". */
/* Der Teilen-Knopf in der Senderleiste: gedrueckt heisst hier
„teilt gerade" und nicht „ist aus" -- deshalb leuchtet er, statt
durchgestrichen zu sein. */
#s-teilen[aria-pressed="true"] {
border-color: rgba(125, 226, 168, .5);
background: rgba(125, 226, 168, .16);
color: #9ff0c2;
}
#s-teilen svg { fill: none; stroke: currentColor; stroke-width: 1.7; }
.sender-knopf[disabled] { opacity: .4; cursor: default; }
@media (pointer: coarse) {
.kamgroesse__knopf { min-height: 44px; }
.kamecke__knopf { min-height: 44px; min-width: 52px; height: 44px; width: 52px; }
/* Am Finger werden auch die Felder in der offenen Spendenliste auf
Hausgroesse gehoben -- sie werden mitten in einer Sendung
bedient, oft am Handy. */
.spendenzeile__feld { min-height: 44px; }
}
.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 ------------------------------------------------------- */
/* ==== DIE ALTE LEGENDE ============================================
Sie stand als eigener Absatz am Ende der Regie -- hinter ALLEN
Registern, also auch unter „Ton" und „Spenden", wo keines ihrer
Kuerzel etwas tut. Seit dem 28.09. steht jede Taste an dem Knopf,
den sie bedient. Die Regeln bleiben, weil `kuerzel` auch anderswo
im Haus vorkommt. */
.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; grid-template-columns: minmax(0, 1fr);
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;
}
/* ==== DER HAUPTKNOPF EINER ZEILE ===================================
`knopf-still--haupt` stand schon an „Übernehmen" bei den Stufen --
und war NIRGENDS gestaltet. Eine Klasse, die kein Stilblatt kennt,
ist stille Absicht ohne Wirkung: Sie sieht im Quelltext aus, als
sei etwas hervorgehoben, und auf dem Bildschirm ist es das nicht.
Gefunden beim Nachsehen, ob es sie gibt, bevor ich sie ein zweites
Mal benutze.
Dieselben Werte wie „Nächstes" in der Transportleiste: Ein Haus,
in dem die wichtige Handlung zweimal verschieden aussieht, hat
keine wichtige Handlung. */
.knopf-still--haupt {
border-color: rgba(154, 183, 255, .34);
background: rgba(154, 183, 255, .12);
color: #cfe0ff;
}
/* Ein Knopf, der gebraucht wird, aber nicht gesucht: leise Farbe,
und im Live grau. Rot waere er erst, wenn er etwas zerstoeren
koennte -- er leert nur den Schreibtisch. */
.knopf-still--leise {
border-color: var(--rand);
background: none;
color: var(--schrift-leise);
}
.knopf-still--leise:hover:not([disabled]) {
color: var(--an-hell);
border-color: rgba(216, 64, 74, .35);
background: rgba(216, 64, 74, .1);
}
.knopf-still--leise[disabled] { opacity: .4; cursor: default; }
.pult__zeile--ende { margin-top: 4px; align-items: center; }
.pult__feld select {
min-height: 44px; padding: 0 10px;
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__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) {
/* ==== DAS BILD VERSCHWINDET NICHT ===============================
Gemessen am 28.09.2026 auf 390x844: Bei offener Regie war das
Kino 0 Pixel hoch -- die Regie (511 px) hatte alles genommen,
weil die Kinozeile auf `minmax(0, 1fr)` steht und bis auf null
schrumpfen darf.
Mit einer Mindesthoehe bleibt das Bild stehen, und die Regie
rollt dafuer in sich. Senkrecht rollen ist in Ordnung; Filipes
Ansage vom 28.09. galt dem Wischen nach links und rechts. Ein
Video, das ganz weg ist, ist dagegen kein Video mehr. */
/* `minmax(0, auto)` FUER DIE REGIE, NICHT `auto`.
`auto` heisst fuer eine Rasterzeile „mindestens so hoch wie
der Inhalt" -- sie schrumpft also nicht, sie laeuft ueber.
Gemessen auf 320 und 390 px: Die Regie lag 51 Pixel ueber der
Transportleiste, „Vorbereiten" und der Klapp-Knopf waren von
der Positionsschiene verdeckt. Erst mit `minmax(0, auto)` darf
sie nachgeben, und dann wirkt auch ihr `overflow-y: auto`:
Sie rollt in sich, statt die Leiste darunter zuzudecken. */
/* ==== OFFEN: AM HANDY VERSCHWINDET DAS BILD ====================
Gemessen am 28.09.2026 auf 390x844 bei offener Regie:
Saal 775 = Leiste 101 + Kino 0 + Regie 511
Das Bild ist NULL Pixel hoch. Wer mitten in der Sendung etwas
einstellt, sieht nicht mehr, worueber er redet.
ICH HABE DAS HEUTE NICHT SAUBER GELOEST und schreibe lieber
auf, was ich probiert habe, als eine halbe Loesung
stehenzulassen:
- Kinozeile auf `minmax(24dvh, 1fr)`: Das Bild kam zurueck,
dafuer wurde die Regiezeile gekuerzt und ihr Kopf lag
ueber der Transportleiste -- „Vorbereiten" und „Beenden"
waren von der Positionsschiene verdeckt (gemessen auf 320
und 390 px). Ein verdeckter Knopf ist schlimmer als ein
kleines Bild: Man drueckt ihn und trifft etwas anderes.
- Hoechsthoehe fuer die Regie (52dvh) mit klebendem Kopf:
besser, 390 px war sauber -- 320 px blieb verdeckt.
- Tempo-Knoepfe schmaler, Wort weg: half nicht genug.
DIE WURZEL ist die Transportleiste: Seit sie umbricht (statt
seitlich zu rollen -- Filipes Ansage vom 28.09.), ist sie auf
320 px 220 Pixel hoch. Zusammen mit der Regieleiste (115) sind
das 335 von 453 Pixeln Saal; fuer Bild UND Regie bleiben 118.
DER RICHTIGE WEG ist, die Tempo-Gruppe am Fingergeraet hinter
einen Knopf zu klappen -- so wie die Schriftleiste im Chat
hinter „Aa". Das spart rund 90 Pixel und braucht ein paar
Zeilen Programm. Als eigener Schritt, nicht nebenbei. */
/* ==== AM HANDY WIRD AUS LINKS UND RECHTS EIN STAPEL ==========
Zwei Spalten auf 390 px waeren zwei Spalten mit je 180 px -- da
passt kein Videotitel hinein und kein Datumsfeld. Die
Transportleiste bleibt, wo sie ist: ganz unten, ueber die
ganze Breite. Sie ist das, was man im Live anfasst, und das
aendert sich mit der Bildschirmbreite nicht. */
.regieplatz {
grid-template-columns: minmax(0, 1fr);
grid-template-areas: "laeuft" "sendung" "bereit";
gap: 12px;
}
/* Die drei gleich breiten Teile der Leiste gehen auf; uebrig
bleibt: Transport in der Mitte, alles andere darunter. */
.transport__reihe {
grid-template-columns: minmax(0, 1fr);
justify-items: center;
gap: 12px;
}
.transport__teil--rechts { justify-content: center; }
.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;
}
/* ==== AM HANDY NUR ZWEI ZAHLEN ANDERS ==========================
Hier stand bis zum 28.09. `.kamera { width: clamp(88px, 26vw,
140px) }` -- eine feste Breite am Fenster selbst. Seit die Regie
die Größe einstellen kann, war das die zweite Antwort auf
dieselbe Frage, und sie gewann: Filipes Einstellung hätte am
Telefon gar nichts bewirkt, und am Rechner wäre alles richtig
gewesen. Gefunden hat das die Prüfung, nicht das Auge.
Und `.kameras { right: 10px; bottom: 10px }` war seit den vier
Ecken wirkungslos: `.kino[data-ecke="…"] .kameras` ist stärker
und setzt `inset` vollständig, ganz gleich, in welcher Reihe die
Regel steht. Eine Regel, die aussieht, als täte sie etwas, ist
schlimmer als keine. */
.kino {
--kam-grund: clamp(88px, 26vw, 140px);
--kam-rand: 10px;
}
.kameras { flex-direction: row; }
/* ==== 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; }
/* 52dvh SEIT DEM 28.09., VORHER 62. Die Register sind nach oben
gewandert, und auf 844 Pixel Höhe blieben mit 62 nur 131 Pixel
für das Bild übrig -- ein Streifen, kein Video. Gemessen mit
52: 215 Pixel. Die Tafeln rollen ohnehin in sich; was hier
kleiner wird, ist die Höhe der Schublade, nicht ihr Inhalt. */
/* GEMESSEN UND NICHT GESCHAETZT. Vorher 62dvh -- damit blieben auf
844 Pixel Höhe 131 Pixel für das Bild übrig, ein Streifen. Mit
52dvh wurden es 75: schlechter, nicht besser. Der Grund stand
woanders — die Leiste des Pults bricht am Handy in vier Zeilen
um und ist dort rund 200 Pixel hoch, nicht 67. Ein Anteil der
Fensterhöhe kann davon nichts wissen.
Also eine feste Obergrenze daneben: 19rem sind 304 Pixel, und
200 + 304 lassen dem Video 217 — genug für ein 16:9-Bild auf
390 Pixel Breite (219). Die Tafeln rollen in sich; kleiner wird
die Schublade, nicht ihr Inhalt. */
.pult__innen { max-height: min(52dvh, 19rem); }
/* ==== 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 auf JEDER Breite waagerecht -- das steht
jetzt in der Grundregel. Am Handy wird nur enger gefasst. */
.reiter { padding: 4px 8px 5px; gap: 3px; }
.reiter__knopf { padding: 0 12px; font-size: .8rem; }
.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,
.reiter__marke,
.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.
===================================================================== */
/* DIE CHAT-LEISTE HIESS BIS ZUM 28.09.2026 `.stufen` -- GENAU WIE
DIE STUFENLEITER DER SPENDEN, 600 Zeilen weiter oben. Zwei Dinge,
ein Name, und die spaetere Regel gewinnt: Die Spenden-Stufenleiter
bekam dadurch `display: flex` und stellte ihre drei Stufen
NEBENEINANDER -- 572 Pixel in einer 327 Pixel schmalen Spalte, mit
waagerechter Rollleiste. Auf dem Bildschirmfoto sah das aus wie ein
Platzproblem; es war ein Namensstreit. Dritter Fall dieser Art nach
`.tafel` und `.stufe-knopf`. */
.chatstufen {
display: flex; gap: 3px;
margin-left: auto;
padding: 3px;
border-radius: 10px;
background: rgba(0, 0, 0, .35);
border: 1px solid var(--rand);
}
.chatstufe {
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;
}
.chatstufe[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; }
}
/* ---- Die Bühnenquellen ------------------------------------------------
Drei Adressen zum Kopieren. Der Schlüssel darin steht NICHT
ausgeschrieben da: Er ist ein Geheimnis, und dieser Bildschirm wird
gestreamt. Der Knopf legt die vollständige Adresse in die
Zwischenablage.
--------------------------------------------------------------------- */
.quellen { display: grid; gap: 7px; }
.quelle {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
padding: 9px 11px;
border-radius: 12px;
border: 1px solid var(--rand);
background: rgba(255, 255, 255, .03);
}
.quelle__text { flex: 1 1 12rem; min-width: 0; display: grid; gap: 1px; }
.quelle__name {
font-size: .84rem; font-weight: 800;
color: var(--schrift);
}
.quelle__was {
font-size: .74rem; color: var(--schrift-leise);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.quelle__kopie {
appearance: none; cursor: pointer; flex: none;
min-height: 38px; padding: 0 14px;
border-radius: 10px;
border: 1px solid rgba(154, 183, 255, .34);
background: rgba(154, 183, 255, .12);
color: #cfe0ff;
font-size: .78rem; font-weight: 700;
}
.quelle__kopie[data-fertig="ja"] {
border-color: rgba(125, 226, 168, .5);
background: rgba(125, 226, 168, .18);
color: #9ff0c2;
}
/* Nur der Notweg, wenn die Zwischenablage nicht geht. */
.quelle__feld {
flex: 1 1 100%;
min-height: 38px; padding: 0 10px;
border-radius: 10px;
border: 1px solid var(--rand);
background: rgba(0, 0, 0, .34);
color: var(--schrift);
font: inherit; font-size: .76rem;
font-family: ui-monospace, "Cascadia Mono", Menlo, monospace;
}
/* =====================================================================
DER BÜHNENMODUS (?nur=buehne)
Dieselbe Seite, nur ohne alles Bedienbare — für die Aufnahme als
Fenster in OBS oder TikTok Studio. Übrig bleibt, was in den Stream
gehört: das Video und die Kameras.
FÜR DEN FALL MIT GÄSTEN. Deren Kameras kommen über eine
Direktverbindung an, und die braucht eine angemeldete Seite — eine
Browser-Quelle in OBS kann das nicht, weil OBS die Anmeldung nicht
zuverlässig behält. Läuft nur das Video, ist `buehne.html` die
bessere Quelle: schärfer, frei in Größe und Lage.
===================================================================== */
body[data-nur="buehne"] .kopfleiste,
body[data-nur="buehne"] .schiene,
body[data-nur="buehne"] .regieleiste,
body[data-nur="buehne"] .pult,
body[data-nur="buehne"] .buehne-schild,
body[data-nur="buehne"] .senderleiste,
body[data-nur="buehne"] .ton-an,
body[data-nur="buehne"] .fehler,
body[data-nur="buehne"] .spendentafel {
display: none !important;
}
/* Der Saal füllt das ganze Fenster — ohne die 69 Pixel Kopfleiste,
die es hier nicht mehr gibt.
==== UND ER BEHÄLT SEINE DREI ZEILEN ==============================
Hier stand `grid-template-rows: minmax(0, 1fr)` — eine einzige
Zeile. Das war richtig, solange nichts festgenagelt war. Seit dem
28.09. sitzt `#teil-live` ausdrücklich auf Zeile 2, und die gab es
hier dann nicht mehr: Das Video landete in einer IMPLIZITEN Zeile,
die sich nach ihrem Inhalt bemisst — während die Leinwand ihre
Höhe aus der Zeile nimmt. Beide warten aufeinander, heraus kommt
null. Gemessen: Leinwand unsichtbar, Saal 720 von 720.
Die drei Zeilen der Grundregel stimmen hier von selbst: Leiste und
Pult sind `display: none` und belegen als `auto`-Zeile genau null
Pixel. Es bleibt also nur die Höhe zu setzen.
DAS IST HEUTE DER VIERTE FALL VON „ZWEI REGELN FÜR DIESELBE
FRAGE" (Tafeln, Saalzeilen, Kamerabreite, jetzt der
Bühnenmodus). Die Lehre ist jedes Mal dieselbe und jedes Mal
dieselbe Lösung: nicht die zweite Regel richtig stellen, sondern
sie abschaffen. */
body[data-nur="buehne"] .saal {
height: 100dvh;
}
body[data-nur="buehne"] .kino { grid-template-columns: 1fr; }
body[data-nur="buehne"] { background: #000; }
/* ==== KEINE TASTENKUERZEL AM FINGERGERAET =========================
Sie stehen an den Knoepfen, damit man sie beim Bedienen lernt --
am Rechner genau richtig. An einem Geraet ohne Tastatur sind sie
eine Beschriftung fuer etwas, das es nicht gibt, und sie kosten
Breite: Gemessen wuchs die Transportleiste auf einem 390er Handy
dadurch auf 373 Pixel und nahm der Regie den Platz, in dem „Auf
Sendung" steht.
Fuer Vorleseprogramme bleiben sie im Dokument -- versteckt wird
nur, was das Auge nicht braucht. */
@media (pointer: coarse) {
.transport__teil kbd,
.transport__wort kbd,
.transport__taste,
.sender-taste,
.spur__knopf kbd { display: none; }
}