/* ==========================================================================
   Traktorrallye — eigenes Erscheinungsbild über Bootstrap 5

   Farbwelt: Türkis, übernommen aus rbTagger (dort --cue: #21C7E8). Im
   Dunkelmodus liegen rbTaggers Flächenwerte unverändert darunter, damit
   beide Projekte zusammengehören.

   Für den Hellmodus ist #21C7E8 dagegen unbrauchbar als Schrift- oder
   Buttonfarbe: auf Weiß ergibt es einen Kontrast von etwa 1,9:1 und wäre
   damit kaum lesbar. Dort trägt ein tiefes Petrol (--trr-teal-700, rund
   6:1 auf Weiß) die bedienbaren Elemente, während das helle Türkis als
   Akzent für Hervorhebungen bleibt.

   Grundhaltung ansonsten unverändert: einladend statt technisch, großzügige
   Klickflächen — das Portal richtet sich ausdrücklich auch an Gäste, die
   mit Computern wenig anfangen können.
   ========================================================================== */

:root {
    /* ----------------------------------------------------------- Die Palette

       Ein Erscheinungsbild, und zwar dunkel. Kein Umschalter.

       Der Grund steht im Logo: Der Markenton #02b0a7 kommt auf Weiß auf
       2,7:1 und auf dunklem Grund auf 6,1:1. Im Hellen hätte man nie die
       Markenfarbe gesehen, sondern immer eine abgedunkelte Ableitung — ein
       Kontur-Logo in einer satten Farbe ist für Dunkel gezeichnet. Dazu
       passt der Inhalt: Scheune, Abend, Lagerfeuer, Cocktails.

       Zwei Erscheinungsbilder kosteten außerdem dauerhaft: Jedes neue
       Bauteil brauchte zwei Kontrollen, und die zweite fand niemand
       schön genug, um sie ernsthaft zu machen.

       Wo tatsächlich Weiß gebraucht wird, ist das Papier — dafür steht
       weiter unten ein eigener Druckabschnitt. Genau diese Aufgabe hatte
       der Hellmodus nie erledigt.

       data-bs-theme="dark" steht trotzdem fest im Dokument: Bootstrap
       schaltet seine eigenen Bauteile (Dropdown, Formulare, Alerts)
       ausschließlich über dieses Attribut. Ohne es blieben sie hell,
       mitten in einer dunklen Seite. */

    /* Leitfarbe. 500 ist der Markenton aus dem Logo — derselbe Wert, der
       später als Plotterfolie auf den Shirts liegt. Auf dunklem Grund
       trägt er selbst, deshalb ist 700 hier kein abgedunkelter Ersatz,
       sondern der Markenton in Person. */
    --trr-teal-900: #8ee7e0;
    --trr-teal-800: #55d6ce;
    --trr-teal-700: #02b0a7;   /* der Markenton selbst, 6,1:1 auf Panel */
    --trr-teal-600: #2ac7bd;
    --trr-teal-500: #02b0a7;   /* Markenton — Logo und Plotterfolie */
    --trr-teal-100: #0f302e;
    --trr-teal-050: #0b2422;

    /* Zweitfarbe für Hinweise und den Manager-Zugang */
    --trr-amber-600: #f2a93b;
    --trr-amber-500: #f2a93b;
    --trr-amber-100: #3a2c10;

    /* Zustände */
    --trr-ok:   #3fcf8e;
    --trr-warn: #f2a93b;
    --trr-hot:  #e5484d;

    /* Flächenwerte unverändert aus rbTagger übernommen */
    /* Dieses Portal ist dunkel -- und sagt es dem Browser.
       ---------------------------------------------------------------------
       Ohne diese Zeile haelt Chrome auf Android die Seite fuer eine, die
       noch nachgedunkelt werden muss ("Auto Dark Theme"), und dreht auf
       eigene Faust an den Farben. Getroffen hat es die Kerben der
       Eintrittskarten: Sie sind in der Farbe der Seite gezeichnet und wurden
       zu weissen Punkten am Kartenrand.

       Nebenbei faerbt sie auch das, was der Browser selbst zeichnet --
       Auswahllisten, Bildlaufleisten, Datumsfelder. Die standen bisher
       hell in einer dunklen Seite. */
    color-scheme: dark;

    --trr-cream:    #14161a;   /* --bg-deck  */
    --trr-paper:    #1c1f25;   /* --bg-panel */
    --trr-row:      #22262d;   /* --bg-row   */
    --trr-line:     #2e343d;   /* --line     */
    --trr-ink:      #d9dee6;   /* --text     */
    --trr-ink-soft: #a8b1bd;   /* --text-dim */

    /* Warum der gedämpfte Ton so hell ist.
       ---------------------------------------------------------------------
       Er stand auf #79828e und kam damit auf 4,2:1 auf Panelgrund — der
       Mindestwert für Fließtext, knapp gerissen. Das ist ein Boden und kein
       Ziel, und er trug den größten Teil des Fließtextes: 241 Stellen riefen
       ihn, --trr-ink nur 72. Der Hilfston war zum Normalfall geworden und
       der Textton zur Ausnahme — deshalb wirkte die Seite grau, obwohl der
       kräftige Ton die ganze Zeit da war.

       Jetzt 7,0:1 auf Reihengrund, 7,6:1 auf Panel, 8,4:1 auf Deck.

       Nach oben bleibt bewusst Luft bis --trr-ink: Helle Schrift auf dunklem
       Grund blüht bei getrübter Linse aus, und das trifft genau die älteren
       Leser, für die diese Änderung gemacht ist. Deshalb ist in dieser
       Palette weder der hellste noch der dunkelste Wert ein Extrem — kein
       reines Weiß, kein reines Schwarz. */

    /* War die Zwischenstufe zwischen ink und ink-soft. Diese Lücke gibt es
       nicht mehr, seit ink-soft selbst über 7:1 liegt — der Ton war mit
       5,0:1 sogar heller als der, den er ergänzen sollte. Der Name bleibt,
       weil drei Stellen ihn rufen; er zeigt jetzt dorthin. */
    --trr-ink-quiet: var(--trr-ink-soft);

    /* Schriftfarbe auf der Leitfarbe. Die Fläche ist der helle Markenton,
       dort trägt nur dunkle Schrift — Weiß käme auf 2,7:1. */
    --trr-on-primary: #08222a;

    /* Die Schriftfarbe in der Leiste. Die Flaeche selbst ist schwarz und
       durchscheinend und steht deshalb nicht mehr hier, sondern dort, wo
       sie mit dem Weichzeichner zusammen gesetzt wird -- die beiden
       gehoeren zusammen und waeren getrennt nur halb verstaendlich. */
    --trr-nav-ink:   var(--trr-ink);

    /* Von Bootstrap genutzte Variablen überschreiben */
    --bs-body-bg:      var(--trr-cream);
    --bs-body-color:   var(--trr-ink);
    --bs-border-color: var(--trr-line);

    --bs-primary:     var(--trr-teal-700);
    --bs-primary-rgb: 2, 176, 167;

    /* Bootstrap 5.3 setzt Linkfarben über -rgb zusammen. Nur
       --bs-link-color zu überschreiben bleibt wirkungslos — dann bliebe
       jeder Link im Bootstrap-Blau stehen. */
    --bs-link-color:           var(--trr-teal-700);
    --bs-link-color-rgb:       2, 176, 167;
    --bs-link-hover-color:     var(--trr-teal-900);
    --bs-link-hover-color-rgb: 142, 231, 224;

    --bs-emphasis-color:  var(--trr-ink);
    --bs-secondary-color: var(--trr-ink-soft);

    /* Bootstrap setzt <code> auf ein kräftiges Magenta — das beißt sich
       mit der übrigen Palette. */
    --bs-code-color: var(--trr-teal-700);

    --bs-body-font-family: "Source Sans 3", system-ui, -apple-system, "Segoe UI", sans-serif;
    /* 17px statt 16. Der Wert stand hier bewusst auf 1rem, solange die
       kleinsten Stufen der Leiter auf 10 und 11 Punkt lagen: Den Grundtext
       anzuheben haette damals nur den Abstand nach unten vergroessert. Seit
       der Boden bei 13px liegt, gilt das nicht mehr — jetzt rueckt der
       Grundtext nach und die Spannweite bleibt trotzdem enger als vorher
       (13-17 statt 10-16).

       body setzt selbst keine Groesse; Bootstrap liest diese Variable. */
    --bs-body-font-size: 1.0625rem;
    --bs-body-line-height: 1.6;

    --trr-radius:    14px;
    --trr-radius-sm: 10px;
    --trr-shadow:    0 1px 2px rgba(0, 0, 0, .24), 0 8px 24px rgba(0, 0, 0, .28);
    --trr-shadow-sm: 0 1px 2px rgba(0, 0, 0, .28);
}
/* --------------------------------------------------------------- Grundlagen */

body {
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
    font-family: var(--bs-body-font-family);
    -webkit-font-smoothing: antialiased;

    /* Dieses Portal heisst "Rasenmaehertraktorrallyemeisterschaft".

       Ein Wort dieser Laenge passt auf einem Telefon in keine Spalte,
       und ohne die naechsten beiden Zeilen schiebt es die ganze Seite
       auseinander: Ein Rasterfach ist mindestens so breit wie sein
       laengstes unteilbares Wort, und der Rest der Seite folgt ihm.
       Genau das war auf 390 Punkten Breite zu sehen -- alles ragte
       rechts hinaus.

       Hier stand dazu "hyphens: auto". Das trennt aber nicht nur, was
       nicht passt, sondern jedes Wort am Zeilenende, wo die Sprache es
       erlaubt -- aus einem vierbuchstabigen Wort werden dann zwei und
       zwei, mitten in einer Zeile mit fuenf Woertern. Es sieht nach einer
       Zeitungsspalte aus und liest sich unruhig.

       overflow-wrap allein macht genau das, was gewollt ist: Es bricht
       ein Wort erst dann, wenn es sonst ueber den Rand liefe. Was in die
       Zeile passt, bleibt ganz.

       "manual" statt "none": Ein ausdrueckliches &shy; im Text soll
       weiterhin wirken. Es gibt derzeit keines -- aber wer eines setzt,
       meint es. */
    overflow-wrap: break-word;
    hyphens: manual;
}

h1, h2, h3, h4, h5, h6, .navbar-brand {
    font-family: "Bitter", Georgia, "Times New Roman", serif;
    font-weight: 600;
    letter-spacing: -.01em;
}

/* Sichtbarer Fokusrahmen — Tastaturbedienung darf nie im Blindflug enden. */
:focus-visible {
    outline: 3px solid var(--trr-teal-500);
    outline-offset: 2px;
    border-radius: 4px;
}

.btn:focus-visible,
.form-control:focus-visible {
    outline-offset: 1px;
}

/* Der Knopf im Dateifeld hat eckige Ecken -- so kommt er von Bootstrap
   (border-radius: 0), und er klebt mit negativen Raendern in der linken
   Ecke des Felds. In einem Feld mit runden Ecken sieht das aus wie ein
   Kasten, den jemand hineingeschoben hat.

   Erst folgte er nur der Rundung des Felds, blieb aber buendig. Das war
   halb: Links rund und rechts an einer Trennlinie eckig ergibt eine Form,
   die von keiner Seite ganz stimmt.

   Jetzt sitzt er im Feld, in der Rundung, die das Portal auch sonst fuer
   Buttons nutzt -- ein paar Bildpunkte kleiner, weil er selbst kleiner ist.
   Die Trennlinie faellt damit weg: Zwischen einem Knopf und dem Feld
   dahinter braucht es keinen Strich, der Abstand sagt es schon.

   Und der Abstand ist ringsum derselbe. Zuerst war er es nicht: links
   zwoelf Bildpunkte, oben und unten zwei -- der Knopf sah aus, als sei er
   nach rechts gerutscht. Ein Rand, der auf drei Seiten verschieden ist,
   faellt auf, auch wenn man nicht sagen kann, woran es liegt.

   Die Zahlen haengen deshalb aneinander: Das Feld hat .375rem Innenrand,
   der Knopf .125rem -- die Differenz von .25rem ist der Abstand oben und
   unten. Links dieselben .25rem, indem der negative Rand von -.75rem auf
   -.5rem zurueckgenommen wird. So bleibt das Feld auch genauso hoch wie
   die uebrigen Eingaben daneben. */
.form-control[type="file"]::file-selector-button {
    margin: -.125rem .75rem -.125rem -.5rem;
    padding: .125rem .75rem;

    border-inline-end-width: 0;
    border-radius: calc(var(--trr-radius-sm) - 3px);
    background: rgba(255, 255, 255, .09);
}

.form-control:focus {
    border-color: var(--trr-teal-600);
    box-shadow: 0 0 0 .2rem rgba(2, 176, 167, .35);
}

/* --------------------------------------------------------------- Schaltflächen */

.btn {
    --bs-btn-padding-y: .625rem;
    --bs-btn-padding-x: 1.25rem;
    --bs-btn-border-radius: var(--trr-radius-sm);
    --bs-btn-font-weight: 600;
    transition: transform .12s ease, box-shadow .12s ease, background-color .12s ease;
}

.btn-lg {
    --bs-btn-padding-y: .8rem;
    --bs-btn-font-size: 1.0625rem;
}

/*
 * Der Haupt-Button trägt die Fase — und zwar nur er.
 *
 * Darin liegt der Sinn: Wäre jedes Element geschnitten, wäre der Schnitt
 * wieder eine Konstante und damit unsichtbar, genau wie der überall gleiche
 * Radius vorher. Eine Seite hat höchstens eine Handlung, auf die es ankommt;
 * die bekommt die abweichende Form, alles andere bleibt rund.
 *
 * clip-path statt border-radius: Ein Radius kann nicht schneiden. Der
 * Rückfall ist unproblematisch — wo clip-path fehlt, ist der Button eben
 * rechteckig und funktioniert.
 */
.btn-primary {
    border-radius: 8px;
    clip-path: polygon(
        0 0,
        calc(100% - var(--trr-fase)) 0,
        100% var(--trr-fase),
        100% 100%,
        0 100%
    );

    --bs-btn-bg: var(--trr-teal-700);
    --bs-btn-border-color: var(--trr-teal-700);
    --bs-btn-hover-bg: var(--trr-teal-800);
    --bs-btn-hover-border-color: var(--trr-teal-800);
    --bs-btn-active-bg: var(--trr-teal-900);
    --bs-btn-active-border-color: var(--trr-teal-900);
    --bs-btn-disabled-bg: var(--trr-teal-600);
    --bs-btn-disabled-border-color: var(--trr-teal-600);

    /* Im Dunkelmodus ist die Fläche der helle Markenton -- dort trägt nur
       dunkle Schrift. Weiß auf #02b0a7 käme auf 2,7:1 und wäre zu wenig. */
    --bs-btn-color: var(--trr-on-primary);
    --bs-btn-hover-color: var(--trr-on-primary);
    --bs-btn-active-color: var(--trr-on-primary);
    --bs-btn-disabled-color: var(--trr-on-primary);

    box-shadow: var(--trr-shadow-sm);
}

/* Zweitrangige Aktionen: Umriss statt Fläche */
.btn-outline-secondary {
    --bs-btn-color: var(--trr-ink-soft);
    --bs-btn-border-color: var(--trr-line);
    --bs-btn-hover-bg: var(--trr-teal-050);
    --bs-btn-hover-color: var(--trr-teal-700);
    --bs-btn-hover-border-color: var(--trr-teal-600);
    --bs-btn-active-bg: var(--trr-teal-100);
    --bs-btn-active-color: var(--trr-teal-700);
    --bs-btn-active-border-color: var(--trr-teal-600);
}

.btn-primary:hover {
    transform: translateY(-1px);
    box-shadow: var(--trr-shadow);
}

.btn-primary:active {
    transform: translateY(0);
}

/* --------------------------------------------------- Schlichte Seiten (Login) */

.page-plain {
    display: flex;
    min-height: 100vh;
    min-height: 100dvh;
    flex-direction: column;
    /* Zarte Andeutung einer Wiese, ohne Bilddatei */
    background-image:
        radial-gradient(ellipse 80% 50% at 50% -10%, var(--trr-teal-100), transparent 70%);
}

/* min-height: 0 gehoert dazu: Ein Flex-Kind weigert sich sonst, unter die
   Hoehe seines Inhalts zu schrumpfen -- und dann rollt die Seite, obwohl
   oben und unten Luft ist. */
.plain-shell {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: clamp(1rem, 3vh, 2rem) 1rem clamp(.5rem, 2vh, 1rem);
}

/*
 * Weder Kasten noch Glas -- nur eine Spalte.
 *
 * Erst war es eine Karte mit Rahmen, dann eine Glasflaeche. Beides zog eine
 * Kante um die Anmeldung, und eine Kante mitten auf einer sonst leeren Seite
 * sieht aus wie ein Dialogfenster, das sich gleich schliessen laesst. Was
 * hier steht, ist aber die Seite selbst.
 *
 * Uebrig bleibt, was wirklich noetig ist: eine Breite, damit die Felder
 * nicht ueber den halben Bildschirm laufen.
 */
.plain-card {
    width: 100%;
    max-width: 26rem;
}

/* Inhaltsreiche Seiten -- Einrichtung, Registrierdaten, Zwei-Faktor.
   Auf schmalen Geräten unverändert; ab Tablet wird die Karte breiter, damit
   der Inhalt in die Fläche statt in die Länge geht. Sonst entsteht auf dem
   Desktop eine sehr hohe, schmale Säule mit viel ungenutztem Platz daneben. */
.plain-card.is-wide {
    max-width: 30rem;
}

@media (min-width: 768px) {
    .plain-card.is-wide {
        max-width: 46rem;
        padding: 2.5rem;
    }
}

/* Auf sehr kleinen Geraeten darf die Spalte bis dicht an den Rand. */
@media (max-width: 400px) {
    .plain-shell { padding: 1rem .75rem 0; }
}

.plain-brand-link {
    display: flex;
    justify-content: center;
    width: 100%;
    align-items: center;
    text-decoration: none;
}

/*
 * Die Marke steht in der Karte, gestapelt: Schriftzug oben, Zeichen
 * darunter.
 *
 * Nebeneinander brauchte sie die volle Fensterbreite, damit der
 * gezeichnete Slogan lesbar bleibt -- und stand dafuer ausserhalb der
 * Karte, ueber ihr in der Luft. Uebereinander teilt sie sich diese Breite
 * nicht mehr mit dem Zeichen: Der Schriftzug bekommt die ganze
 * Kartenbreite, und das Zeichen darunter seine eigene Zeile.
 */
/* Der Abstand nach unten haengt an der Fensterhoehe und nicht an der
   Breite: Was die Seite ueber die Kante schiebt, ist die Hoehe. Auf einem
   flachen Laptop-Bildschirm rueckt die Marke damit von selbst naeher an
   die Felder. */
.plain-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: clamp(1.25rem, 4vh, 2.75rem);
}

/*
 * Groesser als die Anmeldung darunter, und mit Absicht.
 *
 * Sie ist an das Fenster gebunden und nicht an die Anmeldeflaeche: Auf dem
 * Schreibtisch und auf dem Tablet ist rechts und links viel Platz, den die
 * Felder nicht brauchen -- die Marke schon. Auf dem Telefon greift dieselbe
 * Angabe von selbst, weil 88vw dort weniger ist als 42rem; da muss nichts
 * eigens umgeschaltet werden.
 */
.plain-brand .brand { --brand-breite: min(34rem, 86vw); }

.plain-head {
    margin-bottom: 1.5rem;
}

.plain-title {
    font-size: 1.5rem;
    margin-bottom: .375rem;
}

.plain-subtitle {
    color: var(--trr-ink);
    margin-bottom: 0;
}

.plain-aside {
    margin-top: 1.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--trr-line);
    text-align: center;
    color: var(--trr-ink);
    font-size: 1rem;
}

/*
 * Die beiden Nebenwege in einer Zeile.
 *
 * Untereinander waeren es zwei Absaetze und damit zwei Angebote; in einer
 * Zeile sind es zwei Ausweichmoeglichkeiten neben dem Hauptweg. Auf dem
 * Telefon brechen sie um, wenn es eng wird -- deshalb wrap und nicht
 * space-between.
 */
.plain-wege {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .4rem 1.5rem;
    margin-top: 1.5rem;
    font-size: .9375rem;
}

/* Hier stand .plain-weg-aus: ein Weg, den es noch nicht gab -- grau und
   ohne Verweis, weil "Passwort vergessen" nirgendwohin fuehrte. Es fuehrt
   jetzt hin, und damit ist die Regel eine Beschreibung von nichts. */

.plain-note {
    margin: 1.25rem 0 0;
    font-size: .875rem;
    line-height: 1.5;
    color: var(--trr-ink);
    text-align: center;
}

.plain-footer {
    padding: clamp(.75rem, 2vh, 1.5rem) 1rem clamp(.75rem, 2vh, 1.5rem);
    text-align: center;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* ------------------------------------------------------------- Formularblöcke */

.stack-form {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

.form-label {
    font-weight: 600;
    font-size: 1rem;
    margin-bottom: .375rem;
}

.label-optional {
    font-weight: 400;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.form-control {
    border-radius: var(--trr-radius-sm);
    border-color: var(--trr-line);
    background-color: var(--trr-paper);
    color: var(--bs-body-color);
    padding: .625rem .875rem;
}

.form-control-lg {
    padding: .8rem 1rem;
    font-size: 1.0625rem;
}

.form-text {
    color: var(--trr-ink);
    font-size: .875rem;
    margin-top: .375rem;
}

.form-section {
    padding: 1.25rem;
    background: var(--trr-teal-050);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
}

.form-section-title {
    font-size: .875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--trr-ink-soft);
    font-family: var(--bs-body-font-family);
    margin-bottom: 1rem;
}

/* Feld für Codes: breit gesetzt, damit Ziffern gut unterscheidbar sind */
.code-input {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 1.375rem;
    letter-spacing: .18em;
    text-align: center;
}

/* Passwortfeld mit Anzeigen-Schalter */
.password-field {
    position: relative;
}

.password-field .form-control {
    padding-right: 3rem;
}

.password-toggle {
    position: absolute;
    top: 50%;
    right: .5rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--trr-ink-soft);
    cursor: pointer;
}

.password-toggle:hover {
    background: var(--trr-teal-050);
    color: var(--trr-teal-700);
}

.password-toggle svg {
    width: 1.25rem;
    height: 1.25rem;
}

/* ------------------------------------------------------------ Schrittanzeige */

.step-track {
    display: flex;
    gap: .5rem;
    list-style: none;
    padding: 0;
    margin: 0 0 1.75rem;
    counter-reset: step;
}

.step-item {
    flex: 1;

    /* Ohne min-width darf ein Schritt nicht unter die Breite seines
       laengsten Wortes schrumpfen -- "WhatsApp" schob die Treppe dann auf
       dem Telefon ueber den Rand hinaus, und der siebte Schritt war
       abgeschnitten. */
    min-width: 0;

    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .5rem;
    text-align: center;
    position: relative;
}

/* Verbindungslinie zwischen den Schritten */
.step-item:not(:first-child)::before {
    content: "";
    position: absolute;
    top: 1rem;
    right: 50%;
    left: -50%;
    height: 2px;
    background: var(--trr-line);
}

.step-item.step-done::before,
.step-item.step-current::before {
    background: var(--trr-teal-600);
}

.step-marker {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    border: 2px solid var(--trr-line);
    background: var(--trr-paper);
    color: var(--trr-ink-soft);
    font-weight: 700;
    font-size: .9375rem;
}

.step-marker svg {
    width: .875rem;
    height: .875rem;
}

/* Eine Stufe ueber solid gibt es nicht -- also wird nachgeholfen.
   ------------------------------------------------------------------------
   Die Sharp-Leiter endet bei solid. Die uebrigen 33 Stile des Pakets sind
   eigene Handschriften (Slab, Jelly, Whiteboard, Pixel) und wuerden neben
   92 Sharp-Symbolen auffallen. Ein Rand in derselben Farbe legt sich statt
   dessen um die vorhandene Form und verdickt sie, ohne das Zeichen zu
   wechseln.

   stroke-width zaehlt in viewBox-Einheiten, nicht in Bildpunkten: Der Haken
   misst 512 Einheiten, dargestellt wird er mit 14 -- eine Einheit ist also
   rund 1/37 Bildpunkt. 32 Einheiten sind knapp 0,9 Punkte, je zur Haelfte
   nach innen und aussen.

   Der Wert ist erlaufen, nicht gerechnet: 64 war zu heftig, der Haken lief
   in seine eigene Luecke; 48 war immer noch zu viel. Wer nach oben will,
   geht diesen Weg bitte rueckwaerts und nicht weiter. Ohne die Regel bleibt
   das blosse sharp-solid.

   Keine Angabe zu linejoin und linecap: Die Vorgaben miter und butt halten
   die geraden Enden und den spitzen Winkel, von denen Sharp lebt. Rund
   waere hier der falsche Griff.

   Nur an diesen beiden Stellen, wo der Haken auf der Leitfarbe sitzt. Die
   uebrigen fuenfzehn Verwendungen stehen auf normalem Grund und brauchen
   weder den dunklen Ton noch die zusaetzliche Dicke. */
.step-marker svg,
.choice-check svg {
    stroke: currentColor;
    stroke-width: 32;
}

/* Der Haken traegt dunkel, nicht weiss.
   ------------------------------------------------------------------------
   Weiss auf teal-600 sind 2,1:1 -- unter den 3:1, die schon fuer blosse
   Symbole gelten, und der hellste Ton der Palette macht es am schlimmsten.
   --trr-on-primary kommt auf 7,9:1. Die Regel steht oben bei dem Token
   selbst; hier stand sie nur nicht. */
.step-done .step-marker {
    background: var(--trr-teal-600);
    border-color: var(--trr-teal-600);
    color: var(--trr-on-primary);
}

.step-current .step-marker {
    border-color: var(--trr-teal-700);
    color: var(--trr-teal-700);
    box-shadow: 0 0 0 4px var(--trr-teal-100);
}

.step-label {
    font-size: .8125rem;
    line-height: 1.3;
    color: var(--trr-ink-soft);
}

/* Der erklaerende Satz ueber jedem Schritt bekommt eine Breite.
   ------------------------------------------------------------------------
   Ohne Deckel laeuft er ueber die volle Panelbreite -- auf einem grossen
   Schirm sind das gut 180 Zeichen in einer Zeile. Angenehm sind 65 bis 75.
   Der Schaden entsteht nicht beim Lesen der Zeile, sondern am Ende: Das
   Auge springt zurueck und findet den naechsten Anfang nicht mehr sicher.
   Man liest dieselbe Zeile zweimal oder ueberspringt eine, und das trifft
   aeltere Leser zuerst.

   Gemessen in ch und nicht in rem: ch ist die Breite der Null in der
   laufenden Schrift, also genau die Einheit, um die es hier geht. Ein Wert
   in rem muesste jedes Mal nachgerechnet werden, wenn sich die Schriftgroesse
   aendert -- und die hat sich gerade geaendert. */
/* Mittig gestellt, aber nicht mittig gesetzt.
   ------------------------------------------------------------------------
   Zentrierter Fliesstext ist die eine Ausrichtung, die aeltere Augen
   bestraft: Der linke Rand ist der Anker fuer den Ruecksprung ans naechste
   Zeilenende, und zentriert steht er bei jeder Zeile woanders.

   width: fit-content loest beides auf einmal. Ein kurzer Satz -- und sechs
   der neun sind ein- bis zweizeilig -- macht den Block so schmal wie sich
   selbst, mittig gestellt steht er dann tatsaechlich in der Mitte. Ein
   langer stoesst an die 68ch, und dort brechen die Zeilen wieder buendig
   links um. Die Zentrierung ist also da, wo sie nichts kostet, und
   verschwindet, wo sie etwas kosten wuerde. */
.schritt-text {
    max-width: 68ch;
    width: fit-content;
    margin-inline: auto;
}

/* Die Ueberschrift darf mittig stehen -- eine Zeile hat keinen Ruecksprung,
   den man verlieren koennte. */
.schritt-titel {
    text-align: center;
}

.step-current .step-label {
    color: var(--trr-ink);
    font-weight: 600;
}

/* Auf dem Telefon nur die Zahlen.
   ------------------------------------------------------------------------
   Sieben Woerter nebeneinander auf 390 Punkten ueberlappten sich: "Fragen"
   lief in "WhatsApp", und lesbar war keines mehr.

   Auch das Wort des aktuellen Schrittes faellt weg, und es fehlt nicht:
   Direkt unter der Treppe steht die Ueberschrift des Schrittes, und die
   sagt dasselbe in gross. Zweimal dasselbe Wort untereinander waere auf
   dem kleinsten Schirm der schlechteste Platz dafuer.

   Versteckt und nicht entfernt -- ein Vorleser nennt es weiterhin. */
@media (max-width: 36em) {
    .step-label {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .step-track { margin-bottom: 1.25rem; }
}

/* --------------------------------------------------------------- Auswahlliste */

.choice-list {
    display: flex;
    flex-direction: column;
    gap: .625rem;
    border: 0;
    padding: 0;
    margin: 0;
}

.choice-item {
    display: flex;
    align-items: center;
    gap: .875rem;
    padding: 1rem 1.125rem;
    border: 2px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-paper);
    cursor: pointer;
    transition: border-color .12s ease, background-color .12s ease;
}

.choice-item:hover {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
}

/* Der eigentliche Radiobutton bleibt bedienbar und für Screenreader
   vorhanden, wird aber optisch durch die ganze Kachel ersetzt. */
.choice-item input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.choice-item:has(input:checked) {
    border-color: var(--trr-teal-700);
    background: var(--trr-teal-050);
}

.choice-item:has(input:focus-visible) {
    outline: 3px solid var(--trr-teal-500);
    outline-offset: 2px;
}

.choice-body {
    flex: 1;
    display: flex;
    align-items: center;
    gap: .625rem;
    flex-wrap: wrap;
}

.choice-name {
    font-size: 1.0625rem;
    font-weight: 600;
}

.choice-badge {
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    padding: .1875rem .5rem;
    border-radius: 999px;
    background: var(--trr-amber-100);
    color: var(--trr-amber-600);
}

.choice-check {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    border: 2px solid var(--trr-line);
    color: transparent;
    flex-shrink: 0;
}

.choice-check svg {
    width: .75rem;
    height: .75rem;
}

/* Derselbe Fall wie beim Schritt-Haken: dunkel auf der Leitfarbe.
   Weiss waeren hier 2,7:1, --trr-on-primary sind 6,1:1. */
.choice-item:has(input:checked) .choice-check {
    background: var(--trr-teal-700);
    border-color: var(--trr-teal-700);
    color: var(--trr-on-primary);
}

/* -------------------------------------------------------------- Zwei-Faktor */

.totp-setup {
    background: var(--trr-teal-050);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    padding: 1.25rem;
    margin-bottom: 1.5rem;
}

/* Ab Tablet stehen Anleitung und QR-Code nebeneinander. Untereinander
   ergäbe das eine sehr hohe Seite, obwohl links Platz frei bleibt. Der
   Warnhinweis läuft über beide Spalten. */
@media (min-width: 768px) {
    .totp-setup.has-qr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "main qr"
            "warn warn";
        column-gap: 1.75rem;
        align-items: start;
    }

    .totp-setup.has-qr .totp-main    { grid-area: main; }
    .totp-setup.has-qr .totp-qr      { grid-area: qr; margin-top: 0; }
    .totp-setup.has-qr .totp-warning { grid-area: warn; }
}

.totp-steps {
    margin: 0;
    padding-left: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: .875rem;
}

.totp-steps li {
    line-height: 1.5;
}

.totp-steps strong {
    display: block;
    margin-bottom: .125rem;
}

.totp-steps span {
    display: block;
    font-size: 1rem;
    color: var(--trr-ink-soft);
}

.totp-qr {
    margin: 1.25rem 0 0;
    text-align: center;
}

.totp-qr img {
    display: block;
    padding: .625rem;
    background: #fff;
    border-radius: var(--trr-radius-sm);
    /* Der QR-Code braucht auf Weiß stehen, damit Kameras ihn sicher lesen --
       auch wenn die Seite gerade dunkel dargestellt wird. */
    max-width: 100%;
    height: auto;
}

.totp-qr figcaption {
    margin-top: .5rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.totp-key {
    margin-top: 1.25rem;
}

.totp-key-label {
    display: block;
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--trr-ink-soft);
    margin-bottom: .375rem;
}

.totp-secret {
    display: block;
    padding: .75rem 1rem;
    background: var(--trr-paper);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 1rem;
    letter-spacing: .08em;
    /* Umbricht an den Leerzeichen zwischen den Viererblöcken statt mitten
       im Block -- so bleibt der Schlüssel abtippbar. */
    overflow-wrap: break-word;
    color: var(--bs-body-color);
}

.totp-hint {
    display: block;
    margin-top: .375rem;
    font-size: .875rem;
    color: var(--trr-ink);
}

.totp-warning {
    margin: 1.25rem 0 0;
    padding: .75rem .875rem;
    background: var(--trr-amber-100);
    border-radius: var(--trr-radius-sm);
    font-size: .875rem;
    line-height: 1.5;
    color: #f6dcae;
}

/* ------------------------------------------------------------------ Meldungen */

/*
 * Hier standen Bootstraps Alert-Kaesten: gruener Block mit gruenem Rand, und
 * damit die einzige Stelle im Portal, an der man dem Baukasten ansieht,
 * welcher es ist. Alles andere -- Pillen, Kacheln, Ticketzeilen -- lebt vom
 * dunklen Grund mit einem flachen Verlauf darauf.
 *
 * Jetzt dieselbe Machart: kein farbiger Block, sondern eine dunkle Zeile mit
 * einer farbigen Kante links und dem Zeichen in seinem Ton. Die Farbe sagt,
 * was los ist, ohne dass die halbe Seite die Farbe annimmt.
 */

/* So breit wie noetig, hoechstens so breit wie ein Text.
   ------------------------------------------------------------------------
   Ueber die volle Inhaltsbreite gezogen war "Das Bild ist geloescht." ein
   Balken mit vier Woertern darin und einem Meter Leere daneben. Eine
   Meldung ist kein Abschnitt, sondern eine Ansage.

   fit-content passt sie an den Satz an, 46rem deckelt die langen -- das ist
   dieselbe Grenze wie beim Fliesstext: etwa 75 Zeichen je Zeile.

   Mittig, weil sie zu keiner Spalte gehoert. Links angeschlagen sass sie
   unter einem zentrierten Kopfbereich, als waere sie liegen geblieben. */
.flash-stack {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .625rem;
    margin-bottom: 1.5rem;
}

.flash-stack .flash {
    width: fit-content;
    max-width: min(46rem, 100%);
}

.flash,
.notiz {
    --flash-farbe: var(--trr-teal-700);

    display: flex;
    align-items: center;
    gap: .875rem;
    padding: .8rem 1.1rem;

    /* Derselbe flache Verlauf wie ueberall: oben hell, unten dunkel. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .085),
            rgba(255, 255, 255, .03)
        );
    border-radius: var(--trr-radius-sm);

    /* Die Kante links traegt die Farbe -- als Schatten und nicht als
       border-left, damit sie die Rundung nicht aufschneidet. Dazu die
       uebliche Lichtkante oben. */
    box-shadow:
        inset 3px 0 0 var(--flash-farbe),
        inset 0 1px 0 rgba(255, 255, 255, .12),
        0 1px 3px rgba(0, 0, 0, .3);

    font-size: 1rem;
    color: var(--trr-ink);
}

/* Das Zeichen im eigenen Kreis, in der Farbe der Meldung. Frei daneben stand
   es auf der Flaeche und las sich wie ein Aufzaehlungspunkt. */
.flash-zeichen,
.notiz-zeichen {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;

    background: color-mix(in srgb, var(--flash-farbe) 18%, transparent);
    border-radius: 50%;
    color: var(--flash-farbe);
}

.flash-zeichen svg,
.notiz-zeichen svg { width: 1rem; height: 1rem; }

.flash-text,
.notiz-text { flex: 1 1 auto; min-width: 0; line-height: 1.45; }

.flash.ist-gut,     .notiz.ist-gut     { --flash-farbe: var(--trr-teal-700); }
.flash.ist-schlimm, .notiz.ist-schlimm { --flash-farbe: var(--trr-hot); }
.flash.ist-achtung, .notiz.ist-achtung { --flash-farbe: var(--trr-warn); }
.flash.ist-info,    .notiz.ist-info    { --flash-farbe: var(--trr-ink-soft); }

/* Der Unterschied zur Meldung: Eine Notiz steht fest auf der Seite und
   kommt nicht nach einem Seitenwechsel. Sie zieht deshalb nicht auf und
   nimmt die Breite, die sie bekommt. */
.notiz { margin-bottom: 1.25rem; }

/* Sie kommen nach einem Seitenwechsel und stehen sonst einfach da. Ein
   kurzes Aufziehen sagt: Das ist neu. */
.flash {
    animation: flash-auf .28s ease-out both;
}

@keyframes flash-auf {
    from { opacity: 0; transform: translateY(-.4rem); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .flash { animation: none; }
}

/* ------------------------------------------------------- Angemeldeter Bereich */

.page-app {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

/* ==========================================================================
   Die Marke

   Traktor, Schriftzug, Balken und Slogan sind ein Bauteil und nicht vier.
   Das Logo ist als Einheit entworfen: Der Balken gehoert zum Schriftzug, der
   Slogan unter den Balken, der Traktor davor. Wer das auseinandernimmt, hat
   kein Logo mehr, sondern Teile davon.

   Gesteuert wird die Marke ueber genau eine Angabe -- ihre Breite. Die Hoehe
   ergibt sich aus dem Seitenverhaeltnis, und die beiden Zeichnungen fuellen
   diese Hoehe aus. Andersherum -- Hoehe setzen, Breite laufen lassen -- war
   der erste Versuch, und dabei schob sich die Marke ueber ihren Platz
   hinaus, weil niemand ihr sagen konnte, wo Schluss ist.

   Gerechnet, damit die Zahl nachvollziehbar bleibt:
     Traktor    1014,32 : 615,36 =  1,649 Hoehen breit
     Abstand                        0,280
     Schriftzug 1010,67 : 127,45  =  7,929
     zusammen                       9,858 Hoehen breit
   Der Abstand steht deshalb als Anteil der Breite da: 0,280 / 9,858 = 2,84 %.
   ========================================================================== */

/*
 * Weiss, und zwar an jeder Stelle.
 *
 * Der Grund steht im Kopfbereich: Darunter liegt ein Foto, und jedes Foto
 * bringt eigene Farben mit. Ein farbiges Zeichen muesste sich gegen jedes
 * neue Bild neu behaupten; Weiss muss das nie. Und wenn die Marke dort
 * weiss ist, kann sie es auf der Anmeldeseite nicht plotzlich nicht sein --
 * eine Marke, die je nach Seite die Farbe wechselt, ist keine.
 *
 * Der Gewinn ist der zweite Teil davon: Die Leitfarbe wird frei fuer ihre
 * eigentliche Aufgabe. Tuerkis heisst jetzt "hier kannst du etwas tun" und
 * nicht mehr gleichzeitig "das ist die Traktorrallye".
 */
.brand {
    display: flex;
    color: #fff;

    /* Der einzige Button. Jede Stelle setzt ihn selbst. */
    width: var(--brand-breite, 100%);
}

/* Nebeneinander: Die Hoehe ergibt sich aus dem Seitenverhaeltnis, und die
   beiden Zeichnungen fuellen sie aus. */
.brand-reihe {
    align-items: stretch;
    gap: 2.84%;
    aspect-ratio: 9.858;
}

/*
 * Uebereinander: Schriftzug oben ueber die ganze Breite, Zeichen darunter.
 *
 * Hier gibt es kein gemeinsames Seitenverhaeltnis mehr -- die beiden
 * Zeichnungen stehen untereinander und bringen ihre eigene Hoehe mit. Das
 * Zeichen bekommt einen Anteil der Breite: ein Viertel, damit es neben dem
 * Schriftzug ein Zusatz bleibt und keine zweite Ansage wird.
 */
.brand-stapel {
    flex-direction: column;
    align-items: center;
    gap: clamp(.5rem, 2vh, 1.1rem);
}

.brand-stapel > svg:first-child {
    width: 100%;
    height: auto;
}

.brand-stapel > svg + svg {
    width: 27%;
    height: auto;
}

/* Ohne Traktor faellt er samt Abstand weg. */
.brand-reihe.ist-nur-wort {
    aspect-ratio: 7.929;
    gap: 0;
}

/* Beide Zeichnungen sind unmittelbare Kinder und fuellen die Hoehe aus. Sie
   laufen ueber currentColor -- wer die Marke umfaerben will, setzt color
   auf .brand, einmal statt zweimal. */
.brand > svg {
    display: block;
    flex: 0 0 auto;
}

.brand-reihe > svg {
    height: 100%;
    width: auto;
}

/*
 * Die Fase — das Formmotiv des Portals.
 *
 * Es ist nicht erfunden, sondern aus der Wortmarke abgelesen: Die Enden von
 * T, R, A und K sind schräg angeschnitten, nicht rund und nicht stumpf. Ein
 * einzelner 45°-Schnitt an einer Ecke greift das auf.
 *
 * Warum überhaupt: Runde Ecken sind nicht falsch, aber wenn Karte, Button,
 * Eingabefeld und Abzeichen denselben Radius tragen, entsteht der Blick, den
 * jede zweite Seite hat. Der Ausweg ist nicht "alles spitz" — mit dieser
 * geometrischen Schrift kippte das ins Kalte —, sondern Radius als System:
 * große Flächen großzügig rund, das eine Bedienelement, auf das es ankommt,
 * geschnitten.
 */
:root {
    --trr-fase: 9px;
}

/*
 * Die Leiste liegt über der Seite, nicht davor.
 *
 * Schwarz und durchscheinend mit Weichzeichner: Damit läuft das Bild des
 * Kopfbereichs darunter hindurch und die Seite fängt nicht mit einer Kante
 * an. Schwarz und nicht der Papierton -- ein aufgehelltes Grau über einem
 * Foto wird zu einem milchigen Streifen, und man sieht dem Bild dann an,
 * dass etwas darüber liegt. Schwarz sieht man nur an, dass es dunkler wird.
 *
 * Der Weichzeichner ist Zierde und keine Voraussetzung: Wo er fehlt, bleibt
 * das Schwarz, und darauf ist die Schrift ohnehin gerechnet.
 */
:root {
    --nav-hoehe: 4rem;
}

@media (min-width: 62em) {
    :root { --nav-hoehe: 4.75rem; }
}

.app-navbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1035;

    height: var(--nav-hoehe);
    padding-block: 0;

    background: rgba(0, 0, 0, .62);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    border-bottom: 1px solid rgba(255, 255, 255, .07);
    box-shadow: none;
}

/*
 * Volle Fensterbreite und nicht die Inhaltshülle.
 *
 * Der Traktor gehört an den linken Rand und das Konto an den rechten --
 * unabhängig davon, wie breit der Inhalt darunter gerade ist. Mit der Hülle
 * sprängen beide bei jedem Breitenwechsel nach innen, und die Leiste sähe
 * je nach Fenster anders aus.
 *
 * Weiterhin ein Raster mit drei Spalten und nicht eine Flex-Reihe: Nur so
 * stehen die Punkte in der Mitte des Fensters und nicht dort, wohin der
 * linke Nachbar sie schiebt. minmax(0, 1fr) außen, damit die Seitenspalten
 * unter ihren Inhalt schrumpfen dürfen.
 */
.app-navbar > .navbar-innen {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 1rem;

    width: 100%;
    height: 100%;
    padding-inline: clamp(1rem, 2.5vw, 2.25rem);
}

/* Die Spalten werden ausdrücklich zugewiesen und nicht der automatischen
   Verteilung überlassen. Der Grund ist eine Falle, in die ich prompt
   getappt bin: Ein Element mit display:none belegt im Raster gar keine
   Spalte. Auf dem Telefon, wo die Punkte ausgeblendet sind, rutschte das
   Konto damit in die mittlere Spalte -- und stand mitten in der Leiste
   statt rechts. */
.app-navbar .navbar-brand { grid-column: 1; justify-self: start; }
.app-navbar .nav-oben     { grid-column: 2; justify-self: center; }
.app-navbar .navbar-tools { grid-column: 3; justify-self: end; }

.app-navbar .navbar-brand,
.app-navbar .nav-link {
    color: var(--trr-nav-ink);
}

/*
 * Der Traktor allein, in Weiß.
 *
 * Weiß und nicht im Markenton, aus demselben Grund, aus dem Tomorrowland
 * sein Zeichen weiß setzt: Darunter liegt ein Foto, und jedes Foto bringt
 * eigene Farben mit. Ein farbiges Zeichen müsste sich gegen jedes neue Bild
 * neu behaupten; Weiß muss das nie. Und damit wird die Farbe frei für ihre
 * eigentliche Aufgabe -- sie heißt jetzt "hier kannst du etwas tun" und
 * nicht mehr gleichzeitig "das ist die Traktorrallye".
 */
.app-navbar .navbar-brand {
    display: flex;
    align-items: center;
    min-width: 0;
    margin-right: 0;
    opacity: 1;
    color: #fff;
}

/*
 * Gut die Haelfte der Leistenhoehe.
 *
 * Als Flaeche reichte ein Drittel -- da war der Traktor ein satter Fleck
 * und ohnehin nicht zu uebersehen. Als Umriss besteht er nur aus Linien,
 * und die brauchen Flaeche, um als Form gelesen zu werden. Bei 30
 * Bildpunkten war er auf dem Telefon kaum noch zu erkennen; ab 40 steht
 * er. Ausgefuellt wirkte die Leiste damit nicht, weil ein Umriss auch bei
 * doppelter Groesse leichter bleibt als eine Flaeche.
 *
 * Der Strich wird hier gesetzt und nicht in der Datei. Das SVG ist
 * eingebettet, und eine CSS-Regel schlaegt das Attribut darin -- so kommt
 * dieselbe Zeichnung gross mit einer feinen Linie und klein mit einer
 * kraeftigen. Gemessen bei 26, 30 und 44 Bildpunkten mit fuenf Staerken:
 * Zwoelf laesst hier alle Formen stehen, ab zwanzig laeuft der
 * Kuehlergrill zu.
 */
.app-navbar .navbar-brand svg {
    display: block;
    width: auto;
    height: 2.25rem;
    stroke-width: 12;
}

@media (min-width: 62em) {
    .app-navbar .navbar-brand svg { height: 2.6rem; stroke-width: 10; }
}

/* ------------------------------------------------- Die Punkte oben */

.nav-oben {
    display: none;
    flex-direction: row;
    align-items: stretch;
    /* Luft zwischen den Punkten. Vorher standen sie mit .15rem fast
       aneinander, und in Versalien mit Sperrsatz wuerde daraus eine
       durchgehende Zeile ohne erkennbare Grenzen. */
    gap: 1.1rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Die Punkte erscheinen erst ab 992 Bildpunkten, und das ist gerechnet:
   Bei 720 Huellenbreite belegen fuenf zweizeilige Punkte 378 und die
   Werkzeuge 64; fuer die Marke blieben 155, der Schriftzug ist aber 240
   breit -- er schob sich quer ueber die Punkte. Darunter tragen sie
   deshalb dasselbe Menue wie auf dem Telefon.

   Dieselbe Grenze wie beim Schriftzug: Dort springt die Huelle von 720
   auf 960, und erst damit ist Platz fuer beides. Eine Grenze statt
   zweier -- was zusammen passen muss, wechselt zusammen. */
@media (min-width: 62em) {
    .nav-oben { display: flex; }
}

/*
 * Kein Kasten hinter dem Punkt, nur der Balken darunter.
 *
 * Vorher lag hinter dem laufenden Punkt eine Flaeche mit oben runden und
 * unten harten Ecken -- eine Form, die sich nicht entscheidet, ob sie ein
 * Reiter oder ein Button ist. Der Balken allein sagt dasselbe und sagt es
 * leiser. Was uebrig bleibt, ist Schrift und eine Linie; mehr braucht eine
 * Navigationsleiste nicht.
 */
/*
 * Versalien, gesperrt -- wie der Schriftzug.
 *
 * Das Logo ist in Grossbuchstaben gesetzt, und die Leiste steht
 * unmittelbar daneben. In gemischter Schreibung waren es zwei Handschriften
 * in einer Zeile. Der Sperrsatz gehoert dazu und ist keine Zierde: Versalien
 * ohne ihn stehen zu dicht, weil ihnen die Ober- und Unterlaengen fehlen,
 * an denen das Auge sonst die Woerter trennt.
 *
 * Kleiner gesetzt als vorher: Versalien wirken bei gleicher Punktgroesse
 * groesser als gemischte Schrift, und die Leiste soll eine Bank bleiben.
 */
.app-navbar .nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .25rem .55rem;
    white-space: nowrap;
    font-size: .875rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
}

/*
 * Der Balken unter dem laufenden Punkt.
 *
 * Rechts abgeschrägt: Damit wird aus einem Unterstrich ein Marker, der in
 * eine Richtung zeigt -- eine Bahn, keine Markierung. Das ist die ganze
 * "Action", die eine Navigationsleiste verträgt.
 *
 * Er faehrt beim Seitenaufbau einmal von links ein und steht dann still.
 * Bewegung bei der Ankunft ist Charakter; Dauerbewegung ist Unruhe, an der
 * man vorbeisehen muss. Ein mitgleitender Balken zwischen den Punkten
 * braeuchte ausserdem JavaScript und koennte beim Seitenwechsel gar nicht
 * gleiten -- jede Seite wird neu geladen.
 */
.app-navbar .nav-link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    background: currentColor;
    clip-path: polygon(0 0, 100% 0, calc(100% - 5px) 100%, 0 100%);
    transform: scaleX(0);
    transform-origin: left center;
    opacity: 0;
    transition: transform .26s cubic-bezier(.22, .8, .3, 1), opacity .26s ease;
}

.app-navbar .nav-link:hover,
.app-navbar .nav-link:focus-visible {
    color: #fff;
}

.app-navbar .nav-link:hover::after,
.app-navbar .nav-link:focus-visible::after {
    transform: scaleX(1);
    opacity: .35;
}

.app-navbar .nav-link.active {
    color: var(--trr-teal-500);
    font-weight: 600;
}

.app-navbar .nav-link.active::after {
    transform: scaleX(1);
    opacity: 1;
}

/* Wer Bewegung abbestellt hat, bekommt den Balken sofort und ohne Einfahrt. */
@media (prefers-reduced-motion: reduce) {
    .app-navbar .nav-link::after { transition: none; }
}

.nav-icon {
    width: 1.0625rem;
    height: 1.0625rem;
    flex-shrink: 0;
}

/*
 * Tablet: Symbol über der Beschriftung.
 *
 * Dort ist Breite knapp und Höhe reichlich, bedient wird mit dem Finger --
 * ein zweizeiliger Punkt ist größer zu treffen und braucht weniger Breite.
 * Ab 1200 Bildpunkten wieder einzeilig: Auf dem Desktop ist die Maus genau,
 * die Leiste breit, und ein gestapelter Punkt sähe aus wie eine hochskalierte
 * Telefon-App.
 */
@media (min-width: 62em) and (max-width: 74.9375em) {
    .app-navbar .nav-link {
        flex-direction: column;
        gap: .2rem;
        padding: .4rem .65rem .5rem;
        font-size: .875rem;
        line-height: 1.2;
    }

    .nav-icon {
        width: 1.25rem;
        height: 1.25rem;
    }
}

/* Der Manager-Zugang hebt sich ab — er führt in einen anderen Bereich. */
/* Der Manager-Zugang hebt sich über die Farbe ab und nicht über eine
   Fläche -- der Balken darunter nimmt sie ohnehin mit, weil er auf
   currentColor läuft. */
.nav-link-manager,
.nav-link-manager:hover,
.nav-link-manager.active {
    color: var(--trr-amber-500) !important;
}

/* Kein margin-left:auto mehr. Das war die Loesung fuer die alte Flex-Reihe
   und im Raster ein Fehler: Eine Spalte mit einem einzigen automatischen
   Rand faellt auf stretch zurueck -- der Kasten fuellte die ganze rechte
   Spalte, der Rand wurde null, und das Konto stand auf dem Telefon in der
   Mitte statt rechts. justify-self: end weiter oben erledigt es. */
.navbar-tools {
    display: flex;
    align-items: center;
}

/* Das Konto rueckt vom Paar ab.
   ------------------------------------------------------------------------
   Fragezeichen und Glocke sind zwei Zeichen derselben Art: klein, ohne
   Rahmen, beide oeffnen ein Fenster. Das Konto ist etwas anderes -- ein
   gerahmter Knopf mit Bild und Namen, und dahinter liegt ein Menue.

   In gleichem Abstand nebeneinander sahen die drei aus wie eine Reihe. Ein
   groesserer Abstand vor dem Konto macht aus einer Reihe zwei Gruppen, ohne
   dass ein Strich dazwischen muss. */
.account-dropdown { margin-left: .625rem; }

/* ------------------------------------------------------- Die Glocke

   Links vom Konto, mit der Zahl der offenen Punkte. Sie bleibt stehen, auch
   wenn nichts offen ist -- eine Glocke, die verschwindet, sobald alles
   erledigt ist, laesst einen beim naechsten Mal suchen, wo sie war. */

.glocke {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;

    /* Kein Ring mehr.
       ---------------------------------------------------------------------
       Hier stand einer, "wie beim Konto daneben": Ohne ihn sei die Glocke ein
       Zeichen, das frei in der Leiste steht, und neben einem gerahmten Button
       sehe das aus, als waere sie nur Schmuck.

       Der Gedanke war richtig, die Loesung nicht. Ein leerer Ring ist kein
       Knopf, sondern ein Rahmen um ein Zeichen -- und was hineinsollte, war
       zu duenn dafuer: erst ein "?", dann ein "i", beide ein, zwei Striche
       in viel Platz. Der Rahmen machte die Duenne erst sichtbar.

       Jetzt tragen die Zeichen selbst: Das Fragezeichen bringt seinen Kreis
       mit, die Glocke ist eine geschlossene Form, beide eine Stufe
       kraeftiger. Zwei Zeichen statt zweier Rahmen -- und die Leiste wird
       ruhiger, weil neben dem Konto nur noch eine gerahmte Form steht statt
       dreier.

       Die Flaeche von 2.5rem bleibt: Sie ist das Ziel fuer den Finger, und
       das hat mit dem Rahmen nichts zu tun. */
    border: 0;
    border-radius: 999px;
    color: var(--trr-nav-ink);
    background: transparent;

    transition: color .15s ease-in-out, background-color .15s ease-in-out;
}

/* Beim Darueberfahren eine Flaeche statt eines Rahmens: Sie sagt dasselbe --
   hier laesst sich klicken -- und nur dann, wenn jemand danach sucht. */
.glocke:hover,
.glocke:focus-visible {
    color: #fff;
    background: rgba(255, 255, 255, .1);
}

/* Ueber den Button und nicht allein ueber die Klasse.
   ------------------------------------------------------------------------
   Das svg traegt beide Klassen: "icon glocke-icon". Die Grundregel .icon
   steht weiter unten im Stylesheet und setzt 1em -- bei gleicher
   Spezifitaet gewinnt die spaetere. .glocke-icon allein war damit wirkungslos,
   und zwar seit jeher: Die Glocke war nie 1.1875rem gross, wie ihre Regel
   behauptete, sondern immer 1em. Aufgefallen ist es erst beim Nachmessen. */
.glocke .glocke-icon { width: 1.25rem; height: 1.25rem; }

/* Mit offenen Punkten wird die Glocke selbst heller. Sonst muesste man die
   Zahl lesen, um zu merken, dass da eine ist. */
.glocke.hat-offenes { color: var(--trr-amber-500); }

/* Das Fragezeichen ist leiser als die Glocke: Die meldet, was ansteht; es
   wartet, bis jemand danach sucht. Ein Angebot dieser Art darf man erst
   sehen, wenn man es braucht. */
.glocke.ist-hilfe { color: var(--trr-ink-soft); }

.glocke.ist-hilfe:hover,
.glocke.ist-hilfe:focus-visible { color: #fff; }

/* Die Zahl sitzt aussen an der Ecke und nicht im Kreis.

   Innen streifte sie den Ring: Beide sind rund, und zwei Rundungen, die sich
   auf ein paar Bildpunkte naeherkommen, sehen aus wie ein Druckfehler.
   Aussen schneidet sie ihn sauber -- und ihr eigener dunkler Ring haelt den
   Abstand. */
.glocke-zahl {
    position: absolute;

    /* An der Schulter der Glocke und nicht an der Ecke des Buttons.
       ---------------------------------------------------------------------
       Sie sass aussen am Ring, und der Ring war die Kante, die man sah. Ohne
       ihn ist der Button eine unsichtbare Flaeche von 2.5rem, das Zeichen
       darin misst 1.5rem -- die Zahl schwebte dadurch einen halben Zentimeter
       neben der Glocke und gehoerte zu nichts mehr.

       Jetzt sitzt sie an der Schulter der Glocke: so weit herein, dass die
       Flaeche des Buttons keine Rolle mehr spielt, und so weit heraus, dass
       sie den Koerper der Glocke nicht verdeckt. Nachgemessen und nicht
       geschaetzt -- eine Kachel weiter innen lag die Zahl mitten auf dem
       Zeichen. */
    top: .0625rem;
    right: .0625rem;

    min-width: 1.0625rem;
    padding: 0 .25rem;
    font-size: .8125rem;
    font-weight: 700;
    line-height: 1.0625rem;
    text-align: center;

    color: #1a1200;
    background: var(--trr-amber-500);
    border-radius: 999px;

    /* Ein dunkler Ring setzt die Zahl von der Glocke ab -- ohne ihn kleben
       Zahl und Zeichen aneinander. Halbdurchsichtig, weil die Leiste es auch
       ist: Darunter laeuft das Bild des Kopfbereichs hindurch. */
    box-shadow: 0 0 0 2px rgba(0, 0, 0, .55);
}

/* ------------------------------------- Der Hamburger und sein Blatt */

/*
 * Auf dem Telefon liegen Navigation und Konto zusammen hinter einem Button.
 *
 * Zusammen und nicht nebeneinander: Zwei Aufklapper auf einem
 * Telefonbildschirm sind einer zu viel. Wer das Menü öffnet, hat der Reihe
 * nach drei Fragen -- wer bin ich hier, wo kann ich hin, was ist mit meinem
 * Konto -- und in dieser Reihenfolge steht es im Blatt.
 */
.menu-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    border: 0;
    border-radius: 999px;
    color: var(--trr-nav-ink);
    background: transparent;
}

.menu-toggle:hover,
.menu-toggle:focus-visible {
    color: #fff;
    background: rgba(255, 255, 255, .08);
}

.menu-toggle svg { width: 1.25rem; height: 1.25rem; }

/* Sobald die Leiste die Punkte selbst traegt, ist der Button ueberfluessig
   und das Blatt bleibt zu. Dieselbe Grenze wie oben. */
@media (min-width: 62em) {
    .menu-toggle { display: none; }
}

/* Umgekehrt fällt auf dem Telefon der Konto-Aufklapper ganz weg -- er steckt
   im Blatt, und daneben wäre er ein zweiter Weg zum selben Ziel. Genau das
   heißt "zusammengeführt".

   Ganz weg und nicht nur unsichtbar gemacht: Ein Button mit pointer-events:
   none sähe abgeschaltet aus, bliebe aber mit der Tastatur erreichbar und
   ginge auf Eingabetaste auf. Ein Menü, das man nicht sieht, aber öffnen
   kann, ist schlimmer als keines. */
@media (max-width: 61.9375em) {
    .account-dropdown { display: none; }
}

.handy-menu {
    --bs-offcanvas-width: min(20rem, 84vw);
    --bs-offcanvas-bg: var(--trr-paper);
    --bs-offcanvas-color: var(--trr-ink);
    --bs-offcanvas-border-color: var(--trr-line);
}

.handy-menu-kopf {
    align-items: flex-start;
    border-bottom: 1px solid var(--trr-line);
}

.handy-menu-ich {
    display: flex;
    align-items: center;
    gap: .75rem;
    min-width: 0;
}

.handy-menu-name {
    display: block;
    font-weight: 600;
    line-height: 1.2;
}

.handy-menu-rolle {
    display: block;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.handy-menu-body { padding-top: .5rem; }

.handy-menu-liste {
    margin: 0;
    padding: 0;
    list-style: none;
}

.handy-menu-punkt {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: 100%;
    padding: .7rem .25rem;
    border: 0;
    background: none;
    color: var(--trr-ink);
    font-size: 1.0625rem;
    text-align: left;
    text-decoration: none;
}

.handy-menu-punkt:hover,
.handy-menu-punkt:focus-visible { color: var(--trr-teal-700); }

/* Derselbe abgeschrägte Balken wie in der Leiste, nur senkrecht: Er steht
   links am Punkt und zeigt nach unten. Dieselbe Aussage, dieselbe Form. */
.handy-menu-punkt.active {
    color: var(--trr-teal-700);
    font-weight: 600;
}

.handy-menu-punkt.active::before {
    content: "";
    position: absolute;
    left: 0;
    width: 3px;
    height: 1.75rem;
    background: currentColor;
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 calc(100% - 5px));
}

.handy-menu-liste li { position: relative; }

.handy-menu-punkt.is-manager { color: var(--trr-amber-500); }

/* Die Schrift des Konto-Menues.
   ----------------------------------------------------------------------
   Dieselbe wie in der Hauptleiste: klein, halbfett, gesperrt, in
   Versalien. Vorher stand dort die Fliesstextschrift des Portals, und das
   Menue las sich wie ein Absatz aus Verweisen -- obwohl es dasselbe tut
   wie die Leiste daneben und nur an einer anderen Stelle haengt.

   Gesperrt heisst hier etwas weniger als oben (.06em statt .1em): In der
   Leiste stehen vier Woerter nebeneinander, hier dreizehn untereinander,
   und "ZWEI-FAKTOR-ANMELDUNG" ist ohnehin lang genug. */
.dropdown-menu .dropdown-item {
    display: flex;
    align-items: center;
    gap: .65rem;

    /* Mehr Luft als Bootstrap vorgibt (.25rem oben und unten). Elf Zeilen
       in Versalien haben keine Ober- und Unterlaengen, an denen sich das
       Auge festhaelt -- sie stehen als gleich hohe Balken untereinander,
       und dann wirkt der enge Satz gestopft. */
    padding: .55rem 1.1rem;

    font-size: .875rem;

    /* Duenner als in der Leiste oben, und das ist Absicht: Dort stehen vier
       Woerter nebeneinander und muessen sich gegen ein Foto behaupten. Hier
       stehen elf untereinander auf ruhigem Grund -- halbfett wirkt dann wie
       elfmal "wichtig". 400 ist ausserdem das duennste, was die Schrift
       wirklich mitbringt; alles darunter wuerde der Browser selbst
       ausduennen, und das sieht man. */
    font-weight: 400;
    letter-spacing: .06em;
    text-transform: uppercase;
}

.dropdown-icon {
    width: 1.1rem;
    height: 1.1rem;
    flex-shrink: 0;
    opacity: .85;
}

/* Die Trennlinien bekommen dieselbe Luft mit: Sonst waere der Abstand
   zwischen zwei Gruppen kleiner als der innerhalb einer, und die
   Gruppierung saehe nach Zufall aus. */
.dropdown-menu .dropdown-divider {
    margin: .5rem 0;
}

/* Der Kopf bleibt Fliesstext: Dort steht ein Name, und ein Name gehoert
   nicht in Versalien. */
.dropdown-menu .dropdown-header {
    text-transform: none;
    letter-spacing: 0;
}

/* Der aktive Punkt im Konto-Menue.
   ----------------------------------------------------------------------
   Bootstrap faerbt ihn in sein eigenes Blau -- das einzige Blau im ganzen
   Portal, und ausgerechnet an der Stelle, die sagt "hier bist du". Statt
   einer Flaeche derselbe gedeckte Grund wie beim Ueberfahren, dazu der
   Markenton und ein etwas festerer Schnitt. */
.dropdown-menu .dropdown-item.active,
.dropdown-menu .dropdown-item:active {
    background: rgba(2, 176, 167, .12);
    color: var(--trr-teal-800);
    font-weight: 600;
}

.dropdown-menu .dropdown-item.active .dropdown-icon {
    color: var(--trr-teal-800);
}

.handy-menu-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
}

.handy-menu-trenner {
    margin: .75rem 0;
    border-color: var(--trr-line);
    opacity: 1;
}

/* Konto und Abmelden stehen kleiner: Sie sind seltener gemeint als die
   Ziele darüber, und das darf man sehen. */
.handy-menu-liste-klein .handy-menu-punkt {
    padding-left: 2rem;
    font-size: 1rem;
    color: var(--trr-ink-soft);
}

.handy-menu-liste-klein .handy-menu-punkt:hover { color: var(--trr-ink); }

.account-initials-lg {
    width: 2.75rem;
    height: 2.75rem;
    font-size: 1.125rem;
}

/*
 * Schaltflächen in der dunklen Leiste.
 *
 * Die Farben kommen über Bootstraps eigene Variablen und nicht über
 * einzelne Zustandsregeln. Der Grund ist ein Fallstrick: Bootstrap setzt
 * bei geöffnetem Dropdown und beim Drücken
 *
 *     color: var(--bs-btn-active-color)
 *
 * und definiert diese Variable im Basis-.btn gar nicht. Ohne Rückfallwert
 * wird die Angabe ungültig, und weil color vererbt wird, erbt die Schrift
 * den Ton des Umfelds. Das Symbol verschwand also genau in dem Moment, in
 * dem das Menü aufging.
 *
 * Wer nur :hover nachzieht, findet die Lücke nicht, denn sie zeigt sich
 * erst, wenn die Maus die Schaltfläche wieder verlässt. Deshalb hier alle
 * Zustände auf einmal über die Variablen, statt sie einzeln zu jagen.
 */
/*
 * Ohne Fläche im Ruhezustand.
 *
 * Die gefüllte Pille war dieselbe Unruhe wie der Kasten hinter den Punkten:
 * ein Element, das ständig sichtbar ist, obwohl es nur selten gebraucht
 * wird. Das Bild trägt die Erkennbarkeit schon allein -- ein runder Kopf
 * neben dem Namen ist unverwechselbar. Die Fläche kommt erst beim
 * Überfahren, also genau dann, wenn jemand hin will.
 */
/*
 * Das Konto sitzt in einer Pille, und zwar immer.
 *
 * Vorher war die Flaeche nur beim Ueberfahren da. Das ist genau falsch
 * herum: Eine Umrandung, die erst auf Beruehrung erscheint, sagt niemandem
 * vorher, dass da etwas anzufassen ist -- und auf einem Telefon gibt es
 * kein Ueberfahren. Sichtbar umrandet ist es ein Button, auch fuer den, der
 * die Seite zum ersten Mal sieht.
 *
 * Heller Rand statt Flaeche: Die Leiste liegt ueber einem Foto. Eine
 * gefuellte Pille waere dort ein Fleck, ein duenner Rand ist eine Kante.
 */
.btn-account {
    --bs-btn-color: rgba(255, 255, 255, .88);
    --bs-btn-bg: rgba(255, 255, 255, .06);
    --bs-btn-border-color: rgba(255, 255, 255, .22);

    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: rgba(255, 255, 255, .14);
    --bs-btn-hover-border-color: rgba(255, 255, 255, .38);

    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: rgba(255, 255, 255, .18);
    --bs-btn-active-border-color: rgba(255, 255, 255, .45);

    --bs-btn-focus-shadow-rgb: 255, 255, 255;

    border-width: 1px;
    border-style: solid;
    border-radius: 999px;
    padding: .25rem .875rem .25rem .3rem;

    /* Dieselbe Schreibung wie die Punkte daneben. */
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
}

/* Der Pfeil ist im Ruhezustand gedämpft. Er sagt "hier klappt etwas auf",
   und das muss man nicht die ganze Zeit rufen. */
.btn-account::after { opacity: .5; }
.btn-account:hover::after { opacity: 1; }

.account-initials {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.875rem;
    height: 1.875rem;
    border-radius: 50%;
    background: var(--trr-teal-500);
    color: var(--trr-on-primary);
    font-weight: 700;
    font-size: .9375rem;
}

/* Die Leiste liegt fest am oberen Rand und nimmt deshalb keinen Platz mehr
   ein. Der Inhalt haelt ihn sich selbst frei. */
.app-main {
    flex: 1;
    padding-block: calc(var(--nav-hoehe) + 2rem) 3rem;
}

/* Wo die Leiste zum Zusagen liegt, braucht der Inhalt darunter Platz --
   sonst verschwindet die letzte Zeile hinter ihr, und niemand merkt,
   dass dort noch etwas steht. */
body:has(.tunleiste) .app-main { padding-bottom: 7rem; }

/* Ausser dort, wo ein Kopfbereich steht -- der bringt den Abstand mit und
   laeuft absichtlich unter der Leiste hindurch. */
.app-main.hat-hero {
    padding-top: 2.5rem;
}


.page-head {
    margin-bottom: 1.75rem;
}

/* Der Kopf einer Eventseite: Name links, Zahlen rechts auf derselben Hoehe.

   Die Zahlen standen zwischen Titel und Reitern, ueber die ganze Breite. Das
   schob die beiden auseinander und sah aus, als sei die Leiste nachtraeglich
   dazwischengeschoben worden. Neben dem Namen gehoert sie sichtbar zu ihm --
   beide beschreiben dasselbe Event, der eine mit einem Wort, die andere mit
   Zahlen.

   Danach ein kleinerer Abstand als sonst: Die Navigation gehoert noch zum
   Kopf und faengt nicht neu an. */
/* Zustand und Kennzahlen als ein Block rechts im Kopf.
   ------------------------------------------------------------------------
   Der Zustand sass rechts in der Reiterleiste, und die wird voll: acht
   Punkte plus Zustand, und er am Rand, wo man ihn zuletzt sucht. Hier steht
   er ueber dem, was ohnehin sagt, wie es um das Event bestellt ist --
   rechtsbuendig, damit die Kante der Zahlen darunter weiterlaeuft. */
.event-kopf-rechts {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: .625rem;
}

.event-zustand {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
}

/* Der Stift ist ein Knopf ohne Knopfaussehen: Er gehoert zum Abzeichen und
   soll es nicht ueberstrahlen. Erst beim Ueberfahren wird er deutlich. */
.event-zustand-stift {
    display: inline-flex;
    padding: .25rem;
    border: 0;
    border-radius: var(--trr-radius-sm);
    background: transparent;
    color: var(--trr-ink-soft);
    cursor: pointer;
    transition: color .12s ease, background-color .12s ease;
}

.event-zustand-stift:hover,
.event-zustand-stift:focus-visible {
    color: var(--trr-teal-700);
    background: var(--trr-row);
}

/* Auf schmalen Schirmen steht der Kopf ohnehin untereinander -- dann auch
   dieser Block linksbuendig wie alles andere. */
@media (max-width: 47.9375em) {
    .event-kopf-rechts { align-items: flex-start; }
}

.event-kopf {
    display: flex;
    /* Unten buendig und nicht oben.
       -------------------------------------------------------------------
       Links stehen drei Zeilen, rechts eine Reihe Zahlen -- die beiden
       Bloecke sind verschieden hoch, und das aendert sich mit jedem Event:
       Wer kein Motto hat, hat eine Zeile weniger. Oben ausgerichtet endeten
       sie darum unterschiedlich weit ueber dem Strich, und der Kopf sah bei
       jedem Event anders geschnitten aus.

       Unten ausgerichtet haben beide denselben Abstand zur Linie. Was oben
       ueberhaengt, faellt nicht auf -- der Blick sucht die Kante, nicht den
       Anfang. */
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem 2.5rem;
    flex-wrap: wrap;

    /* Die Linie schliesst den Kopf ab. Kein Abstand darunter: Sie ist
       zugleich die Oberkante des Navigationsstreifens.

       Mit Abstand sah es aus wie zwei Striche, zwischen denen etwas
       vergessen wurde -- die Gruppenreihe klebte an der unteren Linie und
       schwebte vierundzwanzig Bildpunkte unter der oberen. Ohne Abstand,
       und mit gleichem Innenabstand oben wie unten, sind aus zwei Strichen
       die beiden Kanten eines Streifens geworden. */
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--trr-line);
    margin-bottom: 0;
}

/* Der Text darf schrumpfen, die Zahlen nicht: Eine umbrechende Zahlenleiste
   neben einem Titel liest sich wie ein Fehler. Erst wenn beide nicht mehr
   nebeneinander passen, rutscht sie unter den Titel -- dann aber ganz. */
.event-kopf-text {
    flex: 1 1 22rem;
    min-width: 0;

    /* „Rasenmaehertraktorrallyemeisterschaft" passt auf kein Telefon.
       Ein Wort, das nicht umbrechen darf, schiebt die ganze Seite breiter
       als den Bildschirm -- und dann laeuft alles andere rechts hinaus,
       auch was kurz genug waere. Lieber gebrochen als abgeschnitten.

       Gebrochen und nicht getrennt: overflow-wrap greift erst, wenn das
       Wort sonst ueberliefe. "hyphens: auto" stand hier auch und trennte
       jedes Wort am Zeilenende -- siehe die Begruendung bei body. */
    overflow-wrap: break-word;
    hyphens: manual;
}
/* min-width: 0 ist der entscheidende Teil.
   ----------------------------------------------------------------------
   Die Zahlenleiste scrollt auf dem Telefon waagerecht in sich selbst. Ein
   Flex-Element darf aber von Haus aus nicht schmaler werden als sein
   Inhalt -- und der ist bei einer Reihe ohne Umbruch die Summe aller
   Zahlen. Also schob sie den ganzen Kopf breiter als den Bildschirm, und
   Titel, Motto und alles darunter liefen rechts hinaus. */
.event-kopf .event-kpi { flex: 0 1 auto; min-width: 0; }

/* Titel, Motto, Termin -- drei Zeilen, die zusammengehoeren und deshalb eng
   stehen. Der voreingestellte Abstand unter der Ueberschrift wuerde sie
   auseinanderziehen. */
.event-kopf .page-title { margin-bottom: .125rem; }

/* Das Motto des Jahres. Es traegt den Markenton, weil es das einzige an
   diesem Kopf ist, das der Veranstalter sich ausgedacht hat -- der Name ist
   eine Bezeichnung, der Termin ein Datum. */
.event-kopf-motto {
    margin: 0;
    font-size: 1rem;
    color: var(--trr-teal-700);
}

.event-kopf-termin {
    margin: 0;
    font-size: .9375rem;
    color: var(--trr-ink-soft);
}


/* Unter etwa einem Tablet steht sie wieder links unter dem Titel: rechts
   ausgerichtet unter einer linksbuendigen Ueberschrift saehe sie verrutscht
   aus. */
@media (max-width: 61.9375em) {
    .event-kopf .event-kpi {
        flex-basis: 100%;
        justify-content: flex-start;
    }
}

.page-title {
    font-size: 1.75rem;
    margin-bottom: .25rem;
}

.page-subtitle {
    color: var(--trr-ink-soft);
    margin-bottom: 0;
}

.content-card {
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius);
    background: var(--trr-paper);
    box-shadow: var(--trr-shadow-sm);
}

.content-card .card-title {
    font-size: 1.0625rem;
    margin-bottom: 1rem;
}

/* ------------------------------------------------------------- Kleinteiliges */

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .75rem;
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--trr-ink);
}

.empty-icon {
    width: 2.5rem;
    height: 2.5rem;
    opacity: .45;
}

.member-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

.member-item {
    display: flex;
    align-items: center;
    gap: .75rem;
}

.member-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background: var(--trr-teal-100);
    color: var(--trr-teal-700);
    font-weight: 700;
    flex-shrink: 0;
}

.member-body {
    display: flex;
    flex-direction: column;
    line-height: 1.35;
}

.member-name {
    font-weight: 600;
}

.member-meta {
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.info-panel {
    background: var(--trr-teal-050);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    padding: 1.25rem 1.25rem 1.25rem 1rem;
    margin-bottom: 1.5rem;
    font-size: 1rem;
}

.info-panel > p:first-child {
    margin-left: .25rem;
    font-weight: 600;
}

.info-panel ul,
.info-panel ol {
    margin-bottom: 0;
    padding-left: 1.25rem;
    color: var(--trr-ink);
}

.info-panel li + li {
    margin-top: .5rem;
}

.info-panel code {
    background: var(--trr-paper);
    padding: .125rem .375rem;
    border-radius: 5px;
    border: 1px solid var(--trr-line);
    color: var(--trr-teal-700);
    font-size: .875em;
}

.status-dot {
    width: .75rem;
    height: .75rem;
    border-radius: 50%;
    margin-top: .5rem;
    flex-shrink: 0;
}

.status-dot-ok {
    background: var(--trr-ok);
    box-shadow: 0 0 0 4px var(--trr-teal-100);
}

/* ---------------------------------------------------- Was noch fehlt */

/*
 * Die Merkliste steht ueber allem anderen und sieht deshalb anders aus als
 * eine Karte: Sie ist keine Rubrik, sondern eine Ansprache. Ein duenner
 * Rahmen in Bernstein statt einer Flaeche -- laut genug, um vor dem
 * Herunterscrollen gelesen zu werden, leise genug, um nicht wie ein Fehler
 * auszusehen. Es ist ja nichts kaputt; es ist nur noch etwas zu tun.
 */
/* Der Kasten auf der Startseite ist weg -- die Liste steht jetzt im Fenster
   hinter der Glocke. Was blieb, sind die Zeilen darin: Sie sehen dort
   genauso aus, weil es dieselben Zeilen sind. */

.todo-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.todo-list > li + li { border-top: 1px solid rgba(242, 169, 59, .22); }

.todo-item {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .6rem .25rem;
    color: var(--trr-ink);
    text-decoration: none;
}

.todo-item:hover,
.todo-item:focus-visible { color: var(--trr-amber-500); }

.todo-icon {
    width: 1.125rem;
    height: 1.125rem;
    flex-shrink: 0;
    color: var(--trr-amber-500);
}

.todo-body { flex: 1 1 auto; min-width: 0; }

.todo-text {
    display: block;
    line-height: 1.3;
}

/* Wozu es gehoert, steht klein darunter: Bei drei Punkten aus zwei Events
   waere sonst nicht zu erkennen, welcher Betrag zu welchem Event gehoert. */
.todo-hint {
    display: block;
    font-size: .875rem;
    color: var(--trr-ink);
}

/* Draengend heisst: das Event ist in einer Woche. Fett und nicht rot --
   eine Anmeldung, die noch fehlt, ist kein Fehler. */
.is-urgent .todo-text { font-weight: 600; }

.todo-arrow {
    width: .875rem;
    height: .875rem;
    flex-shrink: 0;
    opacity: .45;
}

.todo-item:hover .todo-arrow { opacity: 1; }

/* ---------------------------------------------------- Die Statusleiste

   Dasselbe wie hinter der Glocke, nur in Kurzform und ohne Klick: "Zahlung
   offen · Goldkarte ungenutzt". Die Glocke muss man oeffnen, um sie zu
   lesen -- hier steht es einfach da.

   Der ganze Streifen ist der Button. Wer die Kurzform liest und mehr wissen
   will, klickt auf das, was er gerade liest, und nicht oben rechts auf ein
   Zeichen. */

.statusleiste {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1030;

    width: 100%;
    padding: 0;
    text-align: left;

    background: rgba(0, 0, 0, .82);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 0;
    border-top: 1px solid rgba(255, 255, 255, .09);
    color: var(--trr-ink);
    cursor: pointer;
}

.statusleiste:hover,
.statusleiste:focus-visible { background: rgba(0, 0, 0, .92); }

.statusleiste-innen {
    max-width: 68rem;
    margin: 0 auto;
    padding: .6rem 1.25rem;

    display: flex;
    align-items: center;
    gap: .75rem;
}

.statusleiste-icon {
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    color: var(--trr-teal-700);
}

.statusleiste.ist-dringend .statusleiste-icon { color: var(--trr-amber-500); }

/* Die Worte duerfen abgeschnitten werden, der Weg dorthin nicht. Auf dem
   Telefon passen selten mehr als zwei hinein -- wie viele es insgesamt
   sind, sagt die Zahl an der Glocke. */
.statusleiste-worte {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: .9375rem;
    color: rgba(255, 255, 255, .82);
}

.statusleiste-punkt {
    margin: 0 .4rem;
    color: rgba(255, 255, 255, .35);
}

.statusleiste-mehr {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .875rem;
    font-weight: 600;
    color: var(--trr-teal-700);
}

.statusleiste-pfeil { width: .75rem; height: .75rem; }

/* Wo sie liegt, braucht der Inhalt darunter Platz -- sonst verschwindet die
   letzte Zeile hinter ihr, und niemand merkt, dass dort noch etwas steht.
   Dieselbe Ueberlegung wie bei der Tunleiste. */
.app-main.hat-statusleiste { padding-bottom: 5.5rem; }

/* Auf dem Telefon fehlt rechts der Platz. Der Pfeil allein sagt dasselbe:
   Es geht weiter. */
@media (max-width: 34em) {
    .statusleiste-mehr { font-size: 0; gap: 0; }
    .statusleiste-pfeil { width: .875rem; height: .875rem; }
}

/* -------------------------------------------- Die Zahlen des Managers */

/*
 * Kein Kasten, sondern eine Leiste: Sie steht am Fuss der Startseite und
 * soll im Vorbeigehen gelesen werden. Drei Zahlen, jede ein Weg dorthin, wo
 * man etwas daran aendern kann.
 */
.manager-strip {
    margin-top: 1.5rem;
    padding-top: 1.15rem;
    border-top: 1px solid var(--trr-line);
}

.manager-strip-head {
    display: flex;
    align-items: baseline;
    gap: .6rem;
    margin: 0 0 .75rem;
}

.manager-strip-label {
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.manager-figures {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 2.5rem;
}

.manager-figure {
    display: flex;
    flex-direction: column;
    gap: .1rem;
    color: var(--trr-ink);
    text-decoration: none;
}

a.manager-figure:hover,
a.manager-figure:focus-visible { color: var(--trr-teal-700); }

.manager-figure-value {
    font-family: "Bitter", Georgia, serif;
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.1;
}

.manager-figure-value svg { width: 1.25rem; height: 1.25rem; }

/* Die kleinere Zahl hinter dem Schraegstrich ist der Bezug, nicht die
   Nachricht -- "12" ist die Nachricht, "von 18" die Einordnung. */
.manager-figure-of {
    font-size: 1rem;
    font-weight: 400;
    color: var(--trr-ink-soft);
}

.manager-figure-label {
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* Kennzahlen in Kaesten, gruppiert nach der Frage, die sie beantworten.
   ------------------------------------------------------------------------
   Frei nebeneinander gestellt sahen die Zahlen aus wie eine Reihe -- und in
   einer Reihe liest man sie als eine Aufzaehlung von Gleichartigem. Sie sind
   aber nicht gleichartig: Vier zaehlen Familien, drei zaehlen Personen, und
   eine zaehlt beides nicht, sondern den Bestand. Der Kasten macht daraus drei
   Aussagen statt acht Zahlen.

   Die Kaesten wachsen gleichmaessig und brechen um, sobald 16rem nicht mehr
   nebeneinander passen -- auf dem Telefon steht dann einer unter dem anderen.
   Der dritte traegt nur eine Zahl und bekommt deshalb weniger Grundbreite;
   sonst zoege er Platz von den beiden, die etwas zu erzaehlen haben. */
/* Die Kennzahlen als Kreuztabelle.
   ------------------------------------------------------------------------
   Vorher standen hier fuenf Kaesten mit achtzehn Zahlen, von denen die
   meisten voneinander abgeleitet waren. Als Tabelle steht jede Kombination
   dort, wo sich Zeile und Spalte treffen: vier Zeilen tragen jetzt
   vierundzwanzig Zahlen auf weniger Hoehe.

   Klein gesetzt, und das ist Absicht -- hier steht ein Manager vor einer
   Auswertung und will sie in einem Blick haben. Die Schriftleiter des
   Portals gilt fuer die Teilnehmerseiten, wo aeltere Leute lesen; wer diese
   Werte einzeln braucht, findet sie in der Tabelle darunter. */
.kennzahlen {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: .75rem 2rem;

    margin: 0 0 1rem;
    padding: .75rem .875rem;

    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .06),
            rgba(255, 255, 255, .02)
        );
    border-radius: var(--trr-radius-sm);
    box-shadow: var(--trr-shadow-sm);
}

.kennzahl-tafel {
    border-collapse: collapse;
}

/* Ziffern in gleicher Breite: Sonst tanzen die Spalten, weil die 1 schmaler
   ist als die 8 -- und eine Tabelle, deren Zahlen nicht untereinander
   stehen, laesst sich nicht ueberfliegen. */
.kennzahl-tafel th,
.kennzahl-tafel td {
    padding: .2rem .85rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.kennzahl-tafel thead th {
    font-family: var(--bs-body-font-family);
    font-size: .6875rem;
    font-weight: 600;
    color: var(--trr-ink-soft);
    border-bottom: 1px solid var(--trr-line);
    padding-bottom: .35rem;
}

/* Die Wortspalte links: Sie benennt, sie zaehlt nicht -- also ruhiger und
   ohne den rechten Rand, den die Zahlen brauchen. */
.kennzahl-tafel tbody th {
    text-align: left;
    padding-left: 0;
    font-family: var(--bs-body-font-family);
    font-size: .75rem;
    font-weight: 400;
    color: var(--trr-ink-soft);
}

.kennzahl-tafel tbody td {
    font-family: "Bitter", Georgia, serif;
    font-size: .9375rem;
    color: var(--trr-ink);
}

.kennzahl-tafel tbody tr:first-child td { padding-top: .45rem; }

/* Die beiden Summenspalten stehen hervor -- nicht lauter, sondern nur nicht
   zurueckgenommen: Sie liegen auf einer eigenen Flaeche, die uebrigen nicht.
   Wer plant, liest "Aktiv"; wer den Bestand meint, "Gesamt". */
.kennzahl-tafel .ist-summe {
    background: rgba(255, 255, 255, .04);
    color: var(--trr-ink);
}

.kennzahl-tafel thead th.ist-summe { color: var(--trr-ink); }

/* Die Einladungen stehen daneben und nicht darunter.
   ------------------------------------------------------------------------
   Die Tabelle links braucht keine 600 von 1900 Punkten; rechts davon lag die
   Flaeche brach, und eine eigene Zeile darunter machte den Block hoeher,
   ohne den Platz zu nutzen. Drei Zeilen sind fast so hoch wie vier -- die
   beiden stehen damit fast buendig.

   Der Strich links ist die eigentliche Aussage: Hier wird nach einem anderen
   Merkmal gezaehlt, und die Zahlen der beiden Tafeln lassen sich nicht
   miteinander verrechnen. */
.kennzahl-neben {
    display: flex;
    flex-direction: column;
    gap: .35rem;

    /* Der Abstand liegt je zur Haelfte links und rechts des Strichs: Die
       Luecke der Reihe bringt die eine, dieser Innenabstand die andere. */
    padding-left: 2rem;
    border-left: 1px solid var(--trr-line);
}

.kennzahl-zusatz {
    font-weight: 400;
    color: var(--trr-ink-soft);
}

.kennzahl-wort {
    font-size: .6875rem;
    font-weight: 700;
    color: var(--trr-ink);
}

/* Je Anlass eine Schaltflaeche statt neun Texte untereinander.
   ------------------------------------------------------------------------
   Neun vollstaendige Nachrichten auf einer Seite waren eine Textwueste --
   man scrollt daran vorbei, statt zu lesen. Als Kacheln sieht man in einem
   Blick, welche Nachrichten es gibt und wer sie bekommt, und liest die eine,
   um die es gerade geht. */
.mail-knoepfe {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: .625rem;
    margin-top: 1.25rem;
}

.mail-knopf {
    display: flex;
    flex-direction: column;
    gap: .15rem;
    text-align: left;

    padding: .7rem .875rem;

    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    color: var(--trr-ink);
    cursor: pointer;
}

.mail-knopf:hover { border-color: var(--trr-teal-600); }

.mail-knopf:focus-visible {
    outline: 3px solid var(--trr-teal-500);
    outline-offset: 2px;
}

.mail-knopf-wort { font-weight: 600; font-size: .9375rem; }

/* Wer sie bekommt, steht auf der Kachel: Zwei der neun gehen an den Manager
   und nicht an die Familie, und das soll man sehen, bevor man klickt. */
.mail-knopf-an {
    font-size: .75rem;
    line-height: 1.25;
    color: var(--trr-ink-soft);
}

/* Die Nachricht im eigenen Rahmen. Sie bringt ein vollstaendiges Dokument
   mit eigenen Farben mit -- in der Seite wuerden sich die beiden gegenseitig
   einfaerben. Feste Hoehe mit eigenem Bildlauf: Eine Nachricht kann lang
   werden, und das Fenster soll nicht mitwachsen. */
.mail-rahmen {
    display: block;
    width: 100%;
    height: 26rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: #16181a;
}

/* Der Mailtext in der Vorschau -- so gesetzt, wie er ankommt.
   ------------------------------------------------------------------------
   Vorformatiert und nicht als Absaetze: alsText() setzt die Umbrueche schon
   dort, wo sie in der Nachricht stehen. Sie hier neu umbrechen zu lassen
   hiesse, etwas anderes zu zeigen als das, was der Empfaenger sieht -- und
   genau dafuer gibt es die Seite.

   Trotzdem umbrechend statt scrollend: Ein Mailtext ist Fliesstext, und eine
   Zeile, die man waagerecht schieben muss, liest niemand. pre-wrap behaelt
   die gesetzten Umbrueche und bricht nur die zu langen Zeilen zusaetzlich. */
.mail-vorschau {
    margin: 0;
    padding: .875rem 1rem;

    background: var(--trr-cream);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);

    font-family: var(--bs-body-font-family);
    font-size: .9375rem;
    line-height: 1.55;
    color: var(--trr-ink);

    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Notizfeld und Knopf in einer Zeile, auf schmalen Schirmen untereinander.
   Das Feld ist optional und traegt deshalb kein Wort ueber sich -- was
   hineingehoert, sagt der Platzhalter. */
.einladung-abhaken {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

.einladung-abhaken .form-control { flex: 1 1 16rem; }

.manager-figure.is-open .manager-figure-value { color: var(--trr-amber-500); }
.manager-figure.is-done .manager-figure-value { color: var(--trr-ok); }
.error-status {
    font-family: "Bitter", Georgia, serif;
    font-size: 3rem;
    font-weight: 700;
    line-height: 1;
    color: var(--trr-line);
    margin-bottom: .5rem;
}

/* -------------------------------------------------------------- Bewegung aus */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }

    .btn-primary:hover {
        transform: none;
    }
}

/* ==========================================================================
   Manager-Ebene
   ========================================================================== */

.page-head-actions {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.back-link {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    font-size: .9375rem;
    color: var(--trr-ink-soft);
    text-decoration: none;
    margin-bottom: .375rem;
}

.back-link:hover { color: var(--trr-teal-700); }
.back-link svg   { width: 1rem; height: 1rem; }

/* Das Band ueber dem Anmeldeweg: "Du meldest die Bergers an."
   ------------------------------------------------------------------------
   Deutlich und trotzdem kein Alarm. Es meldet keinen Fehler, sondern
   beantwortet eine Frage, die sich auf acht Seiten immer wieder stellt --
   deshalb der Markenton und kein Rot.

   Ganz oben und ueber die volle Breite: Es gilt fuer die ganze Seite und
   nicht fuer einen Kasten darauf. */
.auftrag-band {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-bottom: 1rem;
    padding: .625rem .875rem;
    border: 1px solid var(--trr-teal-600);
    border-radius: var(--trr-radius-sm);
    background: color-mix(in srgb, var(--trr-teal-600) 12%, transparent);
}

.auftrag-icon {
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
    color: var(--trr-teal-600);
}

.auftrag-satz { margin: 0; flex: 1; min-width: 0; }

/* Der Nachsatz leiser und auf dem Telefon in der zweiten Zeile: Er ist die
   Begruendung und nicht die Nachricht. */
.auftrag-zusatz {
    color: var(--trr-ink-soft);
    font-size: .875rem;
}

.auftrag-band form { margin: 0; flex: none; }

@media (max-width: 35.9375em) {
    .auftrag-band { flex-wrap: wrap; }
    .auftrag-satz { flex-basis: calc(100% - 2rem); }
    .auftrag-zusatz { display: block; }
    .auftrag-band form { margin-left: auto; }
}

.btn-icon {
    width: 1.0625rem;
    height: 1.0625rem;
    margin-right: .375rem;
    vertical-align: -.2em;
}

.form-actions {
    display: flex;
    gap: .75rem;
    flex-wrap: wrap;
}

/* Wo es vor und zurueck geht, stehen die Buttons rechts -- und "weiter" ist
   der letzte. Das ist die Leserichtung: Der naechste Schritt liegt vorn, der
   vorige hinter einem. Andersherum greift die Hand ins Leere. */
.form-actions.ist-rechts { justify-content: flex-end; }

/*
 * Buttonreihe eines Assistenten.
 *
 * Hier sind die Buttons keine Wahl zwischen Haupt- und Nebensache, sondern
 * eine Richtung: zurueck nach links, weiter nach rechts -- so, wie die
 * Schrittanzeige darueber auch laeuft. Deshalb steht "Weiter" hier rechts,
 * waehrend in einem Formular zum Bearbeiten das Speichern vorne steht.
 *
 * Im Dokument steht er trotzdem zuerst.
 * ----------------------------------------------------------------------
 * Seit auch "Zurueck" abschickt, sind beide Knoepfe im selben Formular --
 * und Enter in einem Feld loest den ersten aus. Stuende "Zurueck" vorn,
 * schickte ein Druck auf Enter im Telefonfeld die Familie einen Schritt
 * rueckwaerts.
 *
 * Also Weiter zuerst und die Reihe umgedreht: row-reverse macht rechts zum
 * Anfang, flex-start packt dort zusammen. Was im Dokument vorn steht,
 * erscheint damit rechts.
 *
 * Auf dem Handy gibt es kein Links und Rechts. Dort stapeln sich die
 * Knoepfe ueber die volle Breite, und der weiterfuehrende steht oben, wo
 * der Daumen ihn erreicht -- also in der Reihenfolge des Dokuments.
 */
.form-actions.ist-wizard {
    flex-direction: row-reverse;
    justify-content: flex-start;
}

@media (max-width: 575px) {
    .form-actions.ist-wizard {
        flex-direction: column;
        gap: .5rem;
    }

    .form-actions.ist-wizard .btn { width: 100%; }
}

/* Der Ausgang aus dem Anmeldeweg.
   --------------------------------------------------------------------------
   Abgesetzt und leiser als die beiden Buttons darueber: Er soll dastehen und
   nicht einladen. In der Reihe waere er der dritte gleich grosse Knopf, und
   auf dem Telefon -- wo die Reihe zur Spalte wird -- saehe er aus wie der
   naechste Schritt.

   Mittig unter der Reihe, weil er zu beiden gehoert und zu keinem: Links
   staende er unter "Zurueck" und liese sich damit verwechseln. */
.wizard-ausstieg {
    margin-top: 1.25rem;
    text-align: center;
    font-size: .9375rem;
}

.wizard-ausstieg a {
    color: var(--trr-ink-soft);
    text-decoration: none;
    border-bottom: 1px solid transparent;
}

/* Erst unter dem Zeiger wird die Linie sichtbar -- dieselbe Zurueckhaltung
   wie beim Absagen-Button: Der Weg hinaus ist eine Moeglichkeit und keine
   Empfehlung. */
.wizard-ausstieg a:hover,
.wizard-ausstieg a:focus-visible {
    color: var(--trr-ink);
    border-bottom-color: currentColor;
}

/* --------------------------------------------------------------- Kennzahlen */

.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 1rem;
}

.stat-tile {
    display: flex;
    flex-direction: column;
    gap: .125rem;
    padding: 1.125rem 1.25rem;
    background: var(--trr-paper);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius);
    box-shadow: var(--trr-shadow-sm);
}

.stat-value {
    font-family: "Bitter", Georgia, serif;
    font-size: 1.875rem;
    font-weight: 600;
    line-height: 1.1;
    color: var(--trr-teal-700);
    /* Tabellenziffern: die Zahlen sollen in einer Reihe nicht springen */
    font-variant-numeric: tabular-nums;
}

.stat-label {
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* ------------------------------------------------------------- Bereichsliste */

.tile-list {
    display: grid;
    gap: .625rem;
}

.tile {
    display: flex;
    align-items: center;
    gap: .875rem;
    padding: .875rem 1rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-paper);
    color: inherit;
    text-decoration: none;
    transition: border-color .12s ease, background-color .12s ease;
}

a.tile:hover {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
}

.tile.is-disabled {
    opacity: .55;
    cursor: default;
}

.tile-icon {
    width: 1.5rem;
    height: 1.5rem;
    flex-shrink: 0;
    color: var(--trr-teal-700);
}

.tile-body { display: flex; flex-direction: column; line-height: 1.35; }
.tile-name { font-weight: 600; }
.tile-hint { font-size: .875rem; color: var(--trr-ink-soft); }

/* ------------------------------------------------------------------- Suche */

.search-bar {
    display: flex;
    gap: .5rem;
    margin-bottom: 1.25rem;
    flex-wrap: wrap;
}

.search-bar .form-control { flex: 1 1 14rem; }

/* ------------------------------------------------------------------ Tabelle */

/* Breite Tabellen scrollen in sich selbst, damit die Seite nie seitlich
   ausbricht -- auf dem Handy sonst der übliche Ärger. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.data-table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--bs-body-color);
    --bs-table-border-color: var(--trr-line);
    margin-bottom: 0;
    min-width: 34rem;
}

.data-table thead th {
    font-family: var(--bs-body-font-family);
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--trr-ink-soft);
    border-bottom-color: var(--trr-line);
    white-space: nowrap;
}

.data-table tbody tr:hover { background: var(--trr-row); }
.data-table th, .data-table td { padding: .75rem; vertical-align: middle; }
.data-table th[scope="row"] { font-weight: 600; }
.data-table .num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.row-actions { text-align: right; white-space: nowrap; }

/* ------------------------------------------------------------- Statuszeichen */

.badge-state {
    display: inline-block;
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding: .1875rem .5rem;
    border-radius: 999px;
    white-space: nowrap;
}

/* Pillen mit einem Zeichen davor.
   ------------------------------------------------------------------------
   inline-flex statt inline-block, damit Punkt oder Haken neben dem Wort auf
   der Mittellinie sitzen statt auf der Grundlinie -- ein Punkt auf der
   Grundlinie haengt unter dem Wort. Nur wo eines steht: Die uebrigen Pillen
   bleiben inline-block, damit sie sich in einer Textzeile weiter wie Text
   verhalten. */
.badge-state:has(.badge-punkt),
.badge-state:has(.badge-zeichen) {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
}

.badge-punkt {
    width: .4rem;
    height: .4rem;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.badge-zeichen {
    width: .6875rem;
    height: .6875rem;
    flex-shrink: 0;
}

.badge-ok     { background: var(--trr-teal-050); color: var(--trr-ok); }
.badge-accent { background: var(--trr-teal-100); color: var(--trr-teal-700); }
.badge-warn   { background: var(--trr-amber-100); color: var(--trr-amber-600); }
.badge-quiet  { background: var(--trr-row);      color: var(--trr-ink-soft); }

/* Das Abzeichen fuer ein Event, das ausfaellt. Derselbe Ton wie bei einer
   schlimmen Meldung und beim Absage-Button -- wer ihn einmal gelernt hat,
   liest ihn hier ohne das Wort. Gemischt statt voll: Es steht neben dem
   Zustandsabzeichen, und zwei satte Flaechen nebeneinander streiten. */
.badge-stop   { background: color-mix(in srgb, var(--trr-hot) 16%, transparent);
                color: var(--trr-hot); }

/* Hinweis unter dem Namen statt daneben: direkt angehaengt lief er in die
   Unterstreichung des Links und wirkte gedraengt. Als eigene Zeile mit
   Punktmarke ist er ruhig lesbar und bleibt trotzdem zurueckhaltend. */
.cell-stack {
    display: flex;
    flex-direction: column;
    gap: .1875rem;
    align-items: flex-start;
}

.cell-title {
    font-weight: 600;
}

.hint-dot {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    font-size: .8125rem;
    font-weight: 400;
    line-height: 1.3;
    color: var(--trr-warn);
    white-space: nowrap;
}

.hint-marker {
    width: .375rem;
    height: .375rem;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.code-chip {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: .9375rem;
    letter-spacing: .05em;
    background: var(--trr-teal-050);
    border: 1px solid var(--trr-line);
    border-radius: 6px;
    padding: .1875rem .5rem;
    color: var(--trr-teal-700);
    white-space: nowrap;
}

/* -------------------------------------------------------------- Personenzeilen */

.person-rows { display: grid; gap: .75rem; }

.person-row {
    display: grid;
    grid-template-columns: 1fr 1fr 9rem auto;
    gap: .75rem;
    align-items: end;
    padding: .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    margin: 0;
}

@media (max-width: 767px) {
    .person-row {
        grid-template-columns: 1fr 1fr;
    }
    .person-field-head { grid-column: 1 / -1; }
}

@media (max-width: 480px) {
    .person-row { grid-template-columns: 1fr; }
}

.person-field-head {
    display: flex;
    align-items: center;
    padding-bottom: .5rem;
    white-space: nowrap;
}

.person-field-head .form-check-label {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    font-size: .9375rem;
    cursor: pointer;
}

.person-field .form-label { font-size: .875rem; }

/* ------------------------------------------------------------ Personenliste */

.person-list { display: grid; gap: .5rem; }

.person-entry {
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-paper);
    overflow: hidden;
}

.person-entry > summary {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .75rem .875rem;
    cursor: pointer;
    list-style: none;
    flex-wrap: wrap;
}

.person-entry > summary::-webkit-details-marker { display: none; }
.person-entry > summary:hover { background: var(--trr-row); }
.person-entry[open] > summary { border-bottom: 1px solid var(--trr-line); }

.person-summary { display: flex; flex-direction: column; line-height: 1.35; flex: 1 1 10rem; }
.person-name    { font-weight: 600; }
.person-meta    { font-size: .875rem; color: var(--trr-ink-soft); }

.person-badges {
    display: flex;
    gap: .375rem;
    flex-wrap: wrap;
    margin-left: auto;
}

.person-edit {
    padding: 1rem .875rem;
    display: grid;
    gap: 1rem;
}

/* Die Reihe der Schalter -- Hauptkontakt, Ticketgarantie, Supervisor.
   ==========================================================================
   Hier standen Kaestchen, und das Label war selbst ein Flex-Container: Kasten
   links, Text rechts. Damit landete auch die Erklaerung rechts *neben* dem
   Wort statt darunter -- ein `d-block` half nichts, denn als Flex-Kind wird
   ein Block wieder zur Spalte.

   Jetzt Bootstraps eigener Aufbau: Der Schalter steht links im Einzug, das
   Label daneben, und was darin ein Block ist, bleibt ein Block. Die
   Erklaerung sitzt damit unter ihrem Wort und nicht daneben.

   Schalter statt Kaestchen, weil es Zustaende sind und keine Auswahl: "hat
   Ticketgarantie" ist an oder aus, so wie eine Einstellung -- und im Portal
   sieht eine Einstellung ueberall so aus (siehe Mail, Rallye, Regeln). */
.check-row {
    display: flex;
    gap: 1rem 2rem;
    flex-wrap: wrap;
}

/* Zwei Formen leben hier nebeneinander, und das ist Absicht.
   --------------------------------------------------------------------------
   Die alte -- ein Kaestchen im Label -- steht noch bei den Shirt-Schnitten,
   den Umfragen und beim Nachfrage-Haken der Familie. Sie bleibt, wie sie
   war: Ohne `align-items: flex-start` rutschte das Kaestchen bei einem
   Text, der umbricht, in die Mitte der Zeile.

   Die neue -- Bootstraps .form-check mit Schalter -- steht dort, wo eine
   Erklaerung unter dem Wort haengt. Sie braucht das Gegenteil: kein Flex am
   Label, damit der Block darin ein Block bleibt. */
.check-row > .form-check-label {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    font-size: 1rem;
    cursor: pointer;
}

.check-row > .form-check-label > .form-check-input {
    margin-top: .25rem;
    flex-shrink: 0;
}

/* Jeder Schalter nimmt so viel Breite, wie sein laengster Satz braucht --
   und bricht als Ganzes um, statt seine Erklaerung allein zu lassen. */
.check-row .form-check {
    margin-bottom: 0;
    flex: 0 1 auto;
    max-width: 22rem;
}

.check-row .form-check .form-check-label {
    font-size: 1rem;
    cursor: pointer;
}

/* Die Erklaerung eine Spur enger unter ihr Wort: Der Zeilenabstand des
   Fliesstextes laesst sie sonst wie einen eigenen Absatz aussehen. */
.check-row .form-check-label .form-text {
    margin-top: .125rem;
    line-height: 1.35;
}

.add-person-form { margin-top: .5rem; }

/* ---------------------------------------------------------------- Einladung */

.copy-source {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: .9375rem;
    line-height: 1.6;
    background: var(--trr-row);
}

textarea.copy-source { resize: vertical; }

.copy-actions { margin-top: .75rem; }

.copy-inline {
    display: flex;
    gap: .5rem;
    flex-wrap: wrap;
}

.copy-inline .form-control { flex: 1 1 12rem; }

.btn.is-copied {
    --bs-btn-bg: var(--trr-ok);
    --bs-btn-border-color: var(--trr-ok);
    --bs-btn-hover-bg: var(--trr-ok);
    --bs-btn-hover-border-color: var(--trr-ok);
    --bs-btn-color: #fff;
    --bs-btn-hover-color: #fff;
}

.invite-qr { margin: 0; }

.invite-qr img {
    display: block;
    margin: 0 auto;
    padding: .75rem;
    /* Immer auf Weiß -- Kameras lesen invertierte QR-Codes unzuverlässig. */
    background: #fff;
    border-radius: var(--trr-radius-sm);
    max-width: 100%;
    height: auto;
}

.invite-qr figcaption {
    margin-top: .75rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.detail-list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: .5rem 1rem;
    margin: 0;
    font-size: 1rem;
}

.detail-list dt { color: var(--trr-ink-soft); }
.detail-list dd { margin: 0; }

/* ----------------------------------------------------------------- Protokoll */

.log-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .625rem; }

.log-item { display: flex; flex-direction: column; line-height: 1.35; }

.log-action {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: .875rem;
    color: var(--trr-teal-700);
}

.log-meta { font-size: .8125rem; color: var(--trr-ink-soft); }

.badge-hint {
    background: var(--trr-amber-100);
    color: var(--trr-warn);
}

/* Ausgeblendete Person: sichtbar, aber sichtbar zurückgenommen. Ganz
   verstecken wäre eine Sackgasse -- dann gäbe es keinen Weg zurück. */
.person-entry.is-hidden {
    border-style: dashed;
    background: transparent;
}

.person-entry.is-hidden > summary {
    opacity: .6;
}

.person-entry.is-hidden > summary:hover {
    opacity: .85;
}

/* ==========================================================================
   Symbole

   Kommen aus public/assets/icons.svg, gebaut von bin/icons aus dem
   Font-Awesome-Paket. Farbe über currentColor, Größe über die Schriftgröße
   des Umfelds — so sitzt ein Symbol neben Text immer richtig.
   ========================================================================== */

.icon {
    width: 1em;
    height: 1em;
    /* Auf der Grundlinie leicht absenken, sonst schwebt das Symbol über
       dem Text. */
    vertical-align: -.125em;
    fill: currentColor;
    flex-shrink: 0;
}

.icon-lg { width: 1.5em;  height: 1.5em; }
.icon-xl { width: 2.25em; height: 2.25em; }

/* Seit alle Zeichen aus einem Guss sind -- sharp-light, einfarbig --,
   gibt es keine zweite Ebene mehr, die zuruecktreten koennte. Die
   Regeln fuer fa-primary und fa-secondary standen hier und griffen ins
   Leere.

   Die Klasse icon-duo bleibt: Sie steht in einem guten Dutzend
   Ansichten, und sie hat weiter eine Aufgabe -- sie faerbt das Zeichen
   in die Leitfarbe. Nur eben ganz statt in zwei Toenen. */
.icon-duo { color: var(--trr-teal-700); }

/* Fällt nur im Entwicklungsmodus an, wenn die Sprite-Datei fehlt. */
.icon-missing {
    display: inline-block;
    width: 1em;
    height: 1em;
    line-height: 1;
    text-align: center;
    color: var(--trr-hot);
    border: 1px dashed currentColor;
    border-radius: 3px;
    font-size: .75em;
}

/* Größenangaben nach der .icon-Grundregel wiederholen: gleiche Spezifität,
   also entscheidet die Reihenfolge. Ohne das würde .icon mit seinen 1em
   die großen Symbole zusammenstauchen. */
.empty-icon { width: 3rem;    height: 3rem;    opacity: .5; }
.tile-icon  { width: 1.75rem; height: 1.75rem; }
.nav-icon   { width: 1.0625rem; height: 1.0625rem; }
.btn-icon   { width: 1em;     height: 1em; margin-right: .375rem; }

/* Im Leerzustand darf das Symbol gross und ruhig wirken. */
.empty-icon.icon-duo { color: var(--trr-teal-600); }

/* ==========================================================================
   Atmosphäre

   Das Portal muss Batman, Winnetou, Paw Patrol, einen Kinoabend und eine
   Weinprobe gleichermaßen tragen. Deshalb kommt der Charakter hier aus
   Licht und Farbe, nicht aus Motiven — das Motto trägt später das
   Event-Bild, und nur dort.

   Zurückhaltend gehalten: Die Stimmung soll auffallen, wenn man darauf
   achtet, und verschwinden, wenn man arbeitet.
   ========================================================================== */

:root {
    /* Lichtschein hinter der Bühne */
    --trr-glow-cue:   rgba(2, 176, 167, .16);
    --trr-glow-warm:  rgba(242, 169, 59, .08);
    /* Körnung nimmt dem Verlauf das Plastikhafte */
    --trr-grain:      .055;
}

/* Feine Körnung als eingebettetes SVG — keine Bilddatei, wenige hundert
   Byte, und sie skaliert auf jedem Bildschirm. */
:root {
    --trr-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ------------------------------------------------- Anmeldung, Registrierung */

/*
 * Der Schein liegt auf einer eigenen, festen Ebene und nicht auf dem Body.
 *
 * Vorher stand er dort mit background-attachment: fixed. Ein Hintergrund am
 * body wandert aber auf die Zeichenflaeche des Dokuments, und "fixed"
 * bindet ihn dann an das Sichtfenster: Er fuellt genau eine Fensterhoehe,
 * darunter bleibt die nackte Hintergrundfarbe stehen. Auf einer Seite, die
 * hoeher ist als das Fenster, sah man deshalb unten eine Kante und darunter
 * einen schwarzen Streifen.
 *
 * Auf einer eigenen Ebene mit position: fixed gibt es das Problem nicht --
 * sie ist immer genau so gross wie das Sichtfenster und faellt deshalb
 * nirgends ab.
 */
.page-plain::after {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: -1;

    /* Drei Lichtquellen: ein kühler Schein oben, ein warmer Gegenpol unten
       rechts, ein leiser dritter links. Zusammen ergibt das Tiefe, ohne dass
       eine einzelne Farbe dominiert. */
    background-image:
        radial-gradient(ellipse 70% 45% at 50% -8%,  var(--trr-glow-cue),  transparent 72%),
        radial-gradient(ellipse 55% 40% at 92% 108%, var(--trr-glow-warm), transparent 70%),
        radial-gradient(ellipse 45% 35% at 4% 78%,   var(--trr-glow-cue),  transparent 75%);
}

/* Körnung als eigene Ebene darüber, ohne die Bedienung zu behindern. */
.page-plain::before {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    background-image: var(--trr-noise);
    opacity: var(--trr-grain);
    /* Hinter allem, was auf der Seite steht */
    z-index: 0;
}

.plain-shell,
.plain-footer {
    position: relative;
    z-index: 1;
}

/* ==========================================================================
   Die Uhr bis zum Event

   Sie steht im Kopfbereich, unter der Marke und noch auf dem Bild --
   deshalb ohne Kasten und ohne Flaeche. Was auf einem Foto liegt, soll
   darauf liegen und nicht davor stehen.

   Zurueckhaltend gehalten: Die Marke darueber ist die Ansage, die Uhr ist
   die Fussnote dazu. Waeren die Zahlen so gross wie der Schriftzug, haette
   der Kopfbereich zwei Hauptsachen und damit keine.

   Die Zahlen laufen in Tabellenziffern -- sonst huepft die ganze Zeile bei
   jedem Sekundenwechsel, weil eine 1 schmaler ist als eine 8. Das ist der
   Unterschied zwischen einer Uhr und einem Zucken.
   ========================================================================== */

.uhr {
    margin-top: clamp(1.5rem, 3.5vw, 2.5rem);
}

.uhr-felder {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    gap: clamp(.35rem, 1.6vw, 1rem);
}

.uhr-feld {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .35rem;
    min-width: 0;
}

.uhr-zahl {
    font-family: "Orbitron", "Bitter", Georgia, serif;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    font-size: clamp(1.35rem, .8rem + 2vw, 2.25rem);
    font-weight: 600;
    line-height: 1;
    letter-spacing: .02em;
    color: #fff;
    text-shadow: 0 2px 12px rgba(0, 0, 0, .65);
}

/* Der Doppelpunkt sitzt auf der Hoehe der Ziffern und nicht in der Mitte
   des ganzen Felds -- darunter steht schliesslich noch ein Wort. */
.uhr-punkt {
    font-family: "Orbitron", "Bitter", Georgia, serif;
    font-size: clamp(1.35rem, .8rem + 2vw, 2.25rem);
    font-weight: 400;
    line-height: 1;
    color: rgba(255, 255, 255, .45);
    text-shadow: 0 2px 12px rgba(0, 0, 0, .65);
}

.uhr-wort {
    font-size: clamp(.5rem, .44rem + .22vw, .625rem);
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .55);
    text-shadow: 0 1px 8px rgba(0, 0, 0, .7);
}

/* Was da eigentlich anfaengt. Die Zahlen sagen "bald", diese Zeile sagt
   "was" -- ohne sie waere die Uhr eine Behauptung ohne Gegenstand. */
.uhr-was {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: .3rem .6rem;
    margin: .95rem 0 0;
    font-size: .875rem;
    text-shadow: 0 1px 8px rgba(0, 0, 0, .7);
}

.uhr-titel {
    font-weight: 600;
    color: rgba(255, 255, 255, .92);
    text-decoration: none;
}

a.uhr-titel:hover,
a.uhr-titel:focus-visible {
    color: #fff;
    text-decoration: underline;
}

.uhr-wann {
    color: rgba(255, 255, 255, .6);
}

/* Angefangen. Das Skript setzt die Klasse, sobald die Uhr auf null steht --
   was daraus wird, entscheidet aber das Stylesheet und nicht das Skript. */
.uhr-felder.ist-da .uhr-zahl {
    color: var(--trr-teal-800);
}

/* ==========================================================================
   Der Kopfbereich

   Ein Bild ueber die volle Fensterbreite, die Marke darueber, und unten
   laeuft das Bild in den Seitenhintergrund aus. Die Leiste liegt darauf und
   ist durchscheinend -- das Bild beginnt also ganz oben und nicht erst
   darunter.
   ========================================================================== */

.hero {
    position: relative;
    isolation: isolate;

    display: flex;
    align-items: center;
    justify-content: center;

    /* Oben so viel Luft, wie die Leiste hoch ist, plus etwas Abstand --
       sonst klebte die Marke an ihrer Unterkante. */
    padding: calc(var(--nav-hoehe) + clamp(3rem, 8vw, 6.5rem)) 1.25rem clamp(4rem, 10vw, 8rem);
    min-height: clamp(26rem, 56vw, 44rem);

    text-align: center;
    overflow: hidden;
}

/* Die flache Fassung -- auf der Seite eines einzelnen Events.

   Zwei Drittel der Hoehe: Auf der Startseite ist das Bild der Auftritt und
   darf den Bildschirm fuellen. Hier hat die Seite darunter etwas zu sagen,
   und wer sie aufmacht, will nicht erst an einem Foto vorbeiscrollen, um zu
   erfahren, ob er angemeldet ist.

   Gerechnet wird an denselben Werten wie oben, nur mit zwei Dritteln davon.
   Eine eigene Zahl haette sich beim naechsten Anfassen von der anderen
   entfernt. */
.hero.ist-flach {
    min-height: clamp(17rem, 37vw, 29rem);
    padding: calc(var(--nav-hoehe) + clamp(2rem, 5vw, 4.25rem)) 1.25rem clamp(2.5rem, 6.5vw, 5.25rem);
}

.hero.ist-flach .hero-titel {
    font-size: clamp(1.6rem, 3.6vw, 2.5rem);
}

.hero.ist-flach .hero-zeile {
    margin-top: .7rem;
}
/* Ohne Bild ist der Kopfbereich flacher: Es gibt dann nichts zu zeigen,
   und leere Flaeche ist keine Gestaltung. */
.hero.ist-ohne-bild {
    min-height: 0;
    padding-block: calc(var(--nav-hoehe) + 2.5rem) 2.5rem;
}

/* Das Bild als Element und nicht als Hintergrund im Stil: Ein style-Attribut
   faellt unter style-src der Sicherheitsregel und wird stillschweigend
   verworfen. Das Bild waere weg, ohne Meldung. */
.hero-bild {
    position: absolute;
    inset: 0;
    z-index: -2;

    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 40%;
}

/* Die Tafel-Fassung: unscharf im Untergrund, scharf als Tafel darunter.

   Abgeschaut, weil es eine Frage loest, die wir auch haben: Ein Titelbild
   ueber die volle Breite muss beschnitten werden, sonst passt es nicht --
   und beschnitten ist es nicht mehr das Bild, das jemand ausgesucht hat.
   Hier steht es ganz da, und was links und rechts uebrig bleibt, fuellt
   dasselbe Bild unscharf. Es hoert damit nirgends sichtbar auf.

   Der Untergrund ist stark abgedunkelt: Er ist Untergrund und soll nicht
   mit der Tafel darueber um die Aufmerksamkeit streiten.

   Vergroessert, weil ein Weichzeichner an den Kanten ausfranst -- ohne
   scale liefe ringsum ein heller Saum. */

.hero-grund {
    position: absolute;
    inset: 0;
    z-index: -2;

    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 40%;

    filter: blur(3.5rem) saturate(1.3) brightness(.5);
    transform: scale(1.2);
}

/* Im Album ist der Untergrund das einzige Bild -- auf der Event-Seite liegt
   eine scharfe Tafel darauf, hier nicht. Mit derselben Abdunklung wurde
   daraus eine graue Flaeche: viel Platz, nichts darin.

   Weniger Unschaerfe, weniger Abdunklung, mehr Farbe. Erkennbar bleibt
   nichts -- es geht um die Farben des Abends, nicht um das Motiv. */
.hero.ist-verwischt .hero-grund {
    filter: blur(2.5rem) saturate(1.6) brightness(.85);
}

/* Keine feste Hoehe: Die Tafel bestimmt sie. Eine Mindesthoehe daneben
   waere ein zweiter Wert, der dasselbe zu sagen versucht. */
.hero.hat-tafel {
    min-height: 0;

    /* Knapp unter der Tafel: Was darunter kommt, gehoert noch zum Bild --
       die Highlights sind seine Bildunterschrift. Der uebliche Abstand
       liesse sie als eigenen Abschnitt erscheinen. */
    padding-bottom: clamp(.75rem, 1.5vw, 1.25rem);
}

/* Linksbuendig wie beim Vorbild: Ueber einer Tafel, die ihre eigene Kante
   hat, steht mittiger Text ohne Bezug -- er richtet sich an nichts aus.
   Ueber der linken Kante schon. */
.hero.hat-tafel .hero-inhalt {
    max-width: 68rem;
    text-align: left;
}

/* Ein abgesagtes Event verliert die Farbe -- und die Leuchtkraft.
   --------------------------------------------------------------------------
   Das Titelbild trägt das Thema des Jahres und macht Lust darauf. Über einer
   Absage ist das die falsche Musik, und man liest den Hinweis darunter erst,
   wenn man das Bild schon gesehen hat. Grau und blass erkennt man, bevor man
   ein Wort gelesen hat.

   Ganz ohne Farbe und nicht fast.
   --------------------------------------------------------------------------
   Hier stand grayscale(90%), mit der Begründung, ein Rest Farbe sehe nach
   einer Entscheidung aus statt nach einem kaputten Filter. Das war eine
   Erklärung für etwas, das man schlicht als Farbstich liest -- ein Bild,
   dem man ansieht, dass jemand etwas mit ihm vorhatte, aber nicht was. Ein
   Bild ist entweder farbig oder es ist es nicht.

   Die Leuchtkraft nimmt der Rest der Kette: weniger Deckung, weniger
   Kontrast. Das Motiv bleibt erkennbar -- man kommt ja her, um zu sehen,
   um welches Event es geht --, aber es tritt einen Schritt zurück.

   Zwei Regeln und nicht eine.
   --------------------------------------------------------------------------
   Der unscharfe Untergrund im Kopfbereich trägt schon einen Filter, und
   `filter` ersetzt immer die ganze Kette. Eine gemeinsame Regel für alle
   Bilder hätte ihm die Unschärfe genommen -- aus dem weichen Grund wäre ein
   scharfes, formatfüllendes Bild geworden. Also bekommt er seine Kette noch
   einmal, um das Grau ergänzt.

   saturate() fällt dabei weg: Nach grayscale() gibt es nichts mehr zu
   sättigen.

   Und ausdrücklich keine Deckkraft.
   --------------------------------------------------------------------------
   Verblassen über opacity wäre der kürzere Weg und brächte die Farbe durch
   die Hintertür zurück: Unter den Kacheln liegt --trr-teal-050, und das ist
   kein Grau, sondern ein dunkles Grün. Ein halbdurchsichtiges Graustufenbild
   davor hat wieder einen Farbstich -- und zwar genau den, den wir gerade
   herausgerechnet haben.

   Die ganze Arbeit macht deshalb die Filterkette: contrast() nimmt die
   Tiefe, brightness() das Licht. Was dahinterliegt, spielt keine Rolle
   mehr.

   Ein Filter und kein zweites Bild vom Server: Die Farbe wegzurechnen ist
   Sache der Anzeige. Wer die Absage zurücknimmt, hat sein Bild sofort
   wieder -- und in der Mediathek bleibt es farbig, denn dort sucht man
   eines aus. */
.hero.ist-grau .hero-bild,
.hero.ist-grau .hero-tafel img,
.event-card-media.ist-grau img,
.ev-media.ist-grau img {
    filter: grayscale(1) contrast(.7) brightness(.65);
}

.hero.ist-grau .hero-grund {
    filter: blur(3.5rem) grayscale(1) brightness(.35);
}

.hero-tafel {
    margin: clamp(1.75rem, 3.5vw, 3rem) 0 0;
}

.hero-tafel img {
    display: block;
    width: 100%;

    /* Nach oben begrenzt, damit ein hochformatiges Bild nicht den ganzen
       Bildschirm nimmt. Was darueber hinausginge, wird beschnitten -- bei
       einem Bild, das schon zu hoch ist, ist das die kleinere Suende. */
    max-height: clamp(16rem, 42vh, 30rem);
    object-fit: cover;

    border-radius: var(--trr-radius);
    box-shadow: 0 24px 60px -24px rgba(0, 0, 0, .85);
}
/*
 * Der Schleier, und zwar aus drei Lagen:
 *
 *   1. eine gleichmaessige Abdunklung, damit weisse Schrift auf jedem Bild
 *      steht und nicht nur auf den dunklen,
 *   2. ein Verlauf von unten, der das Bild in den Seitenhintergrund
 *      uebergehen laesst -- eine harte Kante waere ein Schnitt quer durch
 *      die Seite,
 *   3. ein Verlauf von oben, damit die Leiste auch ueber einem hellen
 *      Bildhimmel noch als Leiste zu erkennen ist.
 */
.hero-schleier {
    position: absolute;
    inset: 0;
    z-index: -1;

    background:
        linear-gradient(to bottom,
            rgba(0, 0, 0, .5) 0,
            rgba(0, 0, 0, .05) 24%,
            rgba(20, 22, 26, .12) 52%,
            rgba(20, 22, 26, .55) 76%,
            rgba(20, 22, 26, .92) 92%,
            var(--trr-cream) 100%),
        rgba(0, 0, 0, .18);
}

.hero.ist-ohne-bild .hero-schleier {
    background: none;
}

.hero-inhalt {
    position: relative;
    width: 100%;
    max-width: 62rem;
}

/* Hier hat die Marke ihren Platz. Der gezeichnete Slogan wird ab etwa 650
   Bildpunkten Gesamtbreite lesbar -- in der Leiste waeren es 240 gewesen,
   und genau deshalb steht sie hier und nicht dort. */
.hero-marke {
    display: block;
    color: #fff;
}

.hero-marke svg {
    display: block;
    width: min(46rem, 100%);
    height: auto;
    margin-inline: auto;
    filter: drop-shadow(0 2px 14px rgba(0, 0, 0, .55));
}

.hero-titel {
    margin: 0;
    font-size: clamp(1.9rem, 4.5vw, 3rem);
    font-weight: 700;
    color: #fff;
    text-shadow: 0 2px 14px rgba(0, 0, 0, .55);
}

.hero-zeile {
    margin: 1.1rem 0 0;
    font-size: clamp(1rem, 1.4vw, 1.15rem);
    color: rgba(255, 255, 255, .82);
    text-shadow: 0 1px 10px rgba(0, 0, 0, .6);
}

/* Die gesperrte Kleinzeile ueber der Marke -- dasselbe Muster wie sonst im
   Portal, nur auf Bild und deshalb heller. */
.hero .hero-kicker {
    margin-bottom: 1rem;
    color: rgba(255, 255, 255, .72);
}

.hero .hero-kicker::before {
    background: rgba(255, 255, 255, .5);
}

/* ------------------------------------------------------ Angemeldeter Bereich */

/*
 * Kein Schimmer mehr hinter dem Seitenkopf.
 *
 * Hier lag ein tuerkiser Lichtschein, und er lag genau an der Stelle, an
 * der das Kopfbild in den Seitenton uebergeht. Damit lief das Bild nicht
 * in eine Farbe aus, sondern in zwei -- und der Uebergang, der unsichtbar
 * sein soll, war als gruenlicher Streifen zu sehen. Der Schein bleibt auf
 * der Anmeldeseite, wo kein Bild darueber liegt.
 */

/* Kleiner Vorspann über dem Titel — nennt den Anlass, ohne ihn zu überschreien. */
.hero-kicker {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .14em;
    color: var(--trr-teal-700);
    margin-bottom: .625rem;
}

.hero-kicker::before {
    content: "";
    width: 1.5rem;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
}

/*
 * Der Gruss unter dem Bild, auf zwei Zeilen.
 *
 * Er stand ueber der Marke und ist dort weggekommen: Ein Foto, ein
 * Schriftzug ueber die halbe Fensterbreite -- und darueber eine Zeile, die
 * dem Leser sagt, wie er heisst. Der Kopfbereich ist der Auftritt, der
 * Gruss ist Hausordnung.
 *
 * Zwei Zeilen, weil es zwei Dinge sind: die Tageszeit im Idiom der uebrigen
 * Kleinzeilen des Portals, darunter die Anrede als ganzer Satz.
 */
/* Die Startseite so breit wie die Tafel auf der Event-Seite.

   Ueber die volle Fensterbreite waren die Banner fast zwei Meter lang und
   der Text darunter 180 Zeichen je Zeile. Dieselbe Breite heisst auch: Wer
   von hier auf ein Event klickt, sieht das Bild an derselben Stelle in
   derselben Groesse wieder. */
.start {
    max-width: 68rem;
    margin: 0 auto;
}

/* Dieselbe Breite wie der Einleitungstext auf der Event-Seite: 46rem sind
   etwa 75 Zeichen je Zeile, und das ist die Laenge, bei der man einen Text
   noch gern liest. Ueber die vollen 68rem waeren es 110.

   Mittig und nicht links: Der Gruss steht ueber einer Reihe Kacheln, die
   die ganze Breite nutzen -- links angeschlagen saehe er aus, als haette
   ihn jemand vergessen zu ruecken. */
.seiten-gruss {
    max-width: 46rem;
    margin: 0 auto clamp(2rem, 4vw, 3rem);
}

.seiten-gruss-text {
    margin: .9rem 0 0;
    font-size: 1rem;
    line-height: 1.6;
    color: var(--trr-ink);
}

.seiten-gruss-text p { margin: 0 0 .85rem; }
.seiten-gruss-text p:last-child { margin-bottom: 0; }

/* Die Zwischenüberschriften im Vorwort. Drei Abschnitte statt eines Blocks:
   woher es kommt, was es hier gibt, was gilt. Ohne die Marken liest sich das
   als ein langer Absatz, in dem die Hausordnung am Ende untergeht.

   Dieselbe kleine gesperrte Zeile wie über dem Gruß und über den Events --
   sie sagt hier wie dort: was jetzt kommt, gehört zusammen. */
.gruss-zwischen {
    margin-top: 1.6rem !important;
    margin-bottom: .5rem !important;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--trr-teal-700);
}

.seiten-gruss-zeit {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 .5rem;
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .14em;
    color: var(--trr-ink-soft);
}

.seiten-gruss-zeit::before {
    content: "";
    width: 1.5rem;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
}

.seiten-gruss-satz {
    margin: 0;
    font-family: "Bitter", Georgia, "Times New Roman", serif;
    font-size: clamp(1.25rem, 1.05rem + .8vw, 1.75rem);
    font-weight: 600;
    letter-spacing: -.015em;
    line-height: 1.2;
    color: var(--trr-ink);
}
@media (prefers-reduced-motion: reduce) {
    .page-plain::after { position: absolute; }
}

/*
 * Die Jahreszahl ueber einer Gruppe von Events.
 *
 * Sie erscheint nur, wenn die Liste mehr als ein Jahr umfasst. Eine
 * Ueberschrift, die nichts teilt, ist keine Ueberschrift, sondern eine
 * Zeile mehr.
 *
 * Die Zahl gross und in der Schrift der Ueberschriften, der Zusatz
 * daneben klein und gedeckt: "2027" allein sagt nicht, ob es noch weit
 * hin ist -- "im naechsten Jahr" schon.
 */
/* Die Regeln fuer .ev-jahr stehen jetzt weiter unten bei den Kacheln --
   gross und mittig, ohne Zusatz daneben. Hier standen sie doppelt, und
   zwei Regeln fuer dasselbe sind eine Falle beim naechsten Anfassen. */

/* Kaestchen und Schalter im Markenton. Bootstrap faerbt sie blau, und das
   ist die einzige Stelle im Portal, an der Blau vorkaeme. */
.form-check-input:checked {
    background-color: var(--trr-teal-700);
    border-color: var(--trr-teal-700);
}

.form-check-input:focus {
    border-color: var(--trr-teal-600);
    box-shadow: 0 0 0 .2rem rgba(2, 176, 167, .25);
}

/* --------------------------------------------------- Was es beim Event gibt

   Kaesten und keine Pillen: Zeichen, Titel, kleine Zeile. Pillen waren
   verschieden lang -- ein Wort neben einem halben Satz --, und eine Reihe
   aus ungleich langen Pillen liest sich als Unordnung. Events Kaesten
   stehen in einer Flucht.

   Sechs bis acht nebeneinander auf dem Schreibtisch: auto-fit mit 10rem
   Mindestbreite trifft das bei einer 1200er Huelle von selbst und passt
   sich nach unten an, statt eine feste Zahl zu erzwingen.

   Sie zeigen und fuehren nicht: keine Pfeile, kein Hover, keine
   Verweisfarbe. Was aussieht, als koennte man es anklicken, wird
   angeklickt. */

/* ------------------------------------------------------- Die Highlights

   Pillen: Zeichen links im Kreis, daneben Titel und eine kleine Zeile.

   Alle gleich breit, und zwar auch in der angebrochenen letzten Reihe --
   das war die Bedingung. Deshalb flex mit einer festen Breite in Prozent
   und nicht flex-grow: Waechst eine Pille, um die Reihe zu fuellen, ist sie
   breiter als ihre Nachbarn darueber. Mit fester Breite bleibt sie, wie sie
   ist, und justify-content rueckt den Rest in die Mitte.

   Die Breite rechnet den Zwischenraum heraus: Vier Pillen zu 25 Prozent
   plus drei Fugen waeren zusammen breiter als die Zeile, und die vierte
   fiele um.

   Weiss statt Tuerkis. Tuerkis traegt auf dieser Seite die Zahlen, die
   Buttons und die Tueren; noch eine tuerkise Reihe darueber waere zu viel
   von einer guten Sache. Weiss auf dem dunklen Grund liest sich als
   "gehoert zum Bild" -- und das tun die Highlights auch.

   Nicht breiter als das Bild darueber: Eine Reihe, die ueber die Kanten
   der Tafel hinausragt, laesst sie schmal aussehen. */

/* Die Ueberschrift traegt dieselbe Zeile wie der Kopfbereich, nur mittig:
   Sie gehoert zum Bild darueber und nicht zum Inhalt darunter. */
.event-leiste-kopf {
    /* flex statt des geerbten inline-flex: Nur ein Element ueber die ganze
       Breite laesst sich zentrieren. Als inline-flex waere es so breit wie
       sein Inhalt und stuende links. */
    display: flex;
    justify-content: center;
    margin: clamp(2rem, 4vw, 3.25rem) 0 1.25rem;
    color: rgba(255, 255, 255, .55);
}

/* Schmaler als die Tafel darueber. Gleich breit sah aus wie ein Kasten
   unter einem Kasten; ein Stueck schmaler laesst das Bild gross und die
   Pillen zur Bildunterschrift werden. Und die einzelne Pille wird dabei
   enger, was ihr guttut: Bei 17 Zeichen Text war die Haelfte leer. */
.event-leiste {
    list-style: none;
    margin: 0 auto clamp(3rem, 6vw, 5rem);
    padding: 0;
    max-width: 58rem;

    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .4rem;
}

.event-leiste-feld {
    flex: 0 1 calc(25% - .3rem);

    display: flex;
    align-items: center;
    gap: .85rem;
    padding: .65rem 1.25rem;

    /* Kein Rahmen: Ein Haarrahmen macht aus der Pille eine Kontur; sie
       soll eine Flaeche sein, die auf dem Bild liegt.

       Ein flacher Verlauf von oben hell nach unten dunkel, dazu eine
       Lichtkante oben und ein Hauch Schatten unten: So sieht die Pille
       aus, als laege sie auf der Seite statt in ihr. Eine Flaeche in
       einem Ton wirkte flach -- "trist" war das Wort dafuer.

       Der Verlauf ist bewusst schwach. Wo man ihn als Verlauf erkennt,
       ist er zu stark. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .105),
            rgba(255, 255, 255, .04)
        );
    border-radius: 999px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .14),
        0 1px 2px rgba(0, 0, 0, .25);
}

/* Ohne Kreis dahinter. Er war eine Ueberlegung wert und ist beim Ansehen
   durchgefallen: In einer Pille ist schon eine Rundung, und eine zweite
   darin macht daraus ein Abzeichen.

   Ein Hauch der Leitfarbe: Ganz in Weiss war die Pille grau in grau, ganz
   in Tuerkis waere sie ein Button. */
.event-leiste-icon {
    flex: 0 0 auto;
    width: 1.4rem;
    height: 1.4rem;
    color: var(--trr-teal-800);
}

.event-leiste-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.3;
}

/* Eine Zeile und nicht zwei: In einer Pille ist der Umbruch das, was die
   Form kaputtmacht -- die eine wird hoch, die anderen bleiben flach.
   Deshalb hier ausnahmsweise abgeschnitten mit Punkten. Wer den ganzen
   Titel lesen will, findet ihn im Programm weiter unten. */
.event-leiste-wort,
.event-leiste-zeile {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Versalien wie in der Leiste oben: Das Wort ist hier ein Schild und kein
   Satz. Die Zeile darunter bleibt gemischt -- zwei Zeilen in Versalien
   waeren ein Schild ueber einem Schild. */
.event-leiste-wort {
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: #fff;
}

.event-leiste-zeile {
    font-size: .8125rem;
    color: rgba(255, 255, 255, .58);
}
@media (max-width: 61.9375em) {
    .event-leiste-feld { flex-basis: calc(33.3333% - .34rem); }
}

@media (max-width: 47.9375em) {
    .event-leiste-feld { flex-basis: calc(50% - .25rem); }
}

/* Auf dem Telefon eine je Zeile. Zwei Pillen nebeneinander liessen vom
   Titel "Tischfussball" ein "Tischfu…" uebrig, und dann sagt die Pille
   nichts mehr. */
@media (max-width: 30em) {
    .event-leiste-feld { flex-basis: 100%; }
}
/* ==========================================================================
   Die Event-Seite auf dem Schreibtisch: Zahlenzeile und zwei Spalten

   Auf dem Telefon liest man die Seite von oben nach unten, und dort ist eine
   Spalte richtig. Auf einem 1400 Punkte breiten Fenster stand dieselbe
   Spalte in der Mitte, und man scrollte, um zu erfahren, was es hier
   ueberhaupt gibt -- obwohl rechts und links Platz war.
   ========================================================================== */

/* Ein Band und keine vier Kaesten.

   Vier gleich grosse Kaesten mit Rahmen sahen aus wie Formularfelder --
   "Pizza-Bestellung" war das Wort dafuer. Ein durchgehendes Band mit feinen
   Trennern liest sich als eine Aussage in vier Teilen, und genau das ist es:
   Wann, was es kostet, wie viele kommen, wie lange man noch Zeit hat.

   Die Trenner sind kein border, sondern der Untergrund, der durch eine
   Fuge von einem Punkt scheint. Ein border muesste je nach Umbruch links
   oder oben sitzen; die Fuge stimmt in jeder Anordnung von selbst.

   Das Tuerkis traegt hier die Zeichen und den oberen Rand -- mehr nicht.
   Es soll das Band vom uebrigen Grau abheben und nicht selbst gelesen
   werden. */

.event-kpi {
    list-style: none;
    margin: 0 0 1.25rem;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: .5rem;
}

.event-kpi-feld {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .8rem 1rem;
    background: var(--trr-paper);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
}

/* Was knapp wird, faellt auf: eine Frist, die morgen ablaeuft, ist keine
   Randnotiz. Dieselbe Farbe wie ueberall fuer "sieh hier hin". */
.event-kpi-feld.ist-warm {
    border-color: var(--trr-warn);
    color: var(--trr-warn);
}

.event-kpi-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
    color: var(--trr-ink-soft);
}

.event-kpi-feld.ist-warm .event-kpi-icon { color: var(--trr-warn); }

.event-kpi-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.25;
}

.event-kpi-wert {
    font-weight: 700;
    font-size: 1.0625rem;
    font-variant-numeric: tabular-nums;
    color: var(--trr-ink);
}

.event-kpi-feld.ist-warm .event-kpi-wert { color: var(--trr-warn); }

.event-kpi-wort {
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

/* Ein Button, der wie ein Verweis aussieht: Er oeffnet ein Fenster und
   fuehrt nicht auf eine Seite. Was aussieht wie ein Verweis, aber keiner
   ist, laesst sich nicht in einem neuen Reiter oeffnen -- und genau das
   versucht jemand frueher oder spaeter. */
.event-kpi-mehr {
    align-self: flex-start;
    margin-top: .2rem;
    padding: 0;
    background: none;
    border: 0;
    color: var(--trr-teal-700);
    font: inherit;
    font-size: .8125rem;
    font-weight: 600;
    text-decoration: underline;
    cursor: pointer;
}

.event-kpi-mehr:hover { color: var(--trr-teal-900); }

/* Anmeldung und "wer kommt" stehen im selben Kasten: erst, ob ich dabei
   bin, dann, wer sonst. Das ist eine Frage in zwei Schritten und nicht
   zwei Fragen -- der Strich trennt die Schritte und nicht die Kaesten. */
.event-signup-trenner {
    margin: 1.25rem 0;
    border: 0;
    border-top: 1px solid var(--trr-line);
    opacity: 1;
}

/* Die Absage als Textlink.

   Ein Button und kein a: Er oeffnet ein Fenster und fuehrt nicht auf eine
   Seite. Was aussieht wie ein Verweis, aber keiner ist, laesst sich nicht
   in einem neuen Reiter oeffnen -- und genau das versucht jemand frueher
   oder spaeter.

   Gedaempft und nicht in der Leitfarbe: Der Weg hier ist die Zusage. Die
   Absage soll erreichbar sein und nicht einladen. */
.absage-link {
    padding: .35rem 0;
    background: none;
    border: 0;
    color: var(--trr-ink-soft);
    font: inherit;
    font-size: .9375rem;
    text-decoration: underline;
    text-underline-offset: .2em;
    cursor: pointer;
}

.absage-link:hover,
.absage-link:focus-visible { color: var(--trr-ink); }

/* Die eigenen Tickets auf der Event-Kachel.
   ------------------------------------------------------------------------
   Hier stand ein Satz ueber das, was man nach dem Ueberweisen nicht mehr
   selbst kann. Jetzt steht da, was man hat: ein Ticket je Person, mit ihrem
   Gesicht darauf.

   Die gestrichelte Linie zwischen Bild und Namen ist die Perforation -- die
   eine Linie, an der man ein Ticket als solches erkennt, ohne dass es eines
   nachahmen muesste. Ein gezeichneter Abriss mit ausgestanzten Ecken saehe
   auf einer Kachel mit Verlauf darunter unsauber aus. */
/* Direkt ueber den Gesichtern: erst eure Tickets, dann wer sonst kommt.
   Der Abstand nach unten ist kleiner als der nach oben -- die beiden
   Bloecke gehoeren zusammen und sollen als Paar gelesen werden. */
.ev-tickets {
    margin: 1.5rem 0 1rem;
    text-align: center;
}

/* Dieselbe Reihe in Bernstein: eine Freikarte, die noch daliegt.
   ------------------------------------------------------------------------
   Tuerkis heisst im Portal "erledigt" -- das gebuchte Ticket traegt es.
   Bernstein heisst "sieh mal hier", dieselbe Farbe wie an der Glocke, wenn
   dort etwas wartet. Genau das ist eine Freikarte: kein Missstand, sondern
   etwas Schoenes, das noch aussteht. */
.ev-tickets.ist-frei .ev-tickets-wort { color: var(--trr-amber-500); }

.ev-tickets.ist-frei .ev-ticket-art { color: var(--trr-amber-500); }

.ev-tickets.ist-frei .ev-ticket {
    background:
        linear-gradient(
            to bottom,
            rgba(242, 169, 59, .12),
            rgba(242, 169, 59, .04)
        );
}

/* Der Nachsatz sagt, was noch fehlt -- klein, weil das Ticket die Nachricht
   ist und nicht der Weg dorthin. */
.ev-tickets-fuss {
    margin: .625rem 0 0;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}


/* Die Ueberschrift traegt die Leitfarbe -- als Einzige auf der Kachel.
   "Haben sich schon angemeldet" daneben bleibt grau: Die beiden Bloecke
   sehen gleich aus, und genau deshalb muss man den eigenen auf einen Blick
   von dem der anderen unterscheiden koennen. */
.ev-tickets-wort {
    margin: 0 0 .625rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--trr-teal-800);
}

.ev-tickets-reihe {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem;
}

/* Ein Ticket, quer.
   ------------------------------------------------------------------------
   Es sah aus wie eine Pille -- rund, flach, mit einem Namen darin. Ein
   Ticket erkennt man an drei Dingen: einer Kante, die nicht rund ist, einer
   Perforation und den beiden Stanzloechern, die darauf sitzen.

   Quer und nicht hochkant: Drei hochkant nebeneinander naehmen die halbe
   Kachel, und darunter steht noch der Weg hinein. Links das Gesicht, rechts
   die Art und der Name -- so wie man ein Ticket in der Hand haelt.

   --stanz ist die Stelle der Perforation, von links gemessen: Innenrand plus
   Bildbreite plus halber Abstand. Sie steht als Variable da, weil drei
   Regeln sie brauchen -- die Linie und die beiden Loecher -- und ein
   verrutschtes Loch neben seiner Linie schlimmer aussaehe als gar keins. */
.ev-ticket {
    --stanz: 2.9rem;

    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .4rem .9rem .4rem .4rem;

    /* Ruhig und ohne Schein.
       ---------------------------------------------------------------------
       Hier lag kurz ein tuerkiser Schein dahinter, damit die Reihe auffaellt.
       Er hat das Gegenteil bewirkt: Ein weicher Lichthof um eine Form herum
       nimmt ihr die Kante, und die Kante ist beim Ticket die halbe Miete --
       aus dem Abriss wurde wieder eine Pille mit Leuchten.

       Auffallen soll jetzt die Ueberschrift. Ein Wort in der Leitfarbe zieht
       den Blick genauso und laesst die Form in Ruhe. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .08),
            rgba(255, 255, 255, .03)
        );
    border-radius: var(--trr-radius-sm);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .12),
        0 1px 2px rgba(0, 0, 0, .3);
}

/* Die beiden Stanzloecher, oben und unten auf der Perforation.
   In der Farbe der Seite und nicht durchsichtig: Ein echtes Loch braeuchte
   eine Maske, und die faellt auf aelteren Browsern ersatzlos weg -- dann
   fehlte das Kennzeichen, an dem man das Ticket erkennt. Die Kachel hat
   keinen eigenen Grund, also traegt hier der Seitengrund. */
.ev-ticket::before,
.ev-ticket::after {
    content: "";
    position: absolute;
    left: var(--stanz);
    width: .5rem;
    height: .5rem;
    margin-left: -.25rem;

    background: var(--trr-cream);
    border-radius: 50%;
}

.ev-ticket::before { top: -.25rem; }
.ev-ticket::after  { bottom: -.25rem; }

.ev-ticket-bild { display: inline-flex; }

/* Die Perforation. Sie endet oben und unten vor den Loechern -- eine Linie,
   die durch sie hindurchliefe, sieht aus wie ein Fehler. */
.ev-ticket-text {
    display: flex;
    flex-direction: column;
    gap: .05rem;
    padding: .15rem 0 .15rem .5rem;
    border-left: 1px dashed rgba(255, 255, 255, .3);
    text-align: left;
}

.ev-ticket-art {
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-teal-800);
}

.ev-ticket-name {
    font-size: .9375rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--trr-ink);
}

/* Die abgesagten Events, zugeklappt am Ende der Startseite.
   ------------------------------------------------------------------------
   Ein <details> und kein Skript: Es klappt ohne JavaScript auf, und die
   Sicherheitsregel des Portals hat damit nichts zu tun.

   Leise gesetzt, weil es der Teil ist, den man erledigt hat. Wer ihn
   aufmacht, sucht etwas Bestimmtes -- er soll ihn finden, aber nicht daran
   haengenbleiben. */
.ev-versteckt {
    margin-top: 2rem;
    border-top: 1px solid var(--trr-line);
    padding-top: 1.25rem;
}

.ev-versteckt > summary {
    display: flex;
    align-items: center;
    gap: .5rem;
    width: fit-content;
    padding: .35rem 0;

    list-style: none;
    cursor: pointer;

    font-size: .875rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

/* Das Dreieck des Browsers weg -- es sieht auf jedem anders aus. Der Pfeil
   kommt aus dem Zeichensatz und dreht sich beim Aufklappen. */
.ev-versteckt > summary::-webkit-details-marker { display: none; }

.ev-versteckt > summary:hover,
.ev-versteckt > summary:focus-visible { color: var(--trr-ink); }

.ev-versteckt-pfeil {
    width: .875rem;
    height: .875rem;
    transition: transform .15s ease-in-out;
}

.ev-versteckt[open] > summary .ev-versteckt-pfeil { transform: rotate(90deg); }

/* Die Zahl dahinter: Ein Aufklapper, der nicht sagt, wie viel darin liegt,
   wird einmal geoeffnet und danach nie wieder. */
.ev-versteckt-zahl {
    min-width: 1.25rem;
    padding: 0 .375rem;

    background: rgba(255, 255, 255, .1);
    border-radius: 999px;

    font-size: .8125rem;
    line-height: 1.25rem;
    text-align: center;
    letter-spacing: 0;
}

.ev-versteckt-text {
    margin: .5rem 0 1.25rem;
    font-size: .9375rem;
    color: var(--trr-ink);
}

.ev-nichts-offen {
    margin: 0;
    text-align: center;
    color: var(--trr-ink-soft);
}

/* Der Button, der die Absage wirklich abschickt: gefuellt und rot.
   ------------------------------------------------------------------------
   Am Button davor waere Rot falsch -- dort ist die Absage ein Angebot unter
   mehreren. Hier ist sie der Klick, nach dem etwas anders ist, und das darf
   man sehen. Dieselbe Unterscheidung wie ueberall: Ein Nebenweg traegt einen
   Rahmen, eine Entscheidung eine Flaeche.

   Weisse Schrift und nicht --trr-on-primary: Der dunkle Ton der Marke waere
   auf diesem Rot unlesbar. */
.btn-fort {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--trr-hot);
    --bs-btn-border-color: var(--trr-hot);

    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #c93a3e;
    --bs-btn-hover-border-color: #c93a3e;

    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #b43337;
    --bs-btn-active-border-color: #b43337;
}

/* Der Absage-Button: im Ruhezustand wie jeder andere Nebenweg, unter dem
   Zeiger rot.
   ------------------------------------------------------------------------
   Rot im Ruhezustand waere eine Warnung, und Absagen ist keine -- es ist
   eine von zwei gueltigen Antworten, und wer nicht kommen kann, soll sich
   dabei nicht ertappt fuehlen. Unter dem Zeiger darf die Farbe dann sagen,
   dass hier etwas endet.

   --trr-hot ist derselbe Ton wie bei einer schlimmen Meldung. Die Schrift
   bleibt hell: Auf dem gefuellten Rot waere der Markenton unlesbar, und ein
   zweites Rot fuer Schrift gibt es in der Palette nicht. */
.btn.ist-absage:hover,
.btn.ist-absage:focus-visible {
    border-color: var(--trr-hot);
    background: color-mix(in srgb, var(--trr-hot) 16%, transparent);
    color: #fff;
}


/* ------------------------------------------------ Die Leiste zum Zusagen

   Event am unteren Rand, mit demselben schwarzen Grund und derselben
   Unschaerfe wie die Leiste oben. Die beiden fassen die Seite ein, und was
   dazwischen liegt, laeuft unter ihnen durch.

   Warum fest: Die Event-Seite ist lang -- Bild, Highlights, Text, Gebuehr,
   Programm, Ablauf, Filmwahl. Wer unten steht und sich entschieden hat,
   muesste sonst zurueckscrollen, um es zu sagen. Und wer absagen will, sucht
   am laengsten.

   Der Inhalt der Seite bekommt unten so viel Luft, wie die Leiste hoch ist.
   Ohne das verschwindet die letzte Zeile darunter, und niemand merkt, dass
   dort noch etwas steht.
   ========================================================================= */

.tunleiste {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1030;

    background: rgba(0, 0, 0, .82);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid rgba(255, 255, 255, .09);
}

.tunleiste-innen {
    max-width: 68rem;
    margin: 0 auto;
    padding: .7rem 1.25rem;

    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.tunleiste-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.3;
}

.tunleiste-frage {
    font-size: 1rem;
    font-weight: 700;
    color: #fff;
}

.tunleiste-frist {
    font-size: .8125rem;
    color: rgba(255, 255, 255, .58);
}

/* Eine Frist, die naechste Woche ablaeuft, ist keine Randnotiz -- dieselbe
   Farbe wie ueberall fuer "sieh hier hin". */
.tunleiste-frist.ist-knapp { color: var(--trr-warn); }

.tunleiste-tun {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-shrink: 0;
}

/* Die Absage bekommt in der Leiste kein eigenes Aussenmass: Sie steht neben
   einem Button und soll auf derselben Linie liegen. */
.tunleiste .absage { margin-top: 0; }

/* Auf dem Telefon steht der Zustand ueber den Buttons. Nebeneinander blieb
   fuer "Noch 6 Tage" und "Ticket buchen" zusammen kein Platz, und der Button
   wurde zum Wortrest. */
@media (max-width: 34em) {
    .tunleiste-innen {
        flex-direction: column;
        align-items: stretch;
        gap: .5rem;
        padding: .6rem 1rem .7rem;
    }

    .tunleiste-text { flex-direction: row; align-items: baseline; gap: .5rem; }
    .tunleiste-tun { justify-content: space-between; }
}

/* ---------------------------------------------------- Die Teilnahmegebuehr

   Die Karten haben die Form einer Eintrittskarte: zwei Kerben an den Seiten
   und eine Perforation dazwischen. Das ist nicht nur Zierde -- die Form sagt
   in einer halben Sekunde, was die Liste ist, bevor jemand ein Wort gelesen
   hat.

   Gezeichnet und nicht als Bild: Eine Kerbe ist ein Kreis in der Farbe des
   Untergrunds, die Perforation eine gestrichelte Linie. Ein Bild muesste in
   fuenf Groessen vorliegen, koennte die Farbe nicht mitnehmen und waere bei
   jedem Ticket dieselbe Datei mit anderem Text darauf.

   Die Kerbe liegt bei 62 Prozent der Hoehe: Oben steht, was es ist, unten
   was es kostet. Genau in der Mitte saehe die Karte aus wie zweigeteilt, und
   der Preis braucht weniger Platz als der Name.
   ========================================================================= */

.gebuehr {
    margin: 0 auto clamp(2.5rem, 5vw, 4rem);
    max-width: 58rem;
    text-align: center;
}

/* Die Ueberschrift der Gebuehr hiess einmal gebuehr-kopf und sah schon so
   aus wie diese hier. Sie war das Vorbild fuer .strang-kopf -- und benutzt
   ihn jetzt selbst, statt dieselben vier Zeilen ein zweites Mal zu
   fuehren. */

.ticketreihe {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;

    /* Die Fuge muss breiter sein als zwei Kerben nebeneinander, sonst
       beruehren sich die Kreise zweier Karten und werden zu einem
       Steg. Kerbe 1,1rem, halb ausserhalb -- also mindestens 1,3rem. */
    gap: 1.5rem;
}

.ticket {
    position: relative;
    flex: 0 0 auto;
    /* 10rem: Fuenf Karten plus vier Fugen passen damit in die 58rem des
       Blocks. Bei 10,5 fiel das Familienticket in die zweite Reihe und
       stand dort allein. */
    width: 10rem;
    min-height: 13.5rem;

    display: flex;
    flex-direction: column;

    /* Derselbe flache Verlauf wie bei den Highlight-Pillen und den
       Filmkarten -- siehe dort. Kein Rahmen mehr: Der Haarrahmen war das
       Letzte, was diese Karten von einer Eintrittskarte unterschied. Eine
       Eintrittskarte hat Kerben und eine Perforation, keine Kontur. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .105),
            rgba(255, 255, 255, .04)
        );
    border-radius: 12px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .14),
        0 1px 2px rgba(0, 0, 0, .25);
}

/* Die beiden Kerben -- ausgestanzt und nicht uebermalt.
   ========================================================================
   Hier standen zwei Kreise in der Farbe der Seite, halb ueber dem Rand: ein
   Loch, das keines war, sondern ein Fleck in genau dem Ton des Untergrunds.
   Das haelt nur, solange niemand an den Farben dreht.

   Genau das tut Chrome auf Android. Der Fleck war ein solides #14161a und
   wurde beim Umfaerben zu einem weissen Punkt; der Kartenhintergrund
   daneben blieb dunkel, weil er aus halbdurchsichtigem Weiss besteht und
   anders behandelt wird. Auf dem iPhone fiel nichts auf -- Safari faerbt
   nicht um.

   Die Angabe "color-scheme: dark" bittet den Browser, die Finger davon zu
   lassen. Sie steht jetzt im Kopf jeder Seite, und trotzdem wird hier nicht
   mehr uebermalt: Eine Bitte ist keine Zusicherung. Wer "Erzwungenes
   Dunkeldesign" eingeschaltet hat, bekommt sie nicht zu Gesicht -- und
   dasselbe gilt fuer den Hochkontrastmodus und die Lesemodi der Browser.

   Eine Maske hat keine Farbe. Was sie wegnimmt, ist wirklich weg, und dort
   steht dann, was hinter der Karte liegt -- egal, welchen Ton der Browser
   sich fuer die Seite gerade ausgedacht hat.

   Faellt die Maske aus, weil ein alter Browser die Verrechnung zweier
   Ebenen nicht kennt, bleibt die Karte schlicht ohne Kerben stehen. Das ist
   der richtige Rueckfall: kein Schmuck ist besser als falscher. */
.ticket {
    /* Die Kerbe misst 1,1rem und liegt zur Haelfte ausserhalb -- die Fuge
       zwischen zwei Karten ist darauf abgestimmt (siehe .ticketreihe). */
    --kerbe: .55rem;

    -webkit-mask-image:
        radial-gradient(circle at left 62%,
            transparent var(--kerbe), #000 calc(var(--kerbe) + 1px)),
        radial-gradient(circle at right 62%,
            transparent var(--kerbe), #000 calc(var(--kerbe) + 1px));
    mask-image:
        radial-gradient(circle at left 62%,
            transparent var(--kerbe), #000 calc(var(--kerbe) + 1px)),
        radial-gradient(circle at right 62%,
            transparent var(--kerbe), #000 calc(var(--kerbe) + 1px));

    /* Beide Schreibweisen: Die zweite ist die geltende, die erste versteht
       aelteres WebKit. Wer keine kennt, verrechnet die Ebenen additiv --
       dann deckt die eine ab, was die andere ausstanzt, und es bleibt eine
       Karte ohne Kerben. */
    -webkit-mask-composite: source-in;
    mask-composite: intersect;
}

.ticket-riss {
    position: absolute;
    left: .75rem;
    right: .75rem;
    top: 62%;
    border-top: 1px dashed var(--trr-line);
}

.ticket-kopf {
    /* 62 Prozent, genau dort, wo die Kerbe und die Perforation liegen. Mit
       flex:1 schob eine zweizeilige Erklaerung den Preis nach unten, und er
       stand dann tiefer als bei den Nachbarkarten. */
    flex: 1 1 62%;
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .7rem;
    padding: 1.25rem .9rem 1.5rem;
}

.ticket-icon {
    width: 1.75rem;
    height: 1.75rem;
    color: var(--trr-teal-700);
}

.ticket-art {
    font-size: .9375rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--trr-ink);
}

/* Fuer wen das Ticket gilt. Dieselbe Rolle wie die kleine Zeile in einer
   Pille: Der Name sagt, was es ist, die Zeile darunter, fuer wen. */
.ticket-fuer {
    margin-top: .2rem;
    font-size: .8125rem;
    line-height: 1.35;
    color: var(--trr-ink-soft);
}

.ticket-fuss {
    flex: 0 0 38%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: .5rem .8rem 1rem;
}

.ticket-preis {
    font-size: 1.375rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--trr-ink);
}

/* Die Freikarten. Kein Preis, sondern der Weg dorthin -- und ein warmer Ton
   statt Tuerkis: Sie sind eine Auszeichnung und keine Stufe im Tarif. */
.ticket.ist-frei {
    border-color: rgba(242, 169, 59, .35);
}

.ticket.ist-frei .ticket-icon { color: var(--trr-warn); }

.ticket-vergabe {
    font-size: .875rem;
    line-height: 1.4;
    color: var(--trr-ink-soft);
}

.gebuehr-trenner {
    margin: 2rem 0 1.1rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* Der Hinweis des Veranstalters. Schmaler als die Karten daruber und
   linksbuendig -- er ist ein Absatz und keine Bildunterschrift. */
/* Was in der Gebuehr steckt -- ueber den Ticketkarten und nicht darunter.
   ------------------------------------------------------------------------
   Es ist die Auskunft, die ueber das Ja entscheidet, und wer sie erst nach
   dem Preis liest, hat den Preis schon ohne sie bewertet.

   Deshalb heller als der Hinweistext darunter und in der Leitfarbe: Der
   Hinweis erklaert, dieser Satz verspricht. Trotzdem kein Kasten -- zwischen
   der gesperrten Ueberschrift und einer Reihe Eintrittskarten waere ein
   dritter Rahmen einer zu viel.

   Mittig wie die Karten darunter, der Text darin aber linksbuendig, sobald
   er umbricht: Zentrierter Flattersatz ueber zwei Zeilen laesst das Auge bei
   jedem Umbruch neu suchen. */
.gebuehr-enthalten {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: .5rem;

    max-width: 42rem;
    margin: 0 auto 1.75rem;

    font-size: 1rem;
    line-height: 1.5;
    color: var(--trr-ink);
}

.gebuehr-enthalten-icon {
    flex: 0 0 auto;
    color: var(--trr-teal-600);
}

.gebuehr-text {
    max-width: 42rem;
    margin: 2.25rem auto 0;
    text-align: left;
    font-size: 1rem;
    line-height: 1.7;
    color: var(--trr-ink);
}

@media (max-width: 36em) {
    .ticketreihe { gap: .8rem; }
    .ticket { width: 8.75rem; min-height: 11.5rem; }
    .ticket-preis { font-size: 1.1875rem; }
}

/* --------------------------------------------------------- Die Einleitung

   Mittig und schmal, ohne Kasten.

   Die Zeilenlaenge ist der Grund, nicht die Optik: Ueber die ganze Breite
   einer 1900 Punkte breiten Seite waeren es 180 Zeichen je Zeile, und beim
   Ruecksprung findet man die naechste nicht mehr. 46rem sind etwa 75 -- das
   ist die Laenge, bei der man einen Text noch gern liest.

   Der Block sitzt mittig, der Text darin liegt links an. Zentrierter
   Flattersatz ueber mehrere Zeilen liest sich muehsam: Jede Zeile faengt
   woanders an, und das Auge sucht bei jedem Umbruch neu.
   ========================================================================= */

.event-einleitung {
    max-width: 46rem;
    margin: 0 auto clamp(2.5rem, 5vw, 4rem);
}

.event-einleitung .event-lead {
    font-size: clamp(1.125rem, 1.6vw, 1.3125rem);
    line-height: 1.55;
    color: var(--trr-ink);
}

.event-einleitung .event-text {
    font-size: 1.0625rem;
    line-height: 1.75;
}

/* Die Hausordnung in einer Zeile -- derzeit die Haustiere.
   ------------------------------------------------------------------------
   Sie sitzt im Einleitungsblock und nicht darunter: Sie ist ein Satz und
   kein Kapitel, und mit eigenem Abstand ringsum saehe sie aus wie eine
   Warnung, die jemand in einen Rahmen gestellt hat.

   Ohne Kasten und ohne Warnfarbe -- eine Auskunft und keine Verwarnung. Wer
   sein Tier zu Hause lassen soll, liest das freundlicher, wenn es nicht rot
   umrandet ist. Das Zeichen in der Leitfarbe genuegt, damit die Zeile im
   ruhigen Fluss der Seite ueberhaupt auffaellt.

   Zentriert wie der Block, in dem sie steht -- und einzeilig genug, dass
   der Flattersatz nicht stoert. */
.event-hausordnung {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: .55rem;

    margin: 1.5rem 0 0;

    font-size: 1rem;
    line-height: 1.5;
    color: var(--trr-ink);
}

.event-hausordnung-icon {
    flex: 0 0 auto;
    color: var(--trr-teal-600);
}

/* Die Ausnahme tritt zurueck: Sie gilt fuer wenige, die Regel fuer alle. */
.event-hausordnung-zusatz {
    color: var(--trr-ink);
}

/* Der Button mittig unter dem Text: Er gehoert zum Block und nicht an seine
   linke Kante -- dort saehe er aus wie der Anfang eines neuen Absatzes. */
.event-einleitung .event-mehr {
    display: block;
    margin: 1.1rem auto 0;
}

/* ------------------------------------------------------------- Der Strang

   Eine Spalte, von oben nach unten gelesen.

   Vorher waren es zwei im Verhaeltnis 2:1 -- links, was das Event ist, rechts,
   was zu tun ist. Die Aufteilung war logisch und die Seite trotzdem schwer zu
   lesen: Man sprang zwischen den Spalten hin und her, und was rechts oben
   stand, hatte mit dem, was links daneben stand, nichts zu tun. Auf dem
   Telefon gab es die zweite Spalte ohnehin nie, und dort las sich die Seite
   immer besser.

   Die Breite ist die der Einleitung plus ein Stueck: Die Kaesten tragen mehr
   als Fliesstext -- Kacheln, Filmplakate, eine Gaesteliste -- und 46rem
   waeren dafuer eng. Die Gebuehr bringt ihr eigenes Mass mit (58rem) und
   darf breiter sein: Ihre Karten stehen nebeneinander und nicht
   untereinander. */

.event-strang {
    display: flex;
    flex-direction: column;

    /* Viel Luft, und sie ist die halbe Gestaltung.
       ------------------------------------------------------------------
       Vorher 1.25rem -- der Abstand zwischen zwei Karten in einem Stapel.
       Er reichte, solange jeder Abschnitt einen Rahmen hatte: Die Kante
       sagte, wo einer aufhoert. Ohne Rahmen muss die Luft das sagen, und
       dafuer braucht sie ein Vielfaches. */
    gap: clamp(3rem, 6vw, 5rem);

    max-width: 52rem;
    margin: 0 auto;
}

/* Ein Abschnitt ohne Rahmen.
   ----------------------------------------------------------------------
   Ueberschrift mittig als kleine gesperrte Zeile, darunter der Inhalt --
   ebenfalls mittig und schmaler als die Spalte.

   Zwischenzeitlich stand hier die andere Ueberschrift des Portals: gross,
   in Serifen, links, mit dem Strich davor, so wie "Deine Events" auf der
   Startseite. Sie ist richtig, wo eine Seite aus Abschnitten besteht, die
   man ansteuert. Diese Seite ist aber ein Plakat: Alles steht mittig, vom
   Namen des Events ueber die Highlights bis zu den Ticketkarten, und eine
   Ueberschrift, die als Einzige links anfaengt, kippt das Bild.

   Deshalb dieselbe Zeile wie ueber den Highlights ("WAS DICH ERWARTET")
   und ueber der Gebuehr. Sie war schon da, sie galt nur noch nicht
   ueberall. */

/* T-Shirts im Anmeldeweg -- je Person eines.
   ==========================================================================
   Hier stand eine Ausfuehrung mit Mengenfeld und darunter ein Korb. Drei
   Leute sind aber selten dreimal dieselbe Groesse.

   Jetzt dieselben Personenkarten wie in Schritt 1 und 2, und unter jedem
   Gesicht die drei Felder. Die Karte wird dadurch hoeher als dort -- sie
   traegt keinen Klick, sondern Bedienelemente. */
.pers-wahl.ist-shirts .pers-karte { cursor: default; }

.pers-karte.ist-shirt {
    gap: .4rem;
    padding-bottom: 1rem;
}

.pers-karte.ist-shirt:hover { border-color: transparent; }

/* Gewaehlt: derselbe Rahmen wie bei einer angeklickten Karte. Er kommt
   hier aus dem Skript und nicht aus :has(), weil die Auswahl in drei
   Feldern steht und nicht in einem Haekchen. */
.pers-karte.ist-shirt.ist-gewaehlt {
    border-color: var(--trr-teal-700);
    background-color: rgba(2, 176, 167, .07);
}

.pers-karte.ist-shirt .pers-name { margin-bottom: .35rem; }

/* "Platin-Ticket inklusive" -- direkt unter dem Namen.
   ------------------------------------------------------------------------
   Bernstein wie ueberall, wo es um eine Freikarte geht: dieselbe Farbe wie
   auf der Kachel der Startseite und im Fenster ueber neue Karten. Man soll
   sie wiedererkennen, ohne sie zu lesen.

   Kein Kasten und keine Pille: Die Karte traegt schon drei Felder und einen
   Streifen. Ein vierter Rahmen darin waere ein Formular im Formular. */
/* Kein Versalsatz mehr, keine Sperrung.
   ------------------------------------------------------------------------
   Der Kontrast war nie das Problem, die Buchstabenform schon: Grossbuchstaben
   plus Sperrung loeschen die Silhouette des Wortes, an der man Woerter
   erkennt, ohne sie zu buchstabieren. Fuer geuebte Augen ist das ein
   Stilmittel, fuer die, um die es hier geht, eine Buchstabierhilfe.

   Fett und der Bernstein tragen die Betonung auch ohne. */
.shirt-frei {
    display: block;
    margin: -.15rem 0 .35rem;

    font-family: var(--bs-body-font-family);
    font-size: .875rem;
    font-weight: 700;
    color: var(--trr-amber-500);
}

.shirt-feld {
    width: 100%;
    margin-top: .35rem;
}

.shirt-felder { width: 100%; }
.shirt-felder[hidden] { display: none; }

/* Der Streifen sagt, was diese Person bekommt -- gewaehlt traegt er den
   Markenton wie in den Schritten davor.

   Er bleibt unten (margin-top:auto aus der Grundregel); der Abstand kommt
   von den Feldern darueber. Mit festem Abstand haette eine Karte ohne Shirt
   ihn mitten im Kasten hangen, waehrend er nebenan unten sitzt. */
.pers-karte.ist-shirt .shirt-felder { margin-bottom: .9rem; }
.pers-karte.ist-shirt [data-shirt-ob] { margin-bottom: .9rem; }
.pers-karte.ist-shirt .shirt-felder:not([hidden]) ~ .pers-streifen { margin-top: auto; }
.pers-karte.ist-shirt [data-shirt-ob] + .shirt-felder { margin-top: -.55rem; }

.pers-karte.ist-shirt.ist-gewaehlt .pers-streifen {
    background: var(--trr-teal-700);
    color: #062b29;
}

/* Die Bilder ueber der Auswahl: klein und in einer Reihe. Gross waere hier
   falsch -- auf der Event-Seite ist das Shirt die Nachricht, hier ist es
   die Erinnerung daran, wofuer man eine Groesse waehlt. */
/* Das Shirt ist die Ware und war eine Briefmarke.
   ------------------------------------------------------------------------
   5,5rem sind 88 Bildpunkte, quadratisch beschnitten aus einer Vorlage im
   Breitformat. Darunter soll man Schnitt, Farbe und Groesse waehlen -- fuer
   etwas, das man nicht erkennen kann. 11rem sind das Doppelte und immer
   noch ein Vorschaubild: Wer es genau sehen will, klickt es gross, das gab
   es schon. */
.shirt-schau-klein {
    display: inline-block;
    width: 11rem;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border-radius: var(--trr-radius-sm);
    background: linear-gradient(160deg, rgba(2, 176, 167, .14), rgba(0, 0, 0, .35));
}

.shirt-schau-klein img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Das Wort ueber Schnitt und Farbe. Klein, aber nicht versteckt -- es
   beantwortet die Frage "ist das eine Angabe oder eine Wahl?". */
.shirt-feld-wort {
    display: block;
    margin: .35rem 0 -.1rem;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
    text-align: left;
}

.pers-wahl.ist-shirts { margin-top: 1.25rem; }

/* ------------------------------------- Die Ausfuehrungen im Manager

   Nur zur Kontrolle: was aus den Haekchen geworden ist. Deshalb eine
   schlichte Liste und kein Formular -- wer etwas aendern will, aendert oben
   ein Haekchen. */

.shirt-liste {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: .3rem .75rem;
}

.shirt-zeile {
    display: flex;
    align-items: baseline;
    gap: .75rem;
    padding: .4rem .7rem;

    background: var(--trr-row);
    border-radius: var(--trr-radius-sm);
    font-size: .9375rem;
}

.shirt-zeile-was { flex: 1 1 auto; min-width: 0; }

.shirt-zeile-preis {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    color: var(--trr-ink-soft);
}

/* Stillgelegt: noch da, aber nicht mehr bestellbar. */
.shirt-zeile.ist-still { opacity: .55; }

/* Die Bilder im Modul: kleine Kacheln mit Haekchen. Kein Loesch-Button je
   Bild -- das waere ein Formular im Formular, und ein Klick daneben waere
   endgueltig. So entscheidet erst das Speichern. */
.shirt-bilder {
    list-style: none;
    margin: 0 0 .4rem;
    padding: 0;

    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
    gap: .75rem;
}

.shirt-bild {
    position: relative;
}

.shirt-bild img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    display: block;
    border-radius: calc(var(--trr-radius) * .6);
}

.shirt-bild-weg {
    display: flex;
    align-items: center;
    gap: .35rem;
    margin-top: .3rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.shirt-bild-marke {
    position: absolute;
    top: .35rem;
    left: .35rem;
    padding: .1rem .4rem;
    border-radius: 999px;

    font-size: .8125rem;
    letter-spacing: .02em;
    background: rgba(2, 176, 167, .85);
    color: #06201f;
}

/* -------------------------------------------------------- Die T-Shirts

   Ein Bild, drei Zeilen. Was es gibt, was es kostet, wo man es bekommt.

   Ohne Rahmen und ohne Kasten wie alles auf dieser Seite -- das Bild traegt
   den Abschnitt, der Text steht darunter und braucht keine zweite Kante um
   sich herum. */

.shirt-schau {
    text-align: center;
}

/* Dasselbe 16:9 wie auf den Kacheln der Schiene. Kein zweites Format fuer
   dieselbe Sache: Wer ein Bild fuers Event zurechtschneidet, soll es nicht
   zweimal tun muessen. */
.shirt-schau-bild {
    display: block;
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: var(--trr-radius);
    background: linear-gradient(160deg, rgba(2, 176, 167, .14), rgba(0, 0, 0, .35));
}

.shirt-schau-bild img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Und laeuft nach unten aus -- in genau die Farbe, die darunter
   weitergeht, sonst saehe man eine Kante. */
.shirt-schau-bild::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        linear-gradient(
            to bottom,
            rgba(28, 31, 37, 0) 55%,
            rgba(28, 31, 37, .7) 88%,
            var(--trr-paper) 100%
        );
    pointer-events: none;
}

/* Die uebrigen als Reihe darunter: kleiner, ohne Verlauf, gleich hoch.
   Sie sollen ergaenzen und nicht mit dem grossen konkurrieren. */
.shirt-schau-reihe {
    list-style: none;
    margin: .6rem 0 0;
    padding: 0;

    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
    gap: .6rem;
}

.shirt-schau-reihe a {
    display: block;
}

.shirt-schau-reihe img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    display: block;
    border-radius: calc(var(--trr-radius) * .6);
}

.shirt-schau-satz {
    margin: 1.4rem 0 0;
    font-size: 1.0625rem;
    line-height: 1.55;
    color: var(--trr-ink);
    text-wrap: balance;
}

.shirt-schau-preis {
    margin: .5rem 0 0;
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--trr-teal-800);
}

.shirt-schau-hinweis {
    margin: .8rem 0 0;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--trr-ink);
    text-wrap: balance;
}

/* Der Satz, den es wirklich braucht -- deshalb abgesetzt und nicht als
   vierte Zeile im selben Grau. */
.shirt-schau-wo {
    margin: 1.2rem 0 0;
    font-size: .9375rem;
    color: var(--trr-ink-soft);
}

/* ====================================================== Die Cocktailkarten

   Die Arbeitsliste des Bar-Mixers: eine Zeile je Event. Keine Kacheln --
   er sucht ein Datum und keinen Anblick, und zehn Zeilen stehen dort, wo
   zehn Kacheln zweimal Scrollen kosten. */

.karten-liste {
    list-style: none;
    margin: 0;
    padding: 0;

    display: flex;
    flex-direction: column;
    gap: .55rem;
}

.karten-zeile {
    display: flex;
    align-items: center;
    gap: .75rem 1rem;
    flex-wrap: wrap;

    padding: .8rem 1.1rem;
    border-radius: var(--trr-radius);

    /* Eine Flaeche in einem Ton. Der Verlauf der Pillen von der Event-Seite
       stand hier eine Runde lang und ist wieder raus: Dort liegt er auf
       einem Bild und hebt die Pille davon ab. Hier gibt es kein Bild --
       zehn verlaufende Zeilen untereinander sind Unruhe ohne Anlass. */
    background: var(--trr-paper);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
}

/* Name und Datum nehmen den freien Platz, alles Uebrige draengt sich
   rechts zusammen. So stehen Zustand und Button in jeder Zeile
   untereinander und wandern nicht mit der Laenge des Namens. */
.karten-zeile-kopf {
    flex: 1 1 14rem;
    min-width: 0;

    display: flex;
    align-items: baseline;
    gap: .6rem;
    flex-wrap: wrap;
}

.karten-zeile-name {
    font-weight: 600;
    overflow-wrap: anywhere;
}

.karten-zeile-datum,
.karten-zeile-zahl {
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.karten-zeile-button {
    flex: 0 0 auto;
}

/* Ein Hauch der Leitfarbe am Rand: So ist der Button, der etwas aendert,
   von dem zu unterscheiden, der nur hinsehen laesst -- ohne dass die Liste
   zur Wand aus Tuerkis wird. */
.karten-zeile-button.ist-bearbeiten {
    border-color: rgba(2, 176, 167, .45);
    color: var(--trr-teal-800);
}

.karten-zeile-button.ist-bearbeiten:hover,
.karten-zeile-button.ist-bearbeiten:focus-visible {
    border-color: var(--trr-teal-700);
    background: rgba(2, 176, 167, .12);
    color: var(--trr-teal-900);
}

/* Vorbei: gedeckt und ohne Lichtkante. Es soll lesbar bleiben und nicht
   um Aufmerksamkeit bitten. */
.karten-zeile.ist-vorbei {
    background: rgba(255, 255, 255, .028);
    box-shadow: none;
}

.karten-zeile.ist-vorbei .karten-zeile-name {
    font-weight: 500;
    color: var(--trr-ink-soft);
}

/* Der Block darunter, deutlich abgesetzt: Was vorbei ist, gehoert nicht in
   dieselbe Liste wie das, was ansteht. */
.karten-vorbei {
    margin-top: 3.5rem;
    padding-top: 2rem;
    border-top: 1px solid var(--trr-line);
}

.karten-vorbei-kopf {
    margin: 0;

    font-size: .9375rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.karten-vorbei-zahl {
    margin-left: .4rem;
    opacity: .65;
}

.karten-vorbei-text {
    margin: .35rem 0 1.1rem;
    font-size: .9375rem;
    color: var(--trr-ink);
}

/* ================================================== Die Highlight-Schiene

   Was es beim Event gibt -- mit Bild, Satz und Erklaerung.

   Die Pillen oben sagen, dass es etwas gibt; die Schiene sagt, was. Dass
   beides dasselbe aufzaehlt, ist Absicht: oben der Ueberblick, ohne dass
   jemand Text lesen muss, unten die Erklaerung fuer den, der sie will.

   Eine Schiene und kein Raster. Bei vier Punkten sieht man alle vier, bei
   acht wischt man weiter -- ein Raster wuerde acht Kacheln untereinander
   stapeln und den halben Bildschirm fuellen.
   ======================================================================== */

/* Die Schiene darf breiter sein als die Spalte.
   ----------------------------------------------------------------------
   52rem sind das Mass fuer Text -- eine Zeile, die man am Stueck liest.
   Bilder brauchen dieses Mass nicht; sie werden nur klein davon. Also
   bricht die Schiene als Einzige aus der Spalte aus und nimmt sich, was
   das Fenster hergibt.

   margin-left: 50% setzt die linke Kante in die Mitte der Spalte, das
   translate schiebt sie um die halbe eigene Breite zurueck -- so sitzt sie
   mittig, egal wie breit die Spalte gerade ist. */
/* Beide Klassen im Selektor, damit die Aussenabstaende stehen bleiben:
   .strang-teil setzt weiter unten margin: 0, und bei gleicher Staerke
   gewinnt die spaetere Regel. */
.strang-teil.hl-teil {
    --hl-breit: min(68rem, calc(100vw - 2.5rem));

    width: var(--hl-breit);

    /* Nach beiden Seiten gleich weit hinaus. Die Prozente rechnen gegen die
       Spalte, in der die Schiene steht -- ist sie schmaler als die Schiene,
       wird der Wert negativ, und genau das ist gewollt.

       Vorher stand hier margin-left: 50% mit einem translate zurueck. Das
       verschob die Schiene nach links: Ein transform verschiebt, was schon
       gesetzt ist, und beim Rechnen kamen zwei verschiedene Bezugsgroessen
       zusammen. Symmetrische Aussenabstaende brauchen keine zweite
       Rechnung. */
    margin-inline: calc((100% - var(--hl-breit)) / 2);
}

/* Eine Zeile aus drei Teilen: Pfeil, Schiene, Pfeil.
   ----------------------------------------------------------------------
   Vorher lagen die Pfeile absolut positioniert halb ueber den Kacheln --
   sie verdeckten das erste und letzte Bild, und ihre Hoehe musste von Hand
   ausgerechnet werden. Als Geschwister der Schiene liegen sie von selbst
   auf der Mittellinie und stoeren nichts. */
.hl-schiene-huelle {
    display: flex;
    align-items: center;
    gap: .5rem;
}

.hl-schiene {
    /* Nimmt den Platz zwischen den Pfeilen. min-width: 0 muss sein, sonst
       waere ein Flex-Kind so breit wie sein Inhalt -- und der Inhalt ist
       hier acht Kacheln. */
    flex: 1 1 auto;
    min-width: 0;

    list-style: none;
    margin: 0;
    padding: .25rem;

    display: flex;
    gap: 1rem;

    /* Passt alles hinein, steht es in der Mitte.
       --------------------------------------------------------------------
       Die Schiene ist auf vier Kacheln ausgelegt. Bei dreien blieb rechts
       ein Viertel leer, und die Reihe sah aus, als fehle dort etwas -- was
       nicht stimmt: Es gibt drei, und drei sind vollstaendig.

       "safe" ist der ganze Trick. Ein blosses "center" in einem Kasten, der
       scrollt, schiebt bei Ueberlaenge den Anfang aus dem Kasten heraus --
       die erste Kachel waere dann nicht mehr erreichbar, auch nicht durch
       Wischen. Mit "safe" faellt die Ausrichtung genau dann auf den Anfang
       zurueck, wenn der Inhalt nicht mehr passt: mittig bei drei, linksbuendig
       bei acht. */
    justify-content: safe center;

    /* scroll-snap statt Karussell-Skript: Auf dem Telefon wischt es von
       selbst und rastet an der naechsten Kachel ein. Laedt das Skript
       nicht, bleibt die Schiene trotzdem scrollbar -- die Pfeile sind der
       Zusatz, nicht die Bedienung. */
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
}

/* Die Leiste selbst bleibt unsichtbar: Sie liegt bei uns ohnehin ueber dem
   Inhalt und zoege einen grauen Balken unter die Bilder. */
.hl-schiene::-webkit-scrollbar { display: none; }

/* Vier Kacheln plus drei Fugen in den 68rem der Schiene: 4 x 16 + 3 x 1 =
   67. Die fuenfte schaut am Rand herein -- und genau das ist die Einladung
   zu wischen. Eine Schiene, die buendig abschliesst, sieht aus wie ein
   Raster, und dann sucht niemand weiter. */
.hl-kachel {
    position: relative;

    /* Events Breite. Die Variable dafuer ist weggefallen, als die Pfeile
       neben die Reihe wanderten -- sie war nur noch fuer deren Hoehe da,
       und ein Wert, den nur eine Stelle braucht, steht besser dort. */
    flex: 0 0 16rem;
    scroll-snap-align: start;

    display: flex;
    flex-direction: column;

    /* Der Grund, in den das Bild ausläuft. Ein Ton und kein Verlauf: Der
       Uebergang oben soll die einzige Kante sein, die man sieht. */
    background: var(--trr-paper);
    border-radius: 12px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .1),
        0 1px 2px rgba(0, 0, 0, .25);
    overflow: hidden;
}

/* Das Bild quer, sechzehn zu neun -- das Format, in dem Kameras und
   Bildschirme denken. Hochkant war es einmal, und dann lag der Text darauf;
   auf einem hellen Himmel verschwand er trotz Verlauf. Jetzt steht er
   darunter, wo nichts mit ihm um den Grund streitet. */
.hl-kachel-bild {
    position: relative;
    aspect-ratio: 16 / 9;
    background: linear-gradient(160deg, rgba(2, 176, 167, .14), rgba(0, 0, 0, .35));

    display: flex;
    align-items: center;
    justify-content: center;
}

.hl-kachel-bild img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Und laeuft nach unten in den Grund der Kachel aus.
   ----------------------------------------------------------------------
   Nicht in irgendein Schwarz, sondern in genau die Farbe, die darunter
   weitergeht -- sonst saehe man eine Kante quer durch die Kachel. Der
   Verlauf faengt erst bei der Haelfte an: Oben soll das Bild ganz zu sehen
   sein, unten soll es aufhoeren, ohne dass man merkt, wo. */
.hl-kachel-bild::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        linear-gradient(
            to bottom,
            rgba(28, 31, 37, 0) 50%,
            rgba(28, 31, 37, .75) 85%,
            var(--trr-paper) 100%
        );
}

/* Kein Bild: das Zeichen auf getoenter Flaeche. Gedeckt, denn es ist ein
   Platzhalter und kein Bild. */
.hl-kachel-zeichen {
    width: 30%;
    height: 30%;
    /* Etwas hoeher als die Mitte: Unten laeuft das Bild in den Grund aus. */
    margin-bottom: 12%;
    color: rgba(255, 255, 255, .25);
}

/* Der Text steht unter dem Bild und nicht darauf. */
.hl-kachel-text {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;

    /* Oben ein knapper Abstand. Ganz ohne stand die Ueberschrift an der
       Bildkante und wirkte angeklebt; ein voller machte aus dem Verlauf
       wieder eine Fuge. */
    padding: .75rem 1.1rem 1.2rem;
}

/* Keine Silbentrennung auf der Kachel.
   ----------------------------------------------------------------------
   Die Seite trennt sonst ueberall automatisch, und im Fliesstext ist das
   richtig. In einer Ueberschrift von drei Woertern wurde daraus "Dop-" und
   "pel-K.-o.", und man liest zweimal hin. Die Spalte ist breit genug; was
   nicht passt, rutscht in die naechste Zeile. */
.hl-kachel-titel {
    margin: 0;
    font-family: var(--bs-body-font-family);
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.3;
    color: #fff;
    hyphens: manual;
}

.hl-kachel-zeile {
    margin: .45rem 0 0;
    font-size: .9375rem;
    line-height: 1.5;
    color: var(--trr-ink-soft);
    hyphens: manual;
}

/* "Mehr erfahren" am Fuss und immer auf gleicher Hoehe: Die Kacheln sind
   gleich hoch, die Texte darin nicht.

   Ein Button und kein Verweis: Er oeffnet ein Fenster und fuehrt nirgendwo
   hin. Aussehen tut er wie ein Verweis, denn genau das erwartet man an
   dieser Stelle. */
.hl-kachel-mehr {
    margin: auto 0 0;
    padding-top: .8rem;
    padding: 0;
    align-self: flex-start;

    background: none;
    border: 0;
    font-size: .9375rem;
    font-weight: 700;
    color: var(--trr-teal-700);
    cursor: pointer;
}

.hl-kachel-mehr:hover,
.hl-kachel-mehr:focus-visible { text-decoration: underline; }

/* Eine Tuer sieht anders aus als ein eigener Punkt: Sie hat kein Bild, das
   ihre Flaeche fuellt, und sie fuehrt woandershin. Der Hauch Leitfarbe im
   Grund sagt das, ohne dass es jemand lesen muss. */
.hl-kachel.ist-tuer .hl-kachel-bild {
    background: linear-gradient(160deg, rgba(2, 176, 167, .2), rgba(0, 0, 0, .4));
}

/* Die Pfeile. Sie stehen halb ueber dem Rand der Schiene und erscheinen
   erst, wenn es etwas zu schieben gibt -- das entscheidet der Browser, denn
   er allein weiss, wie breit das Fenster ist. */
/* Neben der Reihe und deshalb groesser: Wo er nichts verdeckt, darf er
   auch getroffen werden -- knapp drei Zentimeter sind auf dem Tablet ein
   Ziel und nicht ein Punkt. */
.hl-pfeil {
    flex: 0 0 auto;
    width: 2.75rem;
    height: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;

    background: var(--trr-paper);
    border: 1px solid var(--trr-line);
    border-radius: 999px;
    color: var(--trr-ink);
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .45);
}

/* Am Ende der Schiene wird der Pfeil stumpf statt zu verschwinden.
   ----------------------------------------------------------------------
   Verstecken sprang: Die Schiene rueckte beim Laden um zwei Zentimeter,
   sobald der Browser gerechnet hatte. Ein stumpfer Pfeil bleibt an seinem
   Platz und sagt dasselbe -- hier ist der Anfang, hier das Ende. */
.hl-pfeil:disabled {
    opacity: .3;
    cursor: default;
    box-shadow: none;
}

.hl-pfeil:disabled:hover { border-color: var(--trr-line); color: var(--trr-ink); }

.hl-pfeil:hover { border-color: var(--trr-teal-700); color: var(--trr-teal-700); }
.hl-pfeil svg   { width: 1.25rem; height: 1.25rem; }

/* ---------------------------------------------- Das Fenster dahinter */

.hl-fenster-bild {
    width: 100%;
    max-height: 16rem;
    object-fit: cover;
    border-radius: var(--trr-radius-sm);
    margin-bottom: 1rem;
}

.hl-fenster-zeile {
    margin: 0 0 .75rem;
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--trr-teal-700);
}

.hl-fenster-text {
    font-size: 1rem;
    line-height: 1.65;
    color: var(--trr-ink);
}

/* ================================================== Die Buttonreihe

   Die Wege, die von der Event-Seite wegfuehren: Siegertabelle,
   Cocktailkarte, T-Shirts, Regelwerk, Bilder.

   Zwei nebeneinander, wo Platz ist. Untereinander waeren es fuenf breite
   Balken, und der letzte staende so weit unten, dass ihn niemand mehr
   sucht. */

/* Drei Karten nebeneinander und keine liegenden Balken.
   ----------------------------------------------------------------------
   Es sind genau drei, sie sind gleich wichtig, und was gleich wichtig ist,
   steht nebeneinander -- untereinander wird das Unterste zum Nachklapp.

   Auf dem Telefon rutschen sie doch untereinander: Drei Karten auf 390
   Punkten waeren drei Streifen. */
.ev-buttonreihe {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: .75rem;
}

.ev-button {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: .15rem;
    padding: 1.4rem 1rem 1.5rem;
    text-decoration: none;

    /* Dieselbe Machart wie die Pillen und die Ticketkarten: flacher
       Verlauf, Lichtkante, kein Rahmen. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .095),
            rgba(255, 255, 255, .035)
        );
    border-radius: var(--trr-radius);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .13),
        0 1px 2px rgba(0, 0, 0, .25);
}

/* Der eine, der nach dem Event zaehlt: die freigegebene Wertung. Ein Hauch
   der Leitfarbe im Grund, mehr braucht es nicht -- ein zweiter kraeftiger
   Button daneben, und keiner faellt mehr auf. */
.ev-button.ist-stark {
    background:
        linear-gradient(
            to bottom,
            rgba(2, 176, 167, .22),
            rgba(2, 176, 167, .1)
        );
}

.ev-button:hover {
    box-shadow:
        inset 0 0 0 1px var(--trr-teal-700),
        inset 0 1px 0 rgba(255, 255, 255, .13),
        0 1px 2px rgba(0, 0, 0, .25);
}

/* Das Zeichen auf einer Scheibe: Es traegt die Karte, und ohne Scheibe
   schwebte es ueber dem Text wie ein Aufkleber. */
.ev-button-scheibe {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    margin-bottom: .7rem;

    background: rgba(2, 176, 167, .14);
    border-radius: 999px;
}

.ev-button-icon {
    width: 1.5rem;
    height: 1.5rem;
    color: var(--trr-teal-700);
}

.ev-button-wort {
    font-family: "Bitter", Georgia, "Times New Roman", serif;
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--trr-ink);
}

.ev-button-zeile {
    font-size: .875rem;
    line-height: 1.4;
    color: var(--trr-ink-soft);
    hyphens: manual;
}

.strang-teil { margin: 0; }

/* Die Zwischenkoepfe der Eventseite tragen dieselbe Machart wie die der
   Startseite -- die gemeinsame Regel steht weiter unten bei
   .ev-abschnitt-kopf. Hier bleibt nichts mehr zu sagen.

   Was hier stand: display: flex, zentriert, und
   color: rgba(255, 255, 255, .55). Genau diese Farbe war das Problem. Bei
   13 Pixeln, gesperrt und in Versalien kam sie auf 6,1:1 -- der Text
   darunter steht bei 13,4:1 und ist groesser. Die Ueberschrift war also
   leiser als das, was sie ankuendigt, und beim Scrollen sah man sie
   deshalb nicht. Das ist ein Rangfehler und keine Frage des Farbtons;
   Tuerkis an derselben Stelle haette 6,7:1 gebracht und den Rang nicht
   geaendert. */

/* Schmaler als die Spalte und mittig darin.
   ----------------------------------------------------------------------
   52rem sind die Breite fuer Kaesten, nicht fuer Listen: Zwischen "10:00"
   und "Fahrerbesprechung" stuenden sonst fuenfzehn Zentimeter Nichts. Ein
   Aushang haengt nicht deshalb quer, weil die Wand breit ist.

   Der Inhalt darin bleibt linksbuendig -- eine Uhrzeitenspalte im
   Flattersatz waere keine Spalte mehr. Mittig steht der Block, nicht sein
   Text. */
.strang-inhalt {
    max-width: 32rem;
    margin: 0 auto;
}

/* Ohne das ist ein Fach mindestens so breit wie sein laengstes unteilbares
   Wort und schiebt die Seite auseinander -- der Umbruch am body allein
   genuegt nicht. */
.event-strang > * { min-width: 0; }

/* Die Gebuehr hat ihren eigenen Aussenabstand von frueher, als sie noch
   allein zwischen zwei Bloecken stand. Im Strang sorgt das gap fuer den
   Abstand, und der doppelte liesse sie herausfallen. */
.event-strang > .gebuehr {
    margin-top: 0;
    margin-bottom: 0;
}

/* ==========================================================================
   Die Event-Seite: Preiszeile und die Tueren

   Die Seite hat eine Aufgabe -- Lust machen und zur Anmeldung fuehren.
   Alles, was zum Buchen gehoert, steht im Buchungsweg. Was es hier sonst
   noch gibt, wird als Tuer gezeigt und nicht ausgebreitet.
   ========================================================================== */

.event-preis {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .9rem;
    margin: 0;
    padding: .75rem 1.1rem;
    background: var(--trr-paper);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius);
}

.event-preis-icon {
    width: 1.1rem;
    height: 1.1rem;
    flex-shrink: 0;
    color: var(--trr-ink-soft);
}

.event-preis-text {
    font-weight: 600;
    color: var(--trr-ink);
}

/* Ein Button, der wie ein Verweis aussieht: Er oeffnet ein Fenster und
   fuehrt nicht auf eine Seite -- deshalb button und nicht a. Was aussieht
   wie ein Verweis, aber keiner ist, laesst sich nicht in einem neuen Reiter
   oeffnen, und genau das versucht jemand frueher oder spaeter. */
.event-preis-mehr {
    margin-left: auto;
    padding: 0;
    background: none;
    border: 0;
    color: var(--trr-teal-700);
    font: inherit;
    font-size: .9375rem;
    font-weight: 600;
    text-decoration: underline;
    cursor: pointer;
}

.event-preis-mehr:hover { color: var(--trr-teal-900); }

/* ------------------------------------------------------------- Die Tueren

   Zwei nebeneinander und nicht so viele, wie zufaellig hineinpassen. In der
   linken Spalte einer 2:1-Seite ergab auto-fill mal drei und mal zwei --
   und drei schmale Tueren nebeneinander sahen aus wie eine Werkzeugleiste.

   Das Zeichen sitzt in einem tuerkisfarbenen Feld. Das ist der Unterschied
   zwischen einer Liste und etwas, das man anfasst: Ohne das Feld war die
   Tuer eine Zeile mit einem Symbol davor. */

.ev-tueren {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .7rem;
}

.ev-tuer {
    display: flex;
    align-items: center;
    gap: .85rem;
    height: 100%;
    padding: .9rem 1rem;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    color: inherit;
    text-decoration: none;
    transition: border-color .15s ease, background-color .15s ease;
}

a.ev-tuer:hover,
a.ev-tuer:focus-visible {
    border-color: var(--trr-teal-700);
    background: var(--trr-teal-050);
    color: inherit;
}

a.ev-tuer:hover .ev-tuer-pfeil,
a.ev-tuer:focus-visible .ev-tuer-pfeil { color: var(--trr-teal-700); }

/* Was freigegeben ist, traegt die Leitfarbe -- dieselbe Bedeutung wie
   ueberall: hier ist etwas passiert. */
.ev-tuer.ist-stark {
    border-color: var(--trr-teal-700);
    box-shadow: 0 0 0 1px var(--trr-teal-700);
}

/* Eine Tuer ohne Ziel: Sie sagt, dass es etwas gibt, und mehr nicht. */
.ev-tuer.ist-still { cursor: default; }

.ev-tuer-icon {
    width: 2.5rem;
    height: 2.5rem;
    padding: .62rem;
    flex-shrink: 0;
    color: var(--trr-teal-700);
    background: var(--trr-teal-050);
    border-radius: 10px;
}

.ev-tuer.ist-still .ev-tuer-icon {
    color: var(--trr-ink-soft);
    background: var(--trr-paper);
}

.ev-tuer-text {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.3;
}

.ev-tuer-titel {
    font-weight: 600;
}

.ev-tuer-zeile {
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.ev-tuer-pfeil {
    width: .875rem;
    height: .875rem;
    flex-shrink: 0;
    color: var(--trr-ink-soft);
    transition: color .15s ease;
}

/* Auf dem Telefon untereinander: Zwei Tueren nebeneinander liessen vom
   Text "Wertung" ein "Wer..." uebrig. */
@media (max-width: 36em) {
    .ev-tueren { grid-template-columns: 1fr; }
    .ev-tuer-icon { width: 2.2rem; height: 2.2rem; padding: .55rem; }
}

/* ------------------------------------------------- Der gekuerzte Text

   Ein langer Beschreibungstext schiebt alles Weitere aus dem Bild. Er wird
   deshalb eingeklappt -- aber erst im Browser und nur, wenn er wirklich zu
   hoch ist. Ohne Skripte steht er vollstaendig da, statt hinter einem Button
   zu verschwinden, den es dann nicht gibt.

   Der Verlauf statt einer harten Kante: Eine abgeschnittene Zeile sieht
   nach einem Fehler aus, ein auslaufender Text nach einer Fortsetzung. */

.event-text.ist-gekuerzt,
.seiten-gruss-text.ist-gekuerzt {
    max-height: 9rem;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(180deg, #000 65%, transparent 100%);
            mask-image: linear-gradient(180deg, #000 65%, transparent 100%);
}

.event-mehr {
    margin-top: .85rem;
    padding: 0;
    background: none;
    border: 0;
    color: var(--trr-teal-700);
    font: inherit;
    font-size: .9375rem;
    font-weight: 600;
    cursor: pointer;
}

.event-mehr:hover { color: var(--trr-teal-900); }
/* ----------------------------------------------------- Die Ticketarten */

.preis-arten {
    list-style: none;
    margin: 0 0 1rem;
    padding: 0;
}

.preis-art {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .5rem 0;
}

.preis-art + .preis-art {
    border-top: 1px solid var(--trr-line);
}

.preis-art-wert {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.preis-hinweis {
    padding: .85rem 1rem;
    background: var(--trr-row);
    border-radius: var(--trr-radius-sm);
    font-size: 1rem;
    color: var(--trr-ink);
}

.preis-fuss {
    margin: 1rem 0 0;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* ==========================================================================
   Die Filmwahl

   Ein Film ist keine Umfrageoption: Plakat, Inhalt und Trailer sind das,
   was die Wahl ueberhaupt zu einer macht.

   Hier stand der Aufklapper, in dem alle Filme eines Events untereinander
   bearbeitet wurden -- Plakat als Briefmarke im Kopf, vier Felder im
   Inneren, ein Speichern fuer alle zugleich. Jeder Film hat jetzt seine
   eigene Seite; was ihn dort und in der Liste kleidet, steht bei den
   Uebersichtslisten weiter unten.
   ========================================================================== */

/* --------------------------------------- Die Filmwahl auf der Event-Seite

   Plakat, Inhalt, Trailer und der Zwischenstand. Beim Kino-Abend ist das
   der Grund wiederzukommen -- deshalb steht der Stand hier und nicht nur
   im Manager. */

/* Der Satz unter einer Abschnitts-Ueberschrift: worum es hier geht.
   Mittig wie die Ueberschrift darueber, und schmaler als der Abschnitt --
   ein Satz ueber 52rem laesst das Auge am Zeilenende suchen, wo der
   naechste anfaengt.

   Hiess einmal .film-lead und stand nur ueber der Filmwahl. Er wird an
   mehreren Stellen gebraucht, also traegt er jetzt den Namen des
   Abschnitts und nicht den seines ersten Bewohners. */
.strang-lead {
    max-width: 34rem;
    margin: 0 auto 1.75rem;
    text-align: center;
    color: var(--trr-ink);
}

.strang-lead strong { color: var(--trr-ink); }

/* Die Reihe wie die der Tickets: mittig, umbrechend, feste Kartenbreite.
   Nicht 1fr-Spalten -- bei zwei Filmen waeren das zwei halbe Seiten, und
   ein Plakat, das eine halbe Seite fuellt, ist kein Plakat mehr. */
.filmreihe {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.5rem;
}

/* Die Karte waechst mit, statt fest zu stehen.
   ----------------------------------------------------------------------
   15rem ist der Anfangswert: Drei Karten plus zwei Fugen passen damit in
   die 52rem der Spalte, eine vierte nicht mehr -- besser als vier Karten,
   die jede fuer ein Plakat zu schmal sind.

   Event waren sie vorher auch, und dann blieben rechts drei Zentimeter
   stehen. Mit flex-grow fuellen drei Karten die Spalte aus (16,3rem je
   Karte), und zwei ruecken naeher zusammen, statt in der Mitte zu
   schwimmen.

   Die Obergrenze ist der Grund, warum es hier nicht bei flex-grow bleibt:
   Ein vierter Film stuende allein in der zweiten Reihe und ginge dort auf
   die volle Spaltenbreite auf -- ein Plakat von 52rem Breite ist kein
   Plakat mehr. */
.filmkarte {
    flex: 1 1 15rem;
    max-width: 17rem;

    display: flex;
    flex-direction: column;

    /* Derselbe flache Verlauf wie bei den Highlight-Pillen: von oben hell
       nach unten dunkel, so wie Licht faellt, dazu eine Lichtkante oben
       und ein Hauch Schatten unten. Kein Rahmen -- ein Haarrahmen macht
       aus der Karte eine Kontur; sie soll eine Flaeche sein, die auf der
       Seite liegt.

       Der Verlauf ist bewusst schwach. Wo man ihn als Verlauf erkennt,
       ist er zu stark. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .105),
            rgba(255, 255, 255, .04)
        );
    border-radius: 12px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .14),
        0 1px 2px rgba(0, 0, 0, .25);
    overflow: hidden;
}

/* Der Film, der vorn liegt, bekommt die Leitfarbe -- dieselbe Bedeutung
   wie ueberall im Portal: das ist der ausgewaehlte. Als Ring und nicht als
   Rahmen, damit die Lichtkante darunter bestehen bleibt. */
.filmkarte.ist-vorn {
    box-shadow:
        0 0 0 1px var(--trr-teal-700),
        inset 0 1px 0 rgba(255, 255, 255, .14),
        0 1px 2px rgba(0, 0, 0, .25);
}

/* Zwei zu drei, das Format, in dem Filmplakate haengen. Die Bilder kommen
   in allen moeglichen Seitenverhaeltnissen; ohne festes Format waere die
   Reihe eine Treppe. */
.filmkarte-plakat {
    position: relative;
    aspect-ratio: 2 / 3;
    background: linear-gradient(160deg, rgba(2, 176, 167, .12), rgba(0, 0, 0, .3));

    display: flex;
    align-items: center;
    justify-content: center;
}

.filmkarte-plakat img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Kein Plakat: ein Zeichen und kein leerer Kasten. Gedeckt, denn es ist
   ein Platzhalter und kein Bild. */
.filmkarte-zeichen {
    width: 30%;
    height: 30%;
    color: rgba(255, 255, 255, .22);
}

/* "vorn" auf dem Plakat. Nicht nur der tuerkise Rand: Wer die Farbe nicht
   unterscheidet, saehe sonst gar nichts. */
.filmkarte-marke {
    position: absolute;
    top: .6rem;
    left: .6rem;

    padding: .1rem .5rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;

    background: var(--trr-teal-700);
    color: #05201f;
    border-radius: 999px;
}

.filmkarte-text { padding: .9rem .9rem 1rem; }

.filmkarte-titel {
    margin: 0 0 .35rem;
    font-family: var(--bs-body-font-family);
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.25;
}

.filmkarte-inhalt {
    margin: 0 0 .5rem;
    font-size: .9375rem;
    line-height: 1.5;
    color: var(--trr-ink);
}

.filmkarte-trailer { font-size: .875rem; font-weight: 600; }

/* Auf dem Telefon eine Karte je Zeile, ueber die ganze Breite.
   ----------------------------------------------------------------------
   Ab hier passen keine zwei Karten mehr nebeneinander (2 x 15 + 1,5 =
   31,5rem), und eine einzelne Karte von 17rem liess daneben ein Drittel
   des Bildschirms leer. Genau dort, wo am wenigsten Platz ist, wurde am
   meisten verschenkt.

   Die Obergrenze faellt dafuer weg: Auf einem Telefon ist ein Filmplakat
   ueber die volle Breite kein Aufwand, sondern das, wofuer man das Geraet
   in die Hand nimmt. */
@media (max-width: 33em) {
    .filmkarte {
        flex-basis: 100%;
        max-width: none;
    }
}

/* ------------------------------------------------ Die Wertung darunter

   Eine Zeile je Film: Titel links, Balken in der Mitte, Stimmen rechts.

   Auf der Karte stand der Stand zuerst -- ein Kaestchen unten rechts und
   eine Kante am unteren Rand. Auf dem Schreibtisch liess sich das
   vergleichen, weil die Karten nebeneinander stehen. Auf dem Telefon
   stehen sie untereinander, und dann liegt zwischen zwei Zahlen ein ganzes
   Plakat. Vergleichen kann man nur, was man gleichzeitig sieht.

   Und sie steht immer da, auch ohne eine einzige Stimme: Dann sind alle
   Balken leer und ueberall steht "0 Stimmen". Das ist eine Auskunft. Gar
   nichts anzuzeigen sah aus, als sei die Wahl noch nicht eroeffnet. */

.film-wertung {
    list-style: none;
    margin: 1.75rem auto 0;
    padding: 0;
    max-width: 34rem;

    display: flex;
    flex-direction: column;
    gap: .6rem;
}

.film-wertung-zeile {
    display: grid;
    grid-template-columns: minmax(0, 10rem) 1fr auto;
    align-items: center;
    gap: .5rem .9rem;
}

/* Ein Titel darf umbrechen, aber nicht die Spalte sprengen: "Zurueck in die
   Zukunft" ist laenger als die zehn Zentimeter, die ihm zustehen. */
.film-wertung-titel {
    min-width: 0;
    font-size: .9375rem;
    line-height: 1.3;
    color: var(--trr-ink-soft);
}

/* Der fuehrende Film in der Marke -- dieselbe Aussage wie das Schild "vorn"
   auf seinem Plakat. */
.film-wertung-zeile.ist-vorn .film-wertung-titel {
    font-weight: 700;
    color: var(--trr-ink);
}

.film-wertung-balken {
    min-width: 0;
    background: rgba(255, 255, 255, .08);
}

.film-wertung-zahl {
    font-size: .875rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--trr-ink-soft);
}

.film-wertung-zeile.ist-vorn .film-wertung-zahl { color: var(--trr-teal-700); }

/* Auf dem Telefon der Balken auf eigener Zeile.
   ----------------------------------------------------------------------
   Drei Spalten in einem 320 Punkte breiten Fenster liessen vom Balken
   zwei Zentimeter uebrig, und ein Balken von zwei Zentimetern zeigt
   nichts mehr. Titel und Zahl bleiben zusammen in einer Zeile -- sie
   gehoeren zusammen wie Frage und Antwort. */
@media (max-width: 30em) {
    .film-wertung-zeile { grid-template-columns: minmax(0, 1fr) auto; }

    .film-wertung-balken {
        grid-column: 1 / -1;
        grid-row: 2;
    }
}

.film-enthalten {
    margin: 1.25rem 0 0;
    text-align: center;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* ------------------------------------------------ Die Filmwahl im Anmeldeweg

   Zwei Kaesten standen hier: einer mit den Filmen, einer mit den Stimmen.
   Das war richtig gedacht -- die Filme einmal oben mit allem, was man zum
   Entscheiden braucht, und nicht je Person wiederholt. Nur sahen die beiden
   aus wie zwei Seiten, und dazwischen ging die Verbindung verloren.

   Jetzt eine Flaeche und darin Kacheln wie ueberall sonst.

   Und alles unter "filmwahl-", nicht unter "film-".
   ------------------------------------------------------------------------
   Der Manager hat eigene .film-plakat, .film-text und .film-inhalt. Ein
   Namensvetter im selben Stylesheet ist kein zweiter Name, sondern
   derselbe: Die Kacheln hier erbten den Zweizeiler-Deckel der Managerliste
   -- daher endete jede Beschreibung mit drei Punkten -- und das Plakat die
   3,5rem der Marke daneben. Ein Praefix je Ort, dann kann das nicht
   passieren. */

/* Nebeneinander und nicht untereinander.
   ------------------------------------------------------------------------
   Quer gelegt nahm jeder Film eine ganze Zeile ein, und rechts daneben
   blieb bei drei Saetzen Beschreibung die halbe Flaeche leer. Zur Wahl
   stehen selten mehr als drei Filme -- die passen nebeneinander, und dann
   sieht man sie zusammen statt nacheinander. Dieselbe Reihe wie auf der
   Event-Seite. */
.filmwahl-reihe {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    margin-top: 1.25rem;
}

/* Der Deckel stand auf 17rem, und die Sorge dahinter war richtig: Zwei
   Filme sollen nicht zu zwei Plakatwaenden werden.
   ------------------------------------------------------------------------
   Nur hing das Plakat an der Kartenbreite -- breitere Karte hiess groesseres
   Plakat, und deshalb musste die Karte schmal bleiben. Der Preis dafuer
   stand im Text: Die Beschreibung brach nach rund 30 Zeichen um. Angenehm
   sind 45 bis 75, und zu schmal kostet dasselbe wie zu breit, nur an der
   anderen Seite -- das Auge springt dreimal so oft zurueck.

   Seit das Plakat einen eigenen Deckel hat (siehe unten), sind die beiden
   entkoppelt. Die Karte darf jetzt 27rem, das Plakat wird dabei sogar
   kleiner als vorher, und die Beschreibung kommt auf gut 50 Zeichen. Drei
   Filme fuellen damit rund 1300 Punkte statt 800. */
.filmwahl-kachel {
    flex: 1 1 15rem;
    max-width: 27rem;
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

/* Ein Plakat und keine Marke.
   ------------------------------------------------------------------------
   In der Liste des Managers ist das Bild ein Wiedererkennungszeichen und
   3,5rem breit. Hier trifft man danach seine Wahl -- also so gross, wie die
   Karte hergibt. Zwei zu drei ist das Mass eines Kinoplakats; quer
   beschnitten verliert es sein Gesicht.

   Ein Kasten mit dem Verhaeltnis und das Bild darin: So bleibt die Form
   auch dann stehen, wenn gar kein Plakat da ist. */
.filmwahl-plakat {
    position: relative;
    aspect-ratio: 2 / 3;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border-radius: var(--trr-radius-sm);
    background: linear-gradient(160deg, rgba(2, 176, 167, .12), rgba(0, 0, 0, .3));

    /* Der Deckel fuers Telefon. Ohne ihn nahm das Plakat die volle
       Kartenbreite, und die ist hier die volle Zeile: auf einem Geraet von
       390 Punkten rund 350 breit und 525 hoch. Ein Film fuellte damit mehr
       als einen Bildschirm, und wer drei vergleichen wollte, scrollte
       zwischen ihnen hin und her, statt sie zu sehen.

       12rem sind 192 Punkte -- gut ein Drittel weniger, und drei Filme
       passen in die Naehe eines Blicks. */
    width: 100%;
    max-width: 12rem;
    margin-inline: auto;
}

/* Ein eigener Deckel fuers Plakat -- der Grund, warum die Karte breiter
   werden darf.
   ------------------------------------------------------------------------
   Vorher nahm das Plakat die volle Kartenbreite, also 17rem. Jetzt 9rem,
   mittig ueber dem Text -- knapp ein Drittel dessen, was es war. Die
   Breite, die die Karte gewinnt, geht vollstaendig an die Beschreibung.

   Weiter herunter wuerde ich nicht gehen: Ein Plakat ist hier kein Schmuck,
   sondern das, woran man den Film erkennt, bevor man den ersten Satz liest.
   Unter etwa 8rem faellt der Titel darauf auseinander.
   Zwei Filme werden so auch bei 27rem Karte nicht zu Plakatwaenden -- die
   Sorge des alten Deckels ist damit an der Stelle aufgehoben, an die sie
   gehoert.

   Ab 34em stehen die Filme nebeneinander statt untereinander, und dann darf
   das Plakat noch einmal kleiner werden: Man sieht sie ohnehin zusammen,
   das Erkennen erledigt der Vergleich. Auf dem Telefon bleibt es bei den
   12rem der Grundregel -- dort steht ein Film allein, und er soll nicht
   zum Vorschaubild schrumpfen. */
@media (min-width: 34em) {
    .filmwahl-plakat {
        max-width: 9rem;
    }
}

.filmwahl-plakat img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Kein Plakat: ein Zeichen und kein leerer Kasten. Gedeckt, denn es ist
   ein Platzhalter und kein Bild. */
.filmwahl-zeichen {
    width: 30%;
    height: auto;
    color: var(--trr-teal-800);
    opacity: .55;
}

.filmwahl-text { display: flex; flex-direction: column; }

.filmwahl-titel {
    margin: 0 0 .35rem;
    font-size: 1.0625rem;
    line-height: 1.3;
    color: var(--trr-ink);
}

/* Kein Deckel: Der Veranstalter schreibt zwei, drei Saetze, und die sollen
   hier vollstaendig stehen. Hier entscheidet man sich. */
.filmwahl-inhalt {
    margin: 0 0 .625rem;
    font-size: 1rem;
    line-height: 1.45;
    color: var(--trr-ink);
}

/* Der Verweis nach unten, damit er in allen Karten auf einer Hoehe sitzt --
   auch wenn eine Beschreibung zwei Zeilen laenger ist. */
.filmwahl-trailer {
    display: inline-flex;
    align-items: baseline;
    gap: .4rem;
    margin-top: auto;
    font-size: .9375rem;
    font-weight: 600;
}

.filmwahl-trailer-icon { width: 1.1rem; height: 1.1rem; align-self: center; }

/* Wohin der Verweis fuehrt, steht dabei -- kleiner und ruhiger als der
   Verweis selbst: Es ist eine Auskunft und keine zweite Aufforderung. */
.filmwahl-wohin {
    font-size: .8125rem;
    font-weight: 400;
    color: var(--trr-ink-soft);
}

.filmwahl-zwischenkopf {
    margin: 1.75rem 0 .75rem;
    color: var(--trr-ink);
}

.filmwahl-stimmen { margin-top: .75rem; }

/* Die Person quer und nicht als Karte.
   ------------------------------------------------------------------------
   In den Schritten davor stehen die Leute als Karten nebeneinander. Hier
   nicht: Ein Filmtitel ist ein halber Satz, und in einer Karte von
   dreizehneinhalb Zentimetern bricht er nach jedem zweiten Wort um. Quer
   hat die Auswahl die ganze Breite. */
.filmwahl-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem 1.25rem;
}

.filmwahl-wer {
    display: flex;
    align-items: center;
    gap: .625rem;
    flex: 0 0 auto;
}

.filmwahl-name { font-weight: 600; color: var(--trr-ink); }

.filmwahl-knoepfe { margin-top: 0; flex: 1 1 16rem; }

/* Die Enthaltung tritt zurueck, ohne zu verschwinden: Sie ist eine gueltige
   Wahl und keine Notluke. */
.frage-knopf.ist-leise { color: var(--trr-ink-soft); }

/* Wer noch nicht gewaehlt hat, wird gezeigt und nicht nur gezaehlt. Bei
   fuenf Personen sucht man sonst, welche gemeint ist. */
.filmwahl-zeile.ist-offen {
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .1),
        0 0 0 1px var(--trr-warn);
}

.filmwahl-zeile.ist-offen .filmwahl-name { color: var(--trr-warn); }

/* Auf dem Telefon steht eine Karte je Zeile -- zwei nebeneinander waeren
   zwei Briefmarken. Die Reihe braucht dafuer nichts weiter: 15rem passen
   dort nicht zweimal, also bricht sie von selbst um. Nur der Deckel muss
   weg, sonst blieb rechts ein Streifen leer. */
@media (max-width: 34em) {
    .filmwahl-kachel { max-width: none; }
}

/* Die Enthaltungen im Stand: unter dem Strich, weil sie eine Aussage sind
   und keine Stimme. */
.wahl-zeile.wahl-enthaltung {
    margin-top: .35rem;
    padding-top: .6rem;
    border-top: 1px solid var(--trr-line);
    color: var(--trr-ink-soft);
}

.wahl-enthaltung .wahl-fuellung { background: var(--trr-ink-soft); }

/* ------------------------------------------------------ Der Stand der Wahl

   Balken in Zehnerschritten ueber Klassen und nicht ueber ein
   style-Attribut: Das faellt unter style-src der Sicherheitsregel und wird
   stillschweigend verworfen -- der Balken waere schlicht weg. Diese Falle
   hat im Projekt schon einmal zugeschnappt. */

.wahl-stand {
    list-style: none;
    margin: 0;
    padding: 0;
}

.wahl-zeile {
    display: grid;
    grid-template-columns: minmax(6rem, 12rem) 1fr 2.5rem;
    gap: .75rem;
    align-items: center;
    padding: .35rem 0;
}

.wahl-name {
    font-weight: 600;
    min-width: 0;
    overflow-wrap: break-word;
}

.wahl-balken {
    height: .55rem;
    border-radius: 999px;
    background: var(--trr-row);
    overflow: hidden;
}

.wahl-fuellung {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--trr-teal-700);
}

.wahl-0   { width: 0; }
.wahl-10  { width: 10%; }
.wahl-20  { width: 20%; }
.wahl-30  { width: 30%; }
.wahl-40  { width: 40%; }
.wahl-50  { width: 50%; }
.wahl-60  { width: 60%; }
.wahl-70  { width: 70%; }
.wahl-80  { width: 80%; }
.wahl-90  { width: 90%; }
.wahl-100 { width: 100%; }

.wahl-zahl {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    text-align: right;
    color: var(--trr-ink);
}

/* ----------------------------------------------------- Die Umfrage

   Der Satz des Veranstalters steht ueber den Zahlen und traegt sie: Er
   stellt die Frage, auf die die Balken darunter die Antwort sind. Deshalb
   groesser als der uebrige Kleintext -- er ist kein Zusatz, sondern der
   Anlass. */

.umfrage-einleitung {
    margin: 0 0 1.25rem;
    font-size: 1.0625rem;
    line-height: 1.6;
    color: var(--trr-ink);
}

/* Die Hausregel dagegen tritt zurueck: "Nur die Anzahl, nicht wer was
   geantwortet hat" beantwortet eine Frage, die man vielleicht hat -- und
   nicht die, um die es geht. */
.umfrage-regel {
    margin: 0 0 1.75rem;
    font-size: .875rem;
    line-height: 1.5;
    color: var(--trr-ink);
}

/* ==========================================================================
   Der Zeitplan

   Auf der Event-Seite wie auf dem Aushang: Tagesueberschrift, darunter
   Uhrzeit und Programmpunkt in zwei Spalten. Die Zeitspalte hat eine feste
   Breite, damit die Texte in einer Flucht stehen -- das ist der ganze
   Unterschied zwischen einem Ablauf und einer Aufzaehlung.
   ========================================================================== */

.zp-tag + .zp-tag {
    margin-top: 2.5rem;
}

.zp-tag-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .3rem .7rem;
    margin: 0 0 .75rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--trr-line);
    font-size: 1rem;
}

.zp-tag-datum {
    font-weight: 700;
    color: var(--trr-ink);
}

/* Die Ueberschrift des Tages -- "Die Traktorrallye", "The Day After". Sie
   traegt die Stimmung, das Datum die Auskunft. */
.zp-tag-titel {
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--trr-teal-700);
}

.zp-liste {
    list-style: none;
    margin: 0;
    padding: 0;
}

.zp-zeile {
    display: grid;
    grid-template-columns: 3.5rem 1fr;
    gap: .5rem 1rem;
    padding: .5rem 0;
    align-items: baseline;
}

/* Keine Linie mehr zwischen den Zeilen.
   ----------------------------------------------------------------------
   Sie stand da, als der Zeitplan in einem Kasten lag: Innerhalb eines
   Rahmens braucht es Linien, sonst verschwimmt alles zu einem Block. Ohne
   Rahmen war das Ergebnis ein Gitter aus lauter Strichen, und "frei" ist
   das Gegenteil davon.

   Was die Zeilen jetzt trennt, ist Platz -- und die Zeitspalte, die in
   der Leitfarbe steht und das Auge von Zeile zu Zeile fuehrt. Die eine
   Linie unter dem Tag bleibt: Sie trennt nicht Zeilen, sondern Tage. */

/* Tabellenziffern: Ohne sie stehen 12:00 und 18:15 verschieden breit, und
   der Doppelpunkt wandert von Zeile zu Zeile. */
.zp-zeit {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    font-weight: 600;
    color: var(--trr-teal-700);
}

.zp-text {
    color: var(--trr-ink);
}

/* Eine Zeile ohne Uhrzeit ist keine Luecke, sondern eine Anmerkung:
   "Dazwischen ca. 21:00 Uhr". Sie tritt zurueck, behaelt aber ihre Spalte --
   sonst faellt sie aus der Flucht. */
.zp-zeile.ohne-zeit .zp-text {
    color: var(--trr-ink-soft);
    font-style: italic;
}

/* ------------------------------------------------ Der Zeitplan im Manager

   Eine flache Liste und kein Kasten je Tag: Die Gruppierung entsteht beim
   Anzeigen aus dem Datum. Wer eine Zeile von Samstag auf Sonntag schiebt,
   aendert ein Datum -- er traegt sie nicht aus einem Kasten in den anderen. */

.zeitplan-kopf,
.zeitplan-zeile {
    display: grid;
    grid-template-columns: 9.5rem 6rem minmax(0, 1fr) 12rem;
    gap: .5rem;
    align-items: center;
}

.zeitplan-kopf {
    margin-bottom: .4rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.zeitplan-zeile + .zeitplan-zeile {
    margin-top: .4rem;
}

/* Auf schmalen Geraeten untereinander. Vier Felder nebeneinander ergeben
   dort vier Spalten von je 5 Zeichen Breite. */
@media (max-width: 62em) {
    .zeitplan-kopf {
        display: none;
    }

    .zeitplan-zeile {
        grid-template-columns: 9.5rem 1fr;
        padding: .75rem 0;
    }

    .zeitplan-zeile + .zeitplan-zeile {
        margin-top: 0;
        border-top: 1px solid var(--trr-line);
    }

    /* Text und Tagesueberschrift ueber die volle Breite -- sie sind die
       laengsten Eingaben. */
    .zeitplan-zeile > input[type="text"] {
        grid-column: 1 / -1;
    }
}

/* ---------------------------------------- Ein Programmpunkt im Formular

   Eingeklappt, bis man ihn braucht. Vorher stand jeder Punkt vollstaendig
   da -- mit einundzwanzig Zeichen, drei Hinweistexten und einem Bildfeld.
   Bei fuenf Punkten war das eine Wand, durch die man scrollt, um eine
   Zeile zu aendern. */

.programm-punkt > summary {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .85rem 1rem;
    cursor: pointer;
    border-radius: var(--trr-radius-sm);
    list-style: none;
}

/* Safari zeigt sonst sein eigenes Dreieck zusaetzlich zum unseren. */
.programm-punkt > summary::-webkit-details-marker { display: none; }

.programm-punkt > summary:hover { background: var(--trr-row); }

/* Ohne icon-duo: Dort stehen feste Fuellungen, und die zweite Ebene ist ein
   sehr dunkles Petrol. Bei runden Zeichen -- Ball, Schallplatte -- ver-
   schwanden damit genau die Linien, an denen man sie erkennt, und uebrig
   blieb eine gefuellte Scheibe. Hier traegt currentColor, und die zweite
   Ebene bleibt gedaempft. */
.programm-summary-icon {
    width: 1.4rem;
    height: 1.4rem;
    flex: 0 0 auto;
    color: var(--trr-teal-700);
}

/* Die zweite Ebene gibt es seit der Umstellung auf sharp-light nicht mehr;
   die Regel stand hier und traf nichts. */

/* Ein Punkt ohne Zeichen behaelt den Platz. Sonst spraengen die Titel
   zeilenweise nach links und rechts, je nachdem, wer ein Zeichen hat. */
.programm-summary-leer {
    border: 1px dashed var(--trr-line);
    border-radius: 4px;
}

.programm-summary-titel {
    flex: 1 1 auto;
    font-weight: 600;
    min-width: 0;
}

/* Der Button zum Entfernen. Gedeckt, bis man ihn anfaehrt -- ein rotes
   Kreuz an jedem Punkt machte aus der Liste eine Warnung. */
/* Hoch und runter. Zwei kleine Pfeile statt eines Ziehgriffs: Ziehen ist
   auf dem Telefon fummelig und mit der Tastatur gar nicht zu bedienen --
   ein Button ist beides. */
.programm-sortieren {
    flex: 0 0 auto;
    display: inline-flex;
    gap: .1rem;
}

.programm-pfeil {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    background: none;
    border: 1px solid transparent;
    border-radius: 50%;
    color: var(--trr-ink-soft);
    cursor: pointer;
}

.programm-pfeil svg { width: .75rem; height: .75rem; }

.programm-pfeil:hover,
.programm-pfeil:focus-visible {
    background: var(--trr-row);
    border-color: var(--trr-line);
    color: var(--trr-ink);
}

.programm-weg {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    background: none;
    border: 1px solid transparent;
    border-radius: 50%;
    color: var(--trr-ink-soft);
    cursor: pointer;
}

.programm-weg svg { width: .8125rem; height: .8125rem; }

.programm-weg:hover,
.programm-weg:focus-visible {
    border-color: var(--trr-hot);
    color: var(--trr-hot);
}

.programm-summary-marke {
    flex: 0 0 auto;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-teal-700);
}

/* Das Dreieck rechts, und es dreht sich. Es steht fuer sich und traegt
   keine Bedeutung -- deshalb aus reinem CSS und nicht als Zeichen. */
.programm-punkt > summary::after {
    content: "";
    flex: 0 0 auto;
    width: .5rem;
    height: .5rem;
    border-right: 2px solid var(--trr-ink-soft);
    border-bottom: 2px solid var(--trr-ink-soft);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .18s ease;
}

.programm-punkt[open] > summary::after {
    transform: rotate(-135deg) translate(-2px, -2px);
}

@media (prefers-reduced-motion: reduce) {
    .programm-punkt > summary::after { transition: none; }
}

/* --------------------------------------------- Der Rollbalken im Fenster

   macOS blendet Rollbalken aus, bis jemand rollt. Auf einer Seite ist das
   in Ordnung -- man sieht am abgeschnittenen Text, dass es weitergeht. In
   einem Fenster nicht: Dort schliesst der Inhalt buendig mit dem Rand ab,
   und es sieht aus, als waere das schon alles gewesen.

   Deshalb hier ein Balken, der immer da ist. Nur im Fenster: Auf der Seite
   soll der Browser tun, was das System vorgibt. */

/* Zuerst muss ueberhaupt gerollt werden koennen.

   Bootstrap deckelt dafuer die Hoehe von .modal-content und laesst
   .modal-body ueberlaufen. Das setzt voraus, dass .modal-body ein direktes
   Kind ist -- hier liegt aber ein <form> dazwischen, weil Kopf, Inhalt und
   Fuss zu einem Formular gehoeren. Damit war das Formular das einzige Kind,
   wuchs mit seinem Inhalt, und das Fenster lief unten aus dem Bild.

   Das Formular reicht die Hoehe jetzt durch. min-height: 0, weil ein
   Flex-Kind sonst nicht kleiner wird als sein Inhalt -- der uebliche
   Stolperstein an dieser Stelle. */
.modal-dialog-scrollable .modal-content > form {
    display: flex;
    flex-direction: column;
    min-height: 0;
    max-height: 100%;
}

.modal-dialog-scrollable .modal-content > form > .modal-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.modal-dialog-scrollable .modal-body {
    scrollbar-width: thin;
    scrollbar-color: var(--trr-line) transparent;
}

.modal-dialog-scrollable .modal-body::-webkit-scrollbar { width: 10px; }

.modal-dialog-scrollable .modal-body::-webkit-scrollbar-track {
    background: transparent;
}

.modal-dialog-scrollable .modal-body::-webkit-scrollbar-thumb {
    background: var(--trr-line);
    border: 3px solid transparent;
    background-clip: content-box;
    border-radius: 999px;
}

.modal-dialog-scrollable .modal-body::-webkit-scrollbar-thumb:hover {
    background: var(--trr-ink-soft);
    background-clip: content-box;
}

/* Auf dem Telefon rollt nicht das Fenster, sondern die Seite.
   ------------------------------------------------------------------------
   Der gemalte Balken oben hilft dort nichts: iOS kennt keine Rollbalken, die
   stehen bleiben -- sie sind Ueberlagerungen und erscheinen nur waehrend der
   Bewegung. Ein Fenster mit gedeckelter Hoehe sieht damit aus, als waere der
   Text zu Ende, und der Button am festen Fuss bestaetigt es noch: Er steht
   ja schon da, also ist man wohl unten.

   Also andersherum. Das Fenster waechst auf seine volle Hoehe, und gerollt
   wird die Seite dahinter -- mit dem Balken, den das Telefon selbst zeigt
   und den jeder kennt. Der Button rutscht damit ans Ende des Textes: Wer ihn
   erreicht, ist durch.

   Es hebt genau die drei Deckel auf, die Bootstrap und die Regeln oben
   setzen. Auf dem Desktop bleibt alles, wie es ist -- dort ist ein Fenster,
   das ueber den Bildschirmrand hinauswaechst, das groessere Uebel. */
@media (max-width: 575.98px) {
    .modal-dialog-scrollable {
        height: auto;
    }

    .modal-dialog-scrollable .modal-content,
    .modal-dialog-scrollable .modal-content > form {
        max-height: none;
        overflow: visible;
    }

    .modal-dialog-scrollable .modal-body,
    .modal-dialog-scrollable .modal-content > form > .modal-body {
        overflow-y: visible;
    }
}

/* ------------------------------------------------- Die Highlight-Tabelle

   Eine Zeile je Highlight, und jede Aenderung wirkt sofort. Vorher war es
   ein Formular mit einem Speichern-Button am Ende; wer zwischendurch wegging,
   verlor alles Eingetippte -- und suchte den Fehler danach bei sich. */

.hl-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

/* Events Spaltenbreiten und nicht der automatische Umbruch: Sonst richtet
   sich jede Spalte nach ihrem laengsten Inhalt, und die Zeilen springen
   nebeneinander hin und her -- eine Zeile mit "Zum Modul" schob die Buttons
   der Zeile darueber nach links. */
.hl-tabelle {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
}

/* Die Kopfzeile traegt nur die Spalte "Anzeigen" sichtbar -- die anderen
   erklaeren sich aus dem, was darunter steht. */
.hl-tabelle thead th {
    padding: 0 .5rem .5rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
    text-align: left;
    border-bottom: 1px solid var(--trr-line);
}

.hl-tabelle tbody td {
    padding: .625rem .5rem;
    border-bottom: 1px solid var(--trr-line);
    vertical-align: middle;
}

/* Ausgeblendet heisst blass und nicht durchgestrichen: Der Eintrag ist
   nicht falsch, er steht nur gerade nicht auf der Seite. */
.hl-zeile.ist-aus .hl-was { opacity: .45; }

.hl-sortieren {
    width: 2.5rem;
    padding-right: 0 !important;
}

.hl-sortieren form { display: block; }

.hl-sortieren .programm-pfeil { width: 1.5rem; height: 1.25rem; border-radius: 4px; }

.hl-sortieren .programm-pfeil:disabled {
    opacity: .25;
    cursor: default;
    background: none;
    border-color: transparent;
}

/* Die Zelle bleibt eine Zelle -- display:flex haette sie aus der Tabelle
   genommen, und die Trennlinien brachen zwischen den Spalten auf. Die
   Ausrichtung macht deshalb eine Huelle darin. */
.hl-was-inhalt {
    display: flex;
    align-items: center;
    gap: .75rem;
}

.hl-icon {
    flex: 0 0 auto;
    width: 1.5rem;
    height: 1.5rem;
    color: var(--trr-teal-700);
}

/* Ein Punkt ohne Zeichen bekommt trotzdem den Platz: Sonst stuenden die
   Titel zeilenweise verschoben untereinander. */
.hl-icon-leer { display: inline-block; }

.hl-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.hl-titel {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Die zweite Zeile haelt ihre Hoehe auch dann, wenn nichts darin steht.
   Ohne das waeren die Zeilen mit und ohne Beschreibung verschieden hoch,
   und die Tabelle saehe aus, als haette jemand geschubst. */
.hl-schlagwort,
.hl-herkunft {
    min-height: 1.2em;
    font-size: .875rem;
    color: var(--trr-ink-soft);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.hl-herkunft { font-style: italic; }

/* Nicht umbrechen: "Anzei-" ueber "gen" las sich wie ein Fehler. */
.hl-schalter {
    width: 6rem;
    white-space: nowrap;
}

/* Der Schalter ist ein Button und kein Kaestchen: Er schickt ein Formular ab,
   und ohne Skripte tut er genau dasselbe. */
.hl-toggle {
    display: inline-flex;
    align-items: center;
    width: 2.5rem;
    height: 1.375rem;
    padding: 2px;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    border-radius: 999px;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease;
}

.hl-toggle-button {
    width: 1rem;
    height: 1rem;
    background: var(--trr-ink-soft);
    border-radius: 50%;
    transition: transform .15s ease, background .15s ease;
}

.hl-toggle.ist-an {
    background: var(--trr-teal-700);
    border-color: var(--trr-teal-700);
}

.hl-toggle.ist-an .hl-toggle-button {
    background: #fff;
    transform: translateX(1.125rem);
}

.hl-toggle:focus-visible {
    outline: 2px solid var(--trr-teal-700);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .hl-toggle,
    .hl-toggle-button { transition: none; }
}

.hl-tun {
    width: 8.5rem;
    white-space: nowrap;
    text-align: right;
}

.hl-tun .btn { width: 100%; }

/* Die Spalte fuers Kreuz bleibt auch dort stehen, wo es keins gibt: Ein
   Modul laesst sich nicht loeschen, aber seine Zeile soll deshalb nicht
   anders breit sein als die daneben. */
.hl-weg {
    width: 2.5rem;
    text-align: right;
}

/* Auf dem Telefon rutscht die Tabelle sonst aus dem Bild. Scrollen ist hier
   die ehrlichere Loesung als eine Zeile, die in vier Zeilen zerfaellt. */
@media (max-width: 40em) {
    .hl-tabelle-huelle { overflow-x: auto; }
    .hl-tabelle { min-width: 32rem; }
    .hl-was-inhalt { gap: .5rem; }
}

/* ------------------------------------------------- Die Zeichenauswahl

   Kaestchen mit Bild statt einer Auswahlliste: Wer ein Zeichen sucht,
   sucht ein Bild und keinen Namen. In einer Liste stuende "Huepfburg",
   und man muesste raten, wie es aussieht. */

.zeichen-wahl {
    border: 0;
    padding: 0;
    margin: 0 0 1rem;
}

.zeichen-gitter {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(5.25rem, 1fr));
    gap: .5rem;
}

.zeichen-feld {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .35rem;
    padding: .6rem .3rem .5rem;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    cursor: pointer;
    text-align: center;
}

/* Der Button selbst ist unsichtbar -- angefasst wird das Kaestchen. Nicht
   display:none: Ein so verstecktes Feld ist fuer die Tastatur nicht mehr
   erreichbar und faellt aus der Reihenfolge. */
.zeichen-feld input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.zeichen-feld:hover {
    border-color: var(--trr-teal-600);
}

/* Ein Weg und nicht zwei.
   ----------------------------------------------------------------------
   Hier stand zusaetzlich eine Klasse ".ist-gewaehlt", die der Server auf das
   gerade gesetzte Feld schrieb -- angeblich, damit es auch ohne JavaScript
   stimmt. Sie war falsch gedacht und hat einen Fehler gebaut: Klickte man
   ein anderes Feld an, blieb das alte tuerkis stehen, und zwei sahen
   gewaehlt aus. Der Server kann es nicht besser wissen; er hat die Seite
   ausgeliefert, bevor geklickt wurde.

   :has(input:checked) braucht gar kein JavaScript. Es folgt dem Button
   selbst -- auch beim ersten Aufbau, denn dort setzt der Server ja das
   "checked". Dieselbe Regel wie bei den Rollen- und Umfragefeldern. */
.zeichen-feld:has(input:checked) {
    border-color: var(--trr-teal-700);
    background: var(--trr-teal-050);
    box-shadow: 0 0 0 1px var(--trr-teal-700);
}

.zeichen-feld:has(input:focus-visible) {
    outline: 2px solid var(--trr-teal-700);
    outline-offset: 2px;
}

.zeichen-bild {
    width: 1.5rem;
    height: 1.5rem;
    color: var(--trr-ink);
}

.zeichen-keins {
    font-size: 1.25rem;
    line-height: 1.5rem;
    color: var(--trr-ink-soft);
}

.zeichen-wort {
    font-size: .8125rem;
    color: var(--trr-ink-soft);
    line-height: 1.2;
}

/* ------------------------------------------------------ Die gezeichneten Glaeser
 *
 * Sie stehen an vier Stellen: in der Auswahl, in der Arbeitsliste des
 * Bar-Mixers, auf der Karte der Gaeste und auf dem Monitor an der Bar. Vier
 * Groessen, aber ein Aussehen -- deshalb hier und nicht viermal verstreut.
 *
 * Die Dateien sind schwarze Tinte auf nichts. Das ist die Fassung fuers
 * Papier, wo das Blatt ocker ist; auf Anthrazit waere sie unsichtbar. Statt
 * eines zweiten Satzes Dateien dreht der Browser sie um: invert macht aus
 * Schwarz Weiss und laesst die Durchsichtigkeit in Ruhe. Ein Hauch Sepia
 * nimmt dem Weiss die Haerte -- die Zeichnung soll nach Tinte aussehen und
 * nicht nach Neon.
 */
.glas-bild {
    display: block;
    width: 100%;
    height: 100%;

    /* Nie beschneiden: Ein halbes Glas ist kein Glas. Bei einer Zeichnung
       gibt es auch nichts zu fuellen -- ringsum ist ohnehin nichts. */
    object-fit: contain;

    filter: invert(1) sepia(.18);
    opacity: .9;
}

/* Auf Papier steht die Tinte wieder auf Weiss -- also so, wie sie in der
   Datei liegt. Dieselbe Haltung wie im ganzen Druck-Stylesheet. */
@media print {
    .glas-bild { filter: none; opacity: .85; }
}

/* Die Auswahl braucht groessere Felder als die Zeichenwahl daneben: Ein
   Symbol erkennt man bei 1,5 Rem, ein gestochenes Glas nicht. */
.glas-wahl .zeichen-gitter {
    grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr));
}

.glas-wahl .glas-bild {
    width: 3.25rem;
    height: 3.75rem;
}

/* Etwas mehr Luft zwischen Bild und Beschriftung als bei den Symbolen: Ein
   Martiniglas laeuft unten spitz zu, und der Fuss stand sonst auf dem
   Wort. */
.glas-wahl .zeichen-feld {
    gap: .55rem;
    padding-bottom: .6rem;
}

/* Das Zeichen neben einem Programmpunkt. Es steht an derselben Stelle wie
   ein hochgeladenes Bild und bekommt deshalb auch dessen Groesse. */
.programm-icon {
    width: 2.5rem;
    height: 2.5rem;
    color: var(--trr-teal-700);
}

/* ==========================================================================
   Die Mediathek eines Events

   Die Titelbilder nebeneinander. Bewusst grosszuegige Kacheln: Wer zwischen
   fuenf Stimmungsbildern waehlt, entscheidet nach dem Bild und nicht nach
   dem Dateinamen -- und auf einem Daumennagel sieht jedes Foto gleich aus.
   ========================================================================== */

.bild-gitter {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 1rem;
}

.bild-kachel {
    margin: 0;
    overflow: hidden;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius);
}

/* Das aktive Bild traegt die Leitfarbe. Sie sagt hier "das ist das
   ausgewaehlte" -- dieselbe Bedeutung wie beim Punkt in der Leiste. */
.bild-kachel.ist-aktiv {
    border-color: var(--trr-teal-700);
    box-shadow: 0 0 0 1px var(--trr-teal-700);
}

/* Events Form fuer alle Kacheln: Die Bilder haben unterschiedliche
   Seitenverhaeltnisse, und ein Gitter aus verschieden hohen Kacheln liest
   sich als Unordnung. 16:9 ist ausserdem das, was der Kopfbereich
   ungefaehr zeigt -- die Kachel luegt damit nicht ueber den Ausschnitt. */
.bild-kachel-bild {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    background: var(--trr-cream);
}

.bild-kachel-fuss {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    padding: .75rem;
}

.bild-kachel-mass {
    flex: 1 1 100%;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

.bild-kachel-marke {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-teal-700);
}

.bild-kachel-marke svg {
    width: .875rem;
    height: .875rem;
}

/* Die beiden Formulare sollen nebeneinanderstehen und nicht untereinander --
   ein form-Element ist von Haus aus ein Block. */
.bild-kachel-fuss form {
    margin: 0;
}

/* Loeschen sieht aus wie die uebrigen Neben-Buttons und wird erst beim
   Ueberfahren rot. Ein dauerhaft rotes Element auf jeder Kachel machte aus
   der Mediathek eine Warnung.

   Die Regel hiess einmal .bild-kachel-weg und galt nur hier. Sie wird
   inzwischen auch auf der Cocktailkarte gebraucht -- und ein Loeschen, das
   an der einen Stelle rot wird und an der anderen tuerkis, ist ein
   Loeschen, das man an der zweiten Stelle nicht als solches erkennt. */
.btn-weg:hover,
.btn-weg:focus-visible {
    --bs-btn-hover-bg: transparent;
    --bs-btn-hover-color: var(--trr-hot);
    --bs-btn-hover-border-color: var(--trr-hot);
}

/* ==========================================================================
   Events
   ========================================================================== */

/*
 * Hoechstens drei nebeneinander.
 *
 * Mit blossem auto-fill wurden es auf einem breiten Schirm vier und fuenf.
 * Die Karten wurden dabei nicht besser, nur zahlreicher: Ein Bild im
 * Verhaeltnis 16 zu 9 auf ein Fuenftel der Breite ist eine Briefmarke, und
 * die Ueberschrift bricht nach jedem zweiten Wort.
 *
 * Die Untergrenze ist deshalb nicht mehr nur 19rem, sondern das Groessere aus
 * 19rem und einem Drittel der Reihe. Damit passen nie mehr als drei hinein --
 * und auf schmalen Schirmen greift weiter die 19rem und macht von selbst zwei
 * daraus und dann eine. Ohne Umbruchpunkt: Es gibt keine Breite, an der man
 * das festmachen muesste.
 */
/* Hoechstens zwei Karten nebeneinander -- drei erst auf einem grossen Schirm.
   ------------------------------------------------------------------------
   Die Regel rechnete vorher immer mit Dritteln. Auf dem Tablet ist der
   Inhaltsbereich 1140 Bildpunkte breit, ein Drittel davon sind 366 -- und in
   366 Punkte passen vier Ringe, zwei Kaesten und eine Bildleiste nicht. Die
   Karte quetschte sich, und bei einem einzelnen Event stand sie als schmale
   Saeule neben zwei Dritteln Nichts.

   Der Umbruch haengt am Fenster und nicht am Raster: .container springt bei
   1400 Bildpunkten von 1140 auf 1320, und erst dort sind Drittel wieder
   breit genug (426). Darunter zwei, und auf dem Telefon greift das
   19rem-Mindestmass und macht daraus eine. */
.event-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(max(19rem, (100% - 1.25rem) / 2), 1fr));
    gap: 1.25rem;
}

@media (min-width: 1400px) {
    .event-grid {
        grid-template-columns: repeat(auto-fill, minmax(max(19rem, (100% - 2 * 1.25rem) / 3), 1fr));
    }
}

.event-card {
    display: flex;
    flex-direction: column;
    background: var(--trr-paper);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius);
    box-shadow: var(--trr-shadow-sm);
    overflow: hidden;
}

.event-card.is-past { opacity: .62; }
.event-card.is-past:hover { opacity: 1; }

.event-card-media {
    position: relative;
    display: block;
    aspect-ratio: 16 / 9;
    background: var(--trr-teal-050);
    overflow: hidden;
}

.event-card-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.event-card-placeholder {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--trr-teal-600);
    opacity: .4;
}

.event-card-status {
    position: absolute;
    top: .625rem;
    left: .625rem;
    /* Auf einem Foto braucht das Abzeichen einen eigenen Grund, sonst geht
       es je nach Motiv unter. */
    backdrop-filter: blur(6px);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
}

/* Der Eckstreifen "Hauptevent".
   ------------------------------------------------------------------------
   Zwei Kaesten, und beide muessen sein: der aeussere ist das Quadrat in der
   Ecke und schneidet ab, der innere ist der gedrehte Streifen. Ohne den
   aeusseren stuenden die Enden des Streifens ueber der Bildkante -- die
   Karte hat zwar selbst overflow: hidden, aber der Streifen soll an der
   Ecke enden und nicht am Kartenrand.

   Die Masse haengen zusammen, und zwar ueber den Satz des Pythagoras: Der
   Streifen liegt rund 4,5rem von der Ecke entfernt, und die sichtbare
   Strecke ueber die Ecke ist das Wurzel-Zwei-fache davon -- gut 6,3rem.
   "HAUPTEVENT" braucht bei .75rem gesperrt knapp 5,6rem. Wer die Schrift
   groesser macht, muss "top" mitwachsen lassen, sonst schneidet die Ecke
   Buchstaben ab; und wer den Streifen kuerzer macht, sieht seine Enden
   mitten im Bild stehen statt am Rand verschwinden.

   pointer-events: none, weil das Ganze auf einem Verweis liegt: Ein
   Schmuckstueck, das Klicks abfaengt, macht eine tote Ecke. */
.event-card-haupt {
    position: absolute;
    top: 0;
    right: 0;
    width: 9.5rem;
    height: 9.5rem;
    overflow: hidden;
    pointer-events: none;
}

.event-card-haupt > span {
    position: absolute;
    top: 2.5rem;
    right: -3.5rem;
    width: 13rem;
    padding: .25rem 0;

    transform: rotate(45deg);
    text-align: center;
    white-space: nowrap;

    /* Der Markenton als Flaeche, fast Schwarz als Schrift.
       -------------------------------------------------------------------
       Hier stand var(--trr-bg) -- ein Token, das es in dieser Palette gar
       nicht gibt. Eine ungueltige Farbe faellt ersatzlos weg, und der
       Streifen erbte die Schriftfarbe des Verweises, auf dem er liegt:
       dunkles Tuerkis auf hellem Tuerkis, 1,3:1.

       Schwarz und nicht Weiss, und das ist keine Geschmacksfrage: Weiss
       kaeme auf #2ac7bd auf 2,1:1 und waere damit unlesbar. Der dunkle Ton
       kommt auf 7,9:1.

       --trr-on-primary ist derselbe Ton, der auf jedem Markenknopf steht.
       Damit traegt der Streifen dieselbe Paarung wie der Rest des Portals
       und nicht seine eigene. */
    background: var(--trr-teal-600);
    color: var(--trr-on-primary);

    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;

    box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
}

/* Im Druck kehrt sich das Verhaeltnis um: Dort ist der Markenton dunkel
   (#00615a), und der dunkle Schriftton darauf kaeme auf 2,9:1. Weiss sind
   7,4:1 -- die einzige Stelle in diesem Stylesheet, an der Weiss die
   richtige Antwort ist, und genau dafuer gibt es den Druckabschnitt. */
@media print {
    .event-card-haupt > span {
        color: #ffffff;
        box-shadow: none;
    }
}

/* Auf schmalen Karten faellt eine 9,5rem-Ecke zu breit aus -- sie reichte
   dann bis in die Bildmitte. Alles einen Schritt kleiner, das Verhaeltnis
   bleibt. */
@media (max-width: 35.9375em) {
    .event-card-haupt { width: 8rem; height: 8rem; }

    .event-card-haupt > span {
        top: 2.4rem;
        right: -3.1rem;
        width: 11rem;
        font-size: .6875rem;
        letter-spacing: .04em;
    }
}

.event-card-body {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    padding: 1rem 1.125rem 1.125rem;
    flex: 1;
}

.event-card-title {
    font-size: 1.125rem;
    margin: 0;
}

.event-card-title a {
    color: inherit;
    text-decoration: none;
}

.event-card-title a:hover { color: var(--trr-teal-700); }

.event-card-time {
    margin: 0;
    font-size: .9375rem;
    color: var(--trr-teal-700);
    font-variant-numeric: tabular-nums;
}

/*
 * Der Antwortstand: drei Ringe.
 * --------------------------------------------------------------------------
 * Hier stand einmal "3 Familien, 10 Personen" -- die Einladung. Wer auf die
 * Planungsseite geht, will aber die Antwort darauf: Wer hat zugesagt, wer
 * abgesagt, von wem kam nichts. Das ist die Frage, mit der man diese Seite
 * aufmacht.
 *
 * Drei Ringe nebeneinander und keine gestapelten Balken: Es sind drei Anteile
 * desselben Ganzen, und in einem Balken haetten die kleinen keine Beschriftung
 * mehr. Jeder Ring traegt seinen Prozentsatz in der Mitte und darunter die
 * absoluten Zahlen -- der Anteil sagt, wie weit man ist, die Zahl sagt, wen
 * man noch anrufen muss.
 */
.stand-reihe {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: .5rem;
    margin: .25rem 0 0;
    padding: .875rem .75rem .75rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/*
 * Der vierte Ring misst etwas anderes und steht deshalb abgesetzt.
 *
 * Die drei links sind Anteile desselben Ganzen und ergaenzen sich zu hundert.
 * Die Auslastung zaehlt Personen gegen das Limit -- ohne Trennung liest man
 * vier Teile einer Torte, und dann ergeben sie zusammen 175 Prozent.
 *
 * Der Strich ist ein eigenes Element in der Auszeichnung und kein ::before am
 * Kasten. Als Pseudoelement stuende er in der Auto-Platzierung vor dem ersten
 * Ring statt zwischen dem dritten und vierten -- ausprobiert, und die Reihe
 * fiel auseinander. Seine Spalte gehoert zum Raster und ist keine Umrandung
 * am Ring: So bleiben alle vier Ringe gleich breit.
 */
.stand-reihe.hat-auslastung {
    grid-template-columns: repeat(3, 1fr) 1px 1fr;
}

/* Sichtbar, aber nicht laut: --trr-line kommt auf dem Grund der Reihe auf
   1,2:1 und waere ein Strich, den niemand findet. Der Ton der leisen Schrift
   traegt weit genug. */
.stand-trenner {
    align-self: stretch;
    margin: .125rem 0;
    background: var(--trr-ink-soft);
    opacity: .6;
}

.stand-teil {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: .25rem;
    min-width: 0;
}

.stand-ring {
    display: block;
    width: 100%;
    max-width: 4.5rem;
    height: auto;
}

/* Der Grundring ist die Skala und soll nicht mitreden: dieselbe Staerke,
   aber in der Linienfarbe. */
.ring-grund {
    fill: none;
    stroke: var(--trr-line);
    stroke-width: 3.5;
}

/*
 * Der gefuellte Teil beginnt oben und laeuft im Uhrzeigersinn.
 *
 * Ohne die Drehung faengt ein SVG-Kreis rechts an -- man liest den Anteil
 * dann gegen jede Uhr, die man je gesehen hat. Die runde Kappe laesst den
 * Anfang weich auslaufen; bei sehr kleinen Anteilen ist sie ausserdem das
 * Einzige, was ueberhaupt zu sehen waere.
 */
.ring-teil {
    fill: none;
    stroke-width: 3.5;
    stroke-linecap: round;
    transform: rotate(-90deg);
    transform-origin: 50% 50%;
}

.ring-zahl {
    /* In Einheiten des viewBox, nicht in rem: So waechst die Zahl mit dem
       Ring, wenn die Karte breiter wird. */
    font-size: 9px;
    font-weight: 700;
    fill: var(--trr-ink);
    text-anchor: middle;
    dominant-baseline: central;
    font-variant-numeric: tabular-nums;
}

/*
 * Ampel, und zwar dieselbe wie sonst im Portal.
 *
 * Gruen heisst hier wie ueberall "erledigt", Rot "weg", Grau "noch nichts".
 * Eine eigene Farbwelt fuer diese eine Kachel muesste man sich merken.
 */
.stand-teil.ist-zugesagt .ring-teil { stroke: var(--trr-ok); }
.stand-teil.ist-abgesagt .ring-teil { stroke: var(--trr-hot); }
.stand-teil.ist-offen    .ring-teil { stroke: var(--trr-ink-soft); }

/* Die Auslastung in der Marke -- sie ist keine gute oder schlechte Nachricht,
   sondern eine Auskunft. Erst ueber hundert wird sie eine: Dann sitzen mehr
   Leute auf der Liste, als Plaetze da sind, und jemand hat eine
   Nachrueckerfreigabe zu weit gefasst. */
.stand-teil.ist-auslastung .ring-teil { stroke: var(--trr-teal-700); }
.stand-teil.ist-auslastung.ist-drueber .ring-teil { stroke: var(--trr-hot); }
.stand-teil.ist-auslastung.ist-drueber .ring-zahl { fill: var(--trr-hot); }

/* Wer an der vollen Liste haengengeblieben ist: in Bernstein, weil er eine
   Entscheidung braucht und keine Erinnerung. */
.stand-warteliste {
    color: var(--trr-amber-600);
    font-weight: 600;
}

/*
 * Die Beschriftung eine Spur heller als das uebrige Kleingedruckte.
 *
 * Mit --trr-ink-soft waeren es 3,9:1 auf dem Grund der Reihe. Fuer eine
 * Randbemerkung ginge das durch; hier steht aber, welcher Ring welcher ist --
 * ohne diese drei Woerter sind die Prozente Farbe ohne Bedeutung. Also 5:1,
 * und die Zurueckhaltung kommt aus Groesse und Sperrung statt aus dem Grau.
 */
.stand-name {
    margin: .125rem 0 0;
    font-size: .8125rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-weight: 600;
    color: var(--trr-ink-quiet);
    line-height: 1.2;

    /* Platz fuer zwei Zeilen, auch wenn nur eine dasteht.
       ------------------------------------------------------------------
       "Keine Antwort" bricht auf schmalen Karten um, "Zugesagt" nicht --
       und dann stehen die Zahlen der dritten Spalte eine Zeile tiefer als
       die der beiden anderen. Drei Werte, die man vergleichen soll, duerfen
       nicht auf drei Hoehen liegen. Die leere zweite Zeile auf breiten
       Karten kostet dreizehn Punkte; das ist der guenstigere Handel. */
    min-height: 2.4em;

    /* Nicht mitten im Wort trennen: Bei vier Ringen wird die Spalte schmal,
       und aus "Auslastung" wurde "Auslas-tung". Lieber eine Spur kleiner. */
    hyphens: none;
    overflow-wrap: normal;
    word-break: keep-all;
}

.stand-reihe.hat-auslastung .stand-name {
    font-size: .8125rem;
    letter-spacing: .03em;
}

.stand-zahlen {
    margin: 0;
    display: flex;
    flex-direction: column;
    font-size: .875rem;
    line-height: 1.35;
    font-variant-numeric: tabular-nums;
}

/*
 * Die Familien eine Stufe zurueck.
 * --------------------------------------------------------------------------
 * Der Ring rechnet auf Koepfe, und die stehen deshalb oben in voller
 * Groesse. Die Familien sind weiterhin die Zahl, nach der man telefoniert --
 * aber nicht die, die der Prozentsatz meint. Kleiner und ruhiger sagt genau
 * das, ohne dass ein Wort dazu noetig waere.
 *
 * Nur Groesse und Farbe, keine Klammern und kein "davon": Die Zeile steht
 * unter einer Zahl derselben Sache, und das reicht als Zusammenhang.
 */
.stand-familien {
    font-size: .78125rem;
    color: var(--trr-ink-soft);
}

/*
 * Bei schmaler Karte zwei mal zwei statt vier nebeneinander.
 * --------------------------------------------------------------------------
 * Vier Ringe brauchen Platz. Auf einer 338 Punkte breiten Karte -- zwei
 * Spalten auf einem Tablett -- bleiben je Ring siebzig Punkte, und "3
 * Familien" zerfaellt in vier Zeilen.
 *
 * Eine Medienabfrage hilft hier nicht: Wie breit die Karte ist, haengt an der
 * Zahl der Spalten und nicht am Fenster. Bei 1024 Punkten sind die Karten
 * breiter als bei 1400, weil es dort nur zwei sind. Also eine Containerabfrage
 * -- die erste im Portal, und genau der Fall, fuer den es sie gibt.
 */
.event-card { container-type: inline-size; }

@container (max-width: 24rem) {
    .stand-reihe,
    .stand-reihe.hat-auslastung {
        grid-template-columns: 1fr 1fr;
        gap: .75rem .5rem;
    }

    /* Der Strich trennt nur nebeneinander. Untereinander stuende er quer
       durch die Reihe und trennte die falschen beiden. */
    .stand-trenner { display: none; }
}

/*
 * Zwei Tafeln unter den Ringen: links die Uhr, rechts die Menge.
 * --------------------------------------------------------------------------
 * Getrennt, weil es zwei Sorten Frage sind. Links laeuft etwas ab -- Termin
 * und Anmeldeschluss --, rechts steht etwas fest: wie viele eingeladen sind
 * und ob das Geld da ist.
 *
 * Beschriftung links, Wert rechts. Vorher standen drei Werte nebeneinander in
 * unterschiedlicher Groesse, und "offen" sass damit hoeher als "10 Tage" --
 * zwei Grundlinien in einer Zeile. Untereinander gibt es das Problem nicht:
 * Jede Zahl hat ihre eigene Zeile und richtet sich am rechten Rand aus.
 */
.karte-tafeln {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .5rem;
    margin: .375rem 0 0;
}

.karte-tafel {
    display: grid;
    gap: .25rem;
    margin: 0;
    padding: .5rem .625rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    align-content: start;
}

/*
 * Beschriftung ueber dem Wert und nicht daneben.
 *
 * Nebeneinander blieb rechts zu wenig Platz: "12 Pers. · 4 Fam." wurde zu
 * "12 Pers. · 4…", und eine Zahl, die man nicht zu Ende lesen kann, ist
 * keine. Untereinander hat der Wert die ganze Breite der Tafel.
 */
.tafel-zeile {
    display: grid;
    gap: 0;
    min-width: 0;
}

.tafel-zeile dt {
    font-size: .8125rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-weight: 600;
    color: var(--trr-ink-quiet);
    line-height: 1.3;

    /* "Anmeldeschluss" ist lang und darf nicht umbrechen -- sonst waechst
       genau die Zeile, die in beiden Tafeln gleich hoch sein soll. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tafel-zeile dd {
    margin: 0;
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0 .25rem;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    min-width: 0;
}

.tafel-zahl {
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: -.02em;
}

/* "heute", "morgen", "vorbei", "alle", "kostenlos" -- kein Zaehlwerk, also
   auch keine Ziffernstufe. Sie stehen in der Groesse der Einheit daneben,
   damit die Zeile nicht springt. */
.tafel-wort {
    font-size: 1rem;
    font-weight: 700;
}

.tafel-einheit {
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

/*
 * Vier Toene, und jeder heisst dasselbe wie ueberall im Portal.
 *
 * Marke: laeuft. Bernstein: da ist etwas zu tun. Gruen: erledigt. Grau: geht
 * niemanden mehr etwas an -- ein vergangenes Event faerbt nichts ein, denn
 * "vorbei" in der Marke waere eine Auszeichnung fuer die eine Karte, bei der
 * nichts mehr zu holen ist.
 */
.tafel-zeile.ist-marke .tafel-zahl,
.tafel-zeile.ist-marke .tafel-wort { color: var(--trr-teal-700); }

.tafel-zeile.ist-nah .tafel-zahl,
.tafel-zeile.ist-nah .tafel-wort { color: var(--trr-amber-600); }

.tafel-zeile.ist-gut .tafel-zahl,
.tafel-zeile.ist-gut .tafel-wort { color: var(--trr-ok); }

.tafel-zeile.ist-ruhig .tafel-zahl,
.tafel-zeile.ist-ruhig .tafel-wort { color: var(--trr-ink); }

/* Die vierte Stufe: eine gerissene Untergrenze.
   „nah" heißt, da liegt noch etwas. Das hier heißt, so findet es nicht
   statt -- derselbe Ton wie der Absage-Button, denn es ist die Zahl, die zu
   ihm führt. */
.tafel-zeile.ist-schlimm .tafel-zahl,
.tafel-zeile.ist-schlimm .tafel-wort { color: var(--trr-hot); }

/*
 * Wer bleibt -- die Abendkurve unter den Ringen.
 * --------------------------------------------------------------------------
 * Über die volle Breite und dreispaltig statt in der zweispaltigen Reihe
 * darunter: Die drei Zahlen gehören zusammen und werden von links nach
 * rechts gelesen -- 10, dann 6, dann 3. In zwei Spalten bräche die Reihe in
 * der Mitte, und aus der Kurve würden zwei Angaben und ein Rest.
 *
 * Direkt unter den Ringen und mit demselben Abstand: Sie führt deren Frage
 * weiter und ist keine neue.
 */
.karte-abend {
    margin-top: .5rem;
    padding: .5rem .625rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/* Die Überschrift innerhalb des Kastens und nicht darüber: Sie beschriftet
   ihn, und außen stünde sie zwischen zwei Blöcken und gehörte optisch zu
   keinem. Klein und gesperrt wie die Beschriftungen der Ringe darüber --
   dieselbe Sorte Wort, dieselbe Stimme. */
.karte-abend-kopf {
    margin: 0 0 .375rem;
    font-size: .6875rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    font-weight: 600;
    color: var(--trr-ink-soft);
}

.karte-abend-zahlen {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .25rem;
    margin: 0;
}

/* Auf schmalen Karten untereinander. Drei Spalten mit „Tagsüber",
   „Ab 20:00 Uhr" und „Ab 22:00 Uhr" darin brechen sonst jede Beschriftung
   um, und aus drei Zeilen werden sechs. */
@media (max-width: 30rem) {
    .karte-abend-zahlen { grid-template-columns: 1fr; }
}

.event-card-actions {
    display: flex;
    gap: .5rem;
    margin-top: auto;
    padding-top: .75rem;
    flex-wrap: wrap;
}

/* Der einzige Weg von der Karte in das Event -- also ueber die ganze Breite
   und nicht als schmaler Knubbel in der Ecke. */
.event-card-weg { flex: 1; }

/* ------------------------------------------------------------- Bildvorschau */

.event-image-preview {
    margin: 0 0 1rem;
}

.event-image-preview img {
    width: 100%;
    height: auto;
    max-height: 14rem;
    object-fit: cover;
    border-radius: var(--trr-radius-sm);
    display: block;
}

.event-image-preview figcaption {
    margin-top: .5rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
    font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------- Zulassung */

.admission-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

.admission-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: .5rem;
    border: 0;
    padding: 0;
    margin: 0;
}

.admission-item {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    cursor: pointer;
    transition: border-color .12s ease, background-color .12s ease;
}

.admission-item:hover { border-color: var(--trr-teal-600); }

.admission-item:has(input:checked) {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
}

.admission-item:has(input:focus-visible) {
    outline: 3px solid var(--trr-teal-500);
    outline-offset: 2px;
}

/* Wer keinen Geburtstag hinterlegt hat, laesst sich nicht auswaehlen.
   ------------------------------------------------------------------------
   Gedaempft und nicht versteckt -- dieselbe Machart wie beim Fahrer-Fenster:
   Wer fehlt, soll sehen, dass er fehlt, und woran es liegt. Eine Zeile, die
   gar nicht erst dasteht, sucht man vergeblich.

   Der Verweis daneben bleibt anklickbar und voll deckend: Er ist der Ausweg
   aus der Sperre und darf nicht mitgedaempft werden. */
.admission-item.ist-gesperrt {
    opacity: .55;
    cursor: default;
}

.admission-item.ist-gesperrt:hover { border-color: var(--trr-line); }

.admission-item.ist-gesperrt a {
    opacity: 1;
    position: relative;
    z-index: 1;
}

/* Der Grund in Bernstein: Es ist kein Mangel der Person, sondern etwas, das
   noch zu tun ist. Derselbe Ton wie ueberall im Portal, wo etwas aussteht. */
.admission-fehlt { color: var(--trr-amber-600); font-weight: 600; }

.admission-body { display: flex; flex-direction: column; line-height: 1.3; }
.admission-name { font-weight: 600; }
.admission-meta { font-size: .875rem; color: var(--trr-ink-soft); }

/* Die Standzeile -- immer vorhanden, immer an derselben Stelle.
   ------------------------------------------------------------------------
   Sie stand einmal hinter der Personenzahl und lief bei langen Namen um:
   mal zwei Zeilen, mal drei, und die Kacheln standen unterschiedlich hoch.
   Als eigene Zeile findet man sie, ohne zu suchen.

   min-height, damit auch die Kacheln ohne Auskunft dieselbe Hoehe haben --
   eine Reihe, in der jede zweite Kachel einen Zentimeter kuerzer ist, liest
   sich unruhig. */
.admission-stand {
    display: flex;
    align-items: center;
    gap: .3rem;

    /* Feste Zeilenhoehe statt min-height: Damit ist die Zeile in jedem Fall
       gleich hoch -- mit Symbol, mit Wort, mit Zahl. Vorher stand das Symbol
       in einem eigenen Kasten darin, und der schob die Zeile auseinander;
       Kacheln mit Warnung standen dadurch weiter unten als die uebrigen. */
    height: 1.25rem;
    line-height: 1.25rem;

    margin-top: .15rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* Bernstein wie ueberall, wo etwas offen ist -- und mit Wort statt nur mit
   Zeichen: Ein Dreieck allein ist eine Warnung ohne Inhalt, und wer Farben
   schlecht unterscheidet, liest gar nichts. */
.admission-stand.ist-offen {
    font-weight: 600;
    color: var(--trr-amber-600);
}

/* Der Punkt statt eines Warndreiecks.
   ------------------------------------------------------------------------
   Dasselbe Zeichen wie in der Modulleiste darueber, nur in Bernstein --
   gefuellt, weil er einen Zustand meldet und nicht einen abwaehlbaren
   Schalter.

   Reines CSS und kein SVG: Ein Symbol bringt eine eigene Box mit, und genau
   die schob die Zeile auseinander. Ein Punkt ist so hoch, wie man ihn macht.

   Und leiser als ein Dreieck. "Kein Zugang" sagt "noch nicht", nicht "etwas
   ist kaputt" -- ein Warnzeichen waere fuer diese Auskunft zu laut. */
.admission-punkt {
    flex: 0 0 auto;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: currentColor;
}

/* Die vordere Zahl, wenn dreimal in Folge ein Hauptevent ausgelassen wurde.
   ------------------------------------------------------------------------
   Bernstein und halbfett, sonst nichts: keine Pille, kein Rahmen. Die Zahl
   steht mitten in einer Zeile aus lauter Zahlen, und ein Kasten um eine
   davon schoebe die Zeile auseinander -- genau das, was wir hier gerade
   losgeworden sind.

   Warm und nicht rot: Das ist eine Beobachtung, kein Fehler. Und die Farbe
   ist nicht der einzige Traeger -- die Zahl selbst steht ja da. */
.admission-reihe {
    font-weight: 600;
    color: var(--trr-amber-600);
}

/* Der Punkt zwischen beiden Bilanzen. Leiser als die Zahlen, damit er
   trennt und nicht mitzaehlt. */
.admission-trenner {
    color: var(--trr-ink-quiet);
}

/* ------------------------------------------------------- Events für Gäste */

/* ==========================================================================
   Die Event-Kacheln

   Zuerst das Bild, das nach unten in die Seite auslaeuft, darunter die
   gesperrte Zeile, der Name, die Zeichen, der Satz und der Weg hinein --
   dieselbe Reihenfolge wie auf der Event-Seite.

   Eine je Zeile, getrennt durch einen kurzen Strich in der Mitte. Vier
   nebeneinander waren ein Versuch: Die Kacheln wurden schmaler, aber nicht
   kuerzer, und bei zwei Events im Jahr steht ein Raster fuer vier halb
   leer.
   ========================================================================== */

.ev-grid {
    display: flex;
    flex-direction: column;
}

.ev-card { min-width: 0; }

/*
 * Der Strich am Ende einer Kachel.
 *
 * In der Mitte und nicht ueber die ganze Breite: Eine durchgezogene Linie
 * teilt die Seite in Faecher, ein Strich mit Luft an den Seiten setzt nur
 * eine Pause. Genau das ist gemeint -- die Kacheln gehoeren zusammen, sie
 * kommen bloss nacheinander.
 *
 * Vier Zentimeter waren zu wenig: Zwischen zwei Bannern ging der Strich
 * unter und sah aus wie ein Rest. Jetzt ueber die halbe Textbreite, mit
 * weichen Enden -- so ist er zu sehen und teilt trotzdem nicht ab.
 *
 * Am Ende und nicht vor der naechsten: So schliesst er die Kachel ab, statt
 * die naechste einzuleiten -- und nach der letzten steht keiner.
 */
.ev-card:not(:last-child)::after {
    content: "";
    display: block;
    width: min(24rem, 60%);
    height: 1px;
    margin: clamp(3rem, 6vw, 5rem) auto;
    background: linear-gradient(
        to right,
        transparent,
        var(--trr-line) 25%,
        var(--trr-line) 75%,
        transparent
    );
}

/* ---------------------------------------------------------- Das Banner */

.ev-media {
    position: relative;
    border-radius: var(--trr-radius);
    background: var(--trr-paper);

    /* Ohne overflow: Der Verlauf soll ueber die untere Kante hinauslaufen
       duerfen, sonst endet er an ihr und die Kante ist wieder da. */
    overflow: hidden;
}

.ev-cover {
    display: block;
    width: 100%;

    /* Dieselben Masse wie die Tafel auf der Event-Seite: Wer von hier
       dorthin klickt, findet dasselbe Bild in derselben Groesse wieder.
       Flacher war es sparsam gedacht und wirkte gedrueckt. */
    height: clamp(16rem, 42vh, 30rem);
    object-fit: cover;
    object-position: center 45%;
}

/*
 * Der Verlauf am unteren Bildrand.
 *
 * Eine harte Kante ist ein Schnitt quer durch die Seite; so wird aus zwei
 * Flaechen eine, und der Text darunter sieht aus, als gehoere er zum Bild.
 *
 * Nicht bis ganz schwarz: Das Bild soll auslaufen und nicht abgeschnitten
 * werden. Die untere Haelfte reicht dafuer.
 */
.ev-fade {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 55%;
    background: linear-gradient(
        to bottom,
        rgba(20, 22, 26, 0) 0%,
        rgba(20, 22, 26, .45) 55%,
        var(--trr-cream) 100%
    );
}

.ev-media.ist-leer {
    height: clamp(16rem, 42vh, 30rem);
    background: linear-gradient(160deg, var(--trr-row), var(--trr-paper));
}

/* ---------------------------------------------------- Auf breiten Schirmen

   Auf dem Telefon fuellt das Banner die Breite, die da ist, und 42vh Hoehe
   sind dort ein Bild -- keine Wand. Auf einem Laptop wurde daraus ein Streifen
   von 30rem ueber 1100 Punkte Breite, und darunter kam der ganze Text: eine
   Kachel fuellte fast einen Bildschirm.

   Also nur dort schmaler und flacher. Schmaler ist dabei das Wirksamere --
   das Bild bleibt ein Bild und wird nicht zum Band. Es steht weiter in der
   Mitte, damit die Achse der Kachel dieselbe bleibt: Bild, Name, Termin, Weg
   hinein, alles auf einer Linie.

   Die Zahlen sind bewusst konservativ. Kleiner laesst sich leicht machen; zu
   klein sieht nach Briefmarke aus, und das Titelbild ist das Einzige auf
   dieser Seite, das ein Event unverwechselbar macht. */
@media (min-width: 62em) {
    .ev-media {
        max-width: 42rem;
        margin-inline: auto;
    }

    .ev-cover,
    .ev-media.ist-leer { height: clamp(13rem, 26vh, 18rem); }
}

/* Heute ist der einzige Tag, an dem die Kachel selbst eine Nachricht ist. */
.ev-card.is-today .ev-media { box-shadow: 0 0 0 2px var(--trr-teal-700); }



/* ------------------------------------------------------------ Der Text

   Alles unter dem Bild mittig und in der Breite des Textes auf der
   Event-Seite. Zwei Spalten waren ein Versuch und haben getragen -- aber
   eine Mitte traegt besser: Sie fuehrt von oben nach unten, statt den Blick
   zwischen zwei Spalten hin und her zu schicken.

   Am 30.08.2026 noch einmal versucht, diesmal mit Bild UND Text
   nebeneinander auf breiten Schirmen. Marcel hat es sich angesehen und
   verworfen -- es blieb bei dieser Mitte. Was von dem Versuch bleibt, ist
   die Frage dahinter: Auf dem Desktop war es zu viel. Die Antwort ist jetzt
   ein kleineres Bild und nicht ein anderes Raster.
   ======================================================================== */

/* Das Bild laeuft nach unten aus -- der Text ruecht deshalb dicht heran.
   Ein voller Abstand liesse die Luecke wieder als Schnitt erscheinen. */
.ev-body {
    max-width: 46rem;
    margin: .5rem auto 0;
}

.ev-kopfzeile {
    text-align: center;
    min-width: 0;
}

.ev-head {
    display: flex;
    justify-content: center;
    margin: 0 0 .4rem;
}

/* Der eigene Stand und die Warnung unter dem Datum. Neben der gesperrten
   Zeile schoben sie diese aus der Mitte -- "NOCH 13 TAGE" stand dann links
   vom Namen statt darueber. */
.ev-marken {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: .5rem .9rem;
    margin: .7rem 0 0;
}

.ev-kicker {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--trr-teal-700);
}

/* Derselbe Strich wie ueber dem Namen auf der Event-Seite. */
.ev-kicker::before {
    content: "";
    width: 1.25rem;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
}

.ev-stand {
    font-size: .8125rem;
    font-weight: 600;
    padding: .1rem .55rem;
    border-radius: 999px;
    background: var(--trr-teal-050);
    color: var(--trr-teal-700);
}

.ev-stand.is-draft { background: rgba(242, 169, 59, .12); color: var(--trr-warn); }
.ev-stand.is-out   { background: transparent; color: var(--trr-ink-soft); }

.ev-warnung {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--trr-warn);
}

.ev-warnung-icon { width: .8125rem; height: .8125rem; flex-shrink: 0; }

/* Das Band fuer ein abgesagtes Event.
   --------------------------------------------------------------------------
   Kein Abzeichen in der Markenreihe, sondern ein Kasten ueber die Breite: Es
   hebt alles auf, was sonst noch auf der Kachel steht, und darf deshalb nicht
   aussehen wie eine Angabe unter Gleichen. Derselbe Ton wie beim
   Absage-Button -- wer ihn kennt, liest ihn hier ohne das Wort.

   Links angeschlagen und nicht mittig: Der Grund kann zwei Zeilen lang
   werden, und zentrierter Flattersatz liest sich muehsam. */
.ev-ausfall {
    display: flex;
    gap: .5rem;
    margin-top: .75rem;
    padding: .625rem .75rem;
    text-align: left;
    border-radius: var(--trr-radius-sm);
    border: 1px solid color-mix(in srgb, var(--trr-hot) 40%, transparent);
    background: color-mix(in srgb, var(--trr-hot) 12%, transparent);
    font-size: .875rem;
    line-height: 1.45;
}

.ev-ausfall-icon {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
    margin-top: .15rem;
    color: var(--trr-hot);
}

/* Der Grund auf eigener Zeile: Er ist ein Zitat und keine Fortsetzung des
   Satzes davor -- hintereinanderweg gelesen wuerde aus beidem ein Satz. */
.ev-ausfall-grund {
    display: block;
    margin-top: .25rem;
    color: var(--trr-ink-soft);
}

.ev-title {
    margin: 0 0 .15rem;
    font-size: clamp(1.5rem, 2.6vw, 2rem);
    line-height: 1.15;

    /* „Rasenmaehertraktorrallyemeisterschaft" ist 37 Zeichen lang und passt in
       keine Spalte. Ohne Angabe bricht der Browser hart mitten im Wort
       ("...meisterscha / ft"); mit Trennung bricht er an den Stellen, an denen
       man es auch spricht. lang="de" steht am <html>, sonst wuerde nach
       englischen Regeln getrennt. */
    hyphens: auto;
    overflow-wrap: break-word;
}

.ev-time {
    margin: 0;
    font-size: 1rem;
    color: var(--trr-teal-700);
}

/* Der Satz liegt links an, auch wenn der Kopf darueber mittig steht.
   Zentrierter Flattersatz ueber mehrere Zeilen liest sich muehsam: Jede
   Zeile faengt woanders an, und das Auge sucht bei jedem Umbruch neu. */
.ev-text {
    margin: clamp(1.5rem, 3vw, 2.25rem) 0 0;
    font-size: 1rem;
    line-height: 1.65;
    color: var(--trr-ink);
}

/* --------------------------------------------------------- Die Highlights

   Die Pillen der Event-Seite, hier mittig in einer Reihe.

   Mit einem flachen Verlauf und einer feinen Lichtkante oben: Eine Flaeche
   in einem Ton wirkt flach, und "trist" war das Wort dafuer. Der Verlauf
   laeuft von oben hell nach unten dunkel -- so, wie Licht faellt. Er ist
   bewusst schwach; wo man ihn als Verlauf erkennt, ist er zu stark.
   ======================================================================== */

.ev-pillen {
    justify-content: center;
    gap: .45rem;
    margin: clamp(1.5rem, 3vw, 2.25rem) 0 0;
}

/* Auf der Kachel nehmen die Pillen nur so viel Platz, wie ihr Wort
   braucht -- auf der Event-Seite fuellen sie die Zeile. */
.ev-pillen .event-leiste-feld {
    flex: 0 0 auto;
    max-width: none;
    padding: .5rem 1.1rem;
}

/* ------------------------------------------------------- Wer dabei ist */

/* Ohne Strich darueber: Der eine zwischen den Kacheln reicht, und er steht
   jetzt am Ende statt mittendrin. Zwei Striche auf einer Kachel teilen
   sie in Faecher -- die Reihenfolge ist aber Text, Grafik, Text, Grafik,
   Text, und die traegt sich selbst. */
.ev-dabei {
    margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
    text-align: center;
}

.ev-dabei-kopf {
    margin: 0 0 .75rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

/* Die Gesichter ueberlappen leicht -- so liest sich die Reihe als eine
   Gruppe und nicht als Aufzaehlung. */
.ev-faces {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    row-gap: .35rem;
}

/* Sie ueberlappten sich um einen halben Zentimeter und sahen dadurch
   gequetscht aus -- bei zehn Gesichtern wurde daraus eine Wurst. Ein
   Viertel genuegt: Die Reihe bleibt eine Reihe und kein Nebeneinander, und
   jedes Gesicht ist noch als eines zu erkennen. */
.ev-faces > * + * { margin-left: -.25rem; }
.ev-faces .avatar { box-shadow: 0 0 0 2px var(--trr-cream); }

/* Wie viele nicht mehr ins Bild passen. Ein Kreis in derselben Groesse wie
   ein Gesicht -- er steht in der Reihe und nicht daneben. */
.ev-mehr {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    margin-left: -.5rem;
    border-radius: 50%;
    background: var(--trr-row);
    box-shadow: 0 0 0 2px var(--trr-cream);
    font-size: .8125rem;
    font-weight: 700;
    color: var(--trr-ink-soft);
}

.ev-tun {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.25rem;
    margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
}

/* Die Treppe steht ueber dem Rahmen.
   ==========================================================================
   Sie stand erst ganz im Kasten und ging dort unter: Die Kreise tragen den
   Grund des Papiers, und auf der Flaeche liegt derselbe Ton -- ein Kreis auf
   seiner eigenen Farbe hat keinen Rand mehr.

   Dann lag sie auf der Kante, halb drueber, halb darin. Deutlicher war sie
   damit, aber unruhig: Eine Reihe, die einen Kasten anschneidet, sieht aus,
   als sei sie verrutscht.

   Jetzt steht sie darueber, mit Abstand und auf dem dunklen Grund der Seite
   -- dort hat jeder Kreis seinen Rand. Der Kasten faengt darunter an und
   bleibt ein ganzer Kasten.

   Die eigene Flaeche bleibt: Sie haelt die beiden zusammen und ist die
   Stelle, an der der Abstand steht. */
.schritt-flaeche .step-track { margin-bottom: 1.5rem; }

/* „Save the Date" an der Stelle der Buttons.
   ----------------------------------------------------------------------
   Im Rahmen und im Markenton, in der Groesse eines Buttons -- aber ohne
   Fuellung und ohne Zeiger: Es steht dort, wo man etwas tun koennte, und
   sagt, dass es noch nichts zu tun gibt.

   Der Rahmen ist gedaempft und die Schrift nicht: Ein voller Rahmen im
   Markenton haette wie ein Button im Rahmen ausgesehen, und danach klickt
   jemand. */
.ev-termin {
    margin: 0;
    padding: .55rem 1.6rem;
    border: 1px solid rgba(2, 176, 167, .45);
    border-radius: 999px;
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--trr-teal-700);
}

/* Die Frage nach der Nachricht -- abgesetzt, weil sie nicht zur Liste
   gehoert, sondern zu dem, was beim Speichern passiert. */
.zulassung-melden {
    padding: .875rem 1rem;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
}

.zulassung-melden .form-text { margin-top: .35rem; }

/* Der Kalender steht unter dem Wort und nicht daneben.
   ------------------------------------------------------------------------
   "Save the Date" ist eine Aussage ueber den Zustand, der Knopf eine
   Handlung. Nebeneinander in derselben Reihe sahen sie aus wie zwei
   Schaltflaechen, von denen die linke nicht geht.

   flex-basis 100% bricht ihn in .ev-tun auf eine eigene Zeile -- ohne die
   Reihe selbst umzubauen, die bei allen anderen Zustaenden richtig ist. */
.ev-kalender {
    flex: 0 0 100%;

    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .6rem;

    margin-top: -.35rem;
}

/* Der Satz erklaert den Knopf, also steht er darueber und nicht darunter --
   wer ihn danach liest, hat schon geklickt. Schmal gehalten, damit er nicht
   ueber die Kachelbreite laeuft. */
.ev-kalender-satz {
    max-width: 34rem;
    margin: 0;
    font-size: .875rem;
    line-height: 1.5;
    color: var(--trr-ink-soft);
    text-align: center;
    text-wrap: balance;
}

.ev-card .absage { margin-top: 0; }




/* Auf dem Telefon stehen die Wege untereinander.
   ==========================================================================
   Nebeneinander mit Umbruch ergab eine Treppe: "Zum Event" und "Tickets
   buchen" in der ersten Zeile, unterschiedlich breit, weil die Woerter
   unterschiedlich lang sind -- und "Wir koennen nicht" allein darunter. Drei
   Buttons in drei Groessen an zwei Kanten, und keiner sah aus wie der
   naechste Schritt.

   Untereinander und alle gleich breit ist es eine Liste von Moeglichkeiten,
   und die liest man von oben nach unten. Auf dem Telefon ist das ohnehin die
   Form, die jeder kennt.

   Die Absage traegt ihren eigenen Kasten (partials/absage), deshalb steht
   sie hier mit: Ohne sie waere sie das einzige Element, das seine Breite
   behaelt. */
@media (max-width: 36em) {
    .ev-cover, .ev-media.ist-leer { height: clamp(10rem, 45vw, 16rem); }

    .ev-tun {
        flex-direction: column;
        align-items: stretch;
        gap: .625rem;
    }

    .ev-tun > *,
    .ev-tun .btn {
        width: 100%;
    }
}
/* ==========================================================================
   Event-Seite für Gäste
   ========================================================================== */

.event-hero {
    position: relative;
    border-radius: var(--trr-radius);
    overflow: hidden;
    margin: 1.25rem 0 1.75rem;
}

/*
 * Ein Band und kein Vollbild.
 *
 * Das Bild stand vorher ueber die ganze Hoehe da und schob alles andere
 * unter die Kante -- man scrollte durch ein Foto, um zu erfahren, ob man
 * angemeldet ist. Es traegt die Stimmung und nicht die Auskunft; dafuer
 * reicht ein Streifen.
 *
 * Die Hoehe haengt an der Fensterhoehe und nicht am Seitenverhaeltnis des
 * Bildes: Was den Inhalt nach unten schiebt, ist die Hoehe.
 */
.event-hero img {
    display: block;
    width: 100%;
    height: clamp(11rem, 32vh, 20rem);
    object-fit: cover;
    object-position: center 42%;
}

.event-hero-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to top,
        rgba(6, 26, 32, .92) 0%,
        rgba(6, 26, 32, .68) 40%,
        rgba(6, 26, 32, .12) 75%,
        rgba(6, 26, 32, .04) 100%
    );
}

.event-hero-text {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 1.75rem;
}

/* Ohne Bild trägt die Fläche selbst — sonst stünde die Überschrift im
   Nichts, wo bei anderen Events das Motiv des Jahres liegt. */
.event-hero-plain {
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    padding: 1.75rem;
}

.event-hero-title {
    margin: 0 0 .25rem;
    font-size: clamp(1.5rem, 4vw, 2.25rem);
    font-weight: 700;
    line-height: 1.15;
}

.event-hero-time { margin: 0; font-size: 1rem; }

.event-hero-text .event-hero-title { color: #fff; }
.event-hero-text .event-hero-time { color: rgba(255, 255, 255, .88); }

.event-hero-plain .event-hero-title { color: var(--trr-ink); }
.event-hero-plain .event-hero-time { color: var(--trr-teal-700); }

@media (max-width: 575px) {
    .event-hero img { height: clamp(9rem, 26vh, 14rem); }
    .event-hero-text { padding: 1.125rem; }
}

.event-sections { display: grid; gap: 1.25rem; }

.event-lead {
    font-size: 1.0625rem;
    font-weight: 600;
    margin-bottom: .75rem;
}

.event-text { color: var(--trr-ink); }
.event-text:last-child { margin-bottom: 0; }

/* ------------------------------------------------------- Eigene Rechnung */

.bill-lines { list-style: none; margin: 0 0 .75rem; padding: 0; display: grid; gap: .25rem; }

.bill-line {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: .75rem;
    align-items: baseline;
    padding: .5rem .75rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.bill-line.is-free { opacity: .7; }

.bill-name { font-weight: 600; }
.bill-kind { font-size: .875rem; color: var(--trr-ink-soft); }
.bill-age { opacity: .7; }
.bill-amount { font-variant-numeric: tabular-nums; font-weight: 600; }

@media (max-width: 479px) {
    .bill-line { grid-template-columns: 1fr auto; }
    .bill-kind { grid-column: 1 / -1; }
}

.bill-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: .75rem .75rem .25rem;
    border-top: 2px solid var(--trr-line);
    font-size: 1.125rem;
    font-weight: 700;
}

.bill-total.is-family { color: var(--trr-teal-700); border-top-color: var(--trr-teal-600); }
.bill-total-amount { font-variant-numeric: tabular-nums; }

.bill-hint {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    margin: .75rem 0 0;
    padding: .625rem .75rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-teal-050);
    font-size: .9375rem;
}

.bill-hint-icon { color: var(--trr-teal-600); flex: 0 0 auto; }

/* Was in dem Betrag steckt -- direkt unter der Summe.
   ------------------------------------------------------------------------
   Ohne Kasten, anders als .bill-hint darueber: Das Familienticket ist eine
   Nachricht ("ihr spart 15 Euro"), dies ist eine Erlaeuterung der Zahl, unter
   der es steht. Zwei getoente Kaesten uebereinander liessen die Summe
   zwischen ihnen verschwinden. */
.bill-enthalten,
.zahl-enthalten {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    margin: .5rem 0 0;
    font-size: .9375rem;
    line-height: 1.45;
    color: var(--trr-ink-soft);
}

.bill-note { margin: .75rem 0 0; font-size: .875rem; color: var(--trr-ink-soft); }

.event-details { margin-top: 1rem; }
.event-details summary { cursor: pointer; font-size: .9375rem; color: var(--trr-teal-700); }

.price-list { list-style: none; margin: .75rem 0 0; padding: 0; display: grid; gap: .25rem; }

.price-list li {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .375rem .75rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    font-size: 1rem;
}

.price-list-amount { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------- Fahrer, Shirts */

.driver-guest-list,
.shirt-list,
.note-list { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .375rem; }

.driver-guest {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .625rem;
    padding: .5rem .75rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.driver-guest-name { font-weight: 600; flex: 1 1 auto; }
/* Eigene Zeile statt neben dem Abzeichen: zu dritt in einer Reihe -- Name,
   Abzeichen, Hinweis -- wird es auf einem Handy eng, und der Hinweis ist der
   Teil, der dann zuerst unlesbar bricht. */
.driver-guest-note {
    flex-basis: 100%;
    font-size: .8125rem;
    color: var(--trr-warn);
}

.shirt-item {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: .75rem;
    align-items: baseline;
    padding: .5rem .75rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.shirt-name { font-weight: 600; }
.shirt-cut { font-weight: 400; font-size: .875rem; color: var(--trr-ink-soft); }
.shirt-size { font-size: .9375rem; color: var(--trr-ink-soft); }
.shirt-price { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------ Die Herstellliste

   Eine Aufgabenliste, keine Tabelle. Jede Zeile ist ein Shirt, das
   hergestellt werden muss, und der Button am Ende ist der Haken.

   Feste Spalten, damit die Buttons alle untereinander stehen: Wer zwanzig
   Stueck abarbeitet, klickt zwanzigmal auf dieselbe Stelle -- das geht nur,
   wenn sie dieselbe bleibt. Der Text dazwischen ist unterschiedlich lang und
   darf das nicht verschieben. */

/* ------------------------------------------- Umfragen und Filme, gelistet

   Beide Uebersichten zeigen dasselbe: einen Namen, eine Zeile Auskunft
   darunter, rechts der Zustand und der Weg zur eigenen Seite. Deshalb
   teilen sie sich diese Regeln -- zwei Listen, die gleich aussehen sollen,
   duerfen nicht zweimal beschrieben sein. */

.umfrage-liste,
.film-liste {
    list-style: none;
    margin: 1.25rem 0 0;
    padding: 0;
    display: grid;
    gap: .75rem;
}

.umfrage-eintrag,
.film-eintrag {
    padding: .875rem 1rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/* Name und Frage links, Zustand und Button rechts. Auf schmalen Schirmen
   untereinander -- ein Button neben einer zweizeiligen Frage draengt sonst
   beide. */
.umfrage-kopf,
.film-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: .5rem 1rem;
}

.umfrage-namen,
.film-namen { min-width: 0; flex: 1 1 18rem; }

.umfrage-name,
.film-name {
    font-weight: 600;
    color: var(--trr-ink);
    text-decoration: none;
}

.umfrage-name:hover,
.film-name:hover { color: var(--trr-teal-700); }

/* Die Frage steht unter dem Namen und ist die leisere von beiden: Den Namen
   sucht man, die Frage prueft man. */
.umfrage-frage {
    margin: .125rem 0 0;
    font-size: .9375rem;
    color: var(--trr-ink);
}

.umfrage-abzeichen,
.film-abzeichen {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex: 0 0 auto;
}

/* Der Film bringt ein Plakat mit. Es steht vorn und klein: Es soll den Film
   wiedererkennbar machen und nicht die Liste fuellen. */
.film-eintrag { display: flex; gap: 1rem; align-items: flex-start; }

/* height: auto gehoert dazu, wo aspect-ratio die Hoehe bestimmen soll.
   ------------------------------------------------------------------------
   Ein <img> mit height="1200" im Markup traegt diese Hoehe als Vorgabe des
   Browsers. width:100% ueberschreibt die Breite, aber die Hoehe blieb bei
   1200 Punkten stehen: Das Plakat auf der Filmseite war so hoch wie die
   Datei und nur so breit wie der Kasten. aspect-ratio kommt dagegen nicht
   an -- es rechnet nur, was nicht gesetzt ist. */
.film-plakat {
    flex: 0 0 auto;
    width: 3.5rem;
    height: auto;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-paper);
}

/* Ohne Plakat steht dort ein leeres Feld in derselben Groesse: Sonst
   springen die Zeilen der Liste unterschiedlich weit ein. */
.film-plakat-leer {
    display: grid;
    place-items: center;
    border: 1px dashed var(--trr-line);
    color: var(--trr-ink-soft);
}

.film-plakat-leer svg { width: 1.25rem; height: 1.25rem; }

.film-inhalt { flex: 1 1 auto; min-width: 0; }

/* Auf der Seite des Films bekommt das Plakat den Platz, den es braucht.
   In der Liste ist es eine Marke zum Wiedererkennen, hier ist es das, was
   den Film ausmacht. */
.film-plakat-gross {
    display: block;
    width: 100%;
    max-width: 15rem;
    height: auto;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.film-plakat-gross.film-plakat-leer svg { width: 2.5rem; height: 2.5rem; }

.film-text {
    margin: .125rem 0 0;
    font-size: .9375rem;
    color: var(--trr-ink);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Ueberschrift links, Reihenfolge rechts. Auf schmalen Bildschirmen
   untereinander -- zwei Buttons neben einem zweizeiligen Satz gehen sich
   sonst gegenseitig auf die Fuesse. */
.mach-kopfzeile {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: .75rem;
}

.mach-sortierung { display: flex; gap: .375rem; flex: 0 0 auto; }

.mach-liste { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .375rem; }

/* Der Familienname steht ueber seiner Gruppe und nicht in jeder Zeile --
   dieselbe Machart wie bei der Zulassung. */
.mach-kopf {
    font-size: .875rem;
    font-weight: 600;
    color: var(--trr-ink-soft);
    letter-spacing: .02em;
    padding: .75rem .25rem .125rem;
}

.mach-kopf:first-child { padding-top: .25rem; }

.mach-zeile {
    display: grid;
    grid-template-columns: 1.25rem 1fr 10.5rem;
    gap: .75rem;
    align-items: center;
    padding: .5rem .75rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/* Der Kreis vorn ist derselbe Gedanke wie in der Navigationsleiste: leer
   heisst offen, gefuellt heisst erledigt. Man liest eine Liste von links. */
.mach-punkt {
    width: 1.25rem;
    height: 1.25rem;
    display: grid;
    place-items: center;
    border: 1px solid var(--trr-ink);
    border-radius: 50%;
    color: var(--trr-on-primary);
}

.mach-punkt svg { width: .75rem; height: .75rem; }

.mach-text { min-width: 0; }

.mach-stueck {
    display: block;
    font-size: .8125rem;
    color: var(--trr-ink);
}

.mach-tun { margin: 0; }
.mach-tun .btn { width: 100%; white-space: nowrap; }

/* Erledigt: gedaempft, aber lesbar. Durchgestrichen waere es nicht -- es
   steht ja noch etwas darin, das man wissen will, naemlich fuer wen.

   Die Flaeche bleibt. Ohne sie faellt die Zeile aus der Reihe und die Liste
   sieht aus, als fehle etwas -- dabei ist genau hier etwas fertig. Der
   gefuellte Kreis und der matte Text sagen das schon. */
.mach-zeile.ist-fertig .mach-text { color: var(--trr-ink-soft); }

.mach-zeile.ist-fertig .mach-punkt {
    background: var(--trr-teal-700);
    border-color: var(--trr-teal-700);
}

/* Auf dem Handy passen drei Spalten nicht nebeneinander. Der Button rutscht
   unter den Text, der Kreis bleibt vorn -- er ist die Auskunft, die man
   beim Ueberfliegen braucht. */
@media (max-width: 34rem) {
    .mach-zeile {
        grid-template-columns: 1.25rem 1fr;
        row-gap: .5rem;
    }

    .mach-tun { grid-column: 2; }
    .mach-tun .btn { width: auto; }
}

.note-list li {
    padding: .5rem .75rem .5rem 1.75rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    position: relative;
}

.note-list li::before {
    content: "";
    position: absolute;
    left: .75rem;
    top: 1.05em;
    width: .375rem;
    height: .375rem;
    border-radius: 50%;
    background: var(--trr-teal-600);
}

/* ------------------------------------------------------------- Umfragen */

.survey-preview {
    margin-top: 1rem;
    padding: .875rem 1rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.survey-question { margin: 0; font-weight: 600; }
.survey-description { margin: .25rem 0 0; font-size: .9375rem; color: var(--trr-ink); }

.survey-options {
    list-style: none;
    margin: .625rem 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .375rem;
}

.survey-options li {
    padding: .25rem .625rem;
    border: 1px solid var(--trr-line);
    border-radius: 999px;
    background: var(--trr-paper);
    font-size: .875rem;
}

.event-signup { border-style: dashed; }

/* ==========================================================================
   Event-Module
   ========================================================================== */

/* Umbrechen statt seitwärts zu scrollen, und zwar überall.

   Ursprünglich lief die Leiste auf breiten Schirmen in einer Zeile und nur
   auf dem Handy in zwei. Mit den Spielen sind aus sieben Punkten zwölf
   geworden, und damit passt auch auf einem 1200 Pixel breiten Fenster nicht
   mehr alles nebeneinander -- der letzte Punkt lag außerhalb, ohne dass es
   jemandem auffiel. Ein Punkt, den man nicht sieht, ist schlimmer als eine
   zweite Zeile. */
.event-nav {
    display: flex;
    flex-wrap: wrap;
    gap: .125rem .25rem;
    margin-bottom: 1.75rem;
    padding-bottom: .25rem;
    border-bottom: 1px solid var(--trr-line);
}

/* Kein halbrunder Reiter mehr.
   ----------------------------------------------------------------------
   Oben rund und unten flach sagt "ich haenge an der Linie darunter". In der
   ersten Reihe ging das noch durch, in der zweiten steht darunter keine
   Linie mehr -- der Reiter hing dann an nichts. */
.event-nav-item {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .5rem .875rem;
    border-radius: var(--trr-radius-sm);
    color: var(--trr-ink-soft);
    text-decoration: none;
    white-space: nowrap;
    font-size: 1rem;
}

.event-nav-item:hover,
.event-nav-item:focus-visible {
    color: var(--trr-ink);
    background: var(--trr-row);
}

.event-nav-item.is-active {
    color: var(--trr-teal-700);
    font-weight: 600;
}

/* Die obere Reihe: die Gruppen.
   ----------------------------------------------------------------------
   Derselbe Schnitt wie in der Hauptleiste -- klein, halbfett, gesperrt, in
   Versalien, mit einem Zeichen davor. Sie sind Ueberschriften und keine
   Geschwister der Zeile darunter; ohne diesen Unterschied saehen achtzehn
   Punkte in zwei Reihen wieder aus wie achtzehn Punkte in zwei Reihen. */
.event-nav-huelle {
    margin-bottom: 1.75rem;

    /* Der Innenabstand des Streifens, oben. Unten sitzt derselbe Wert an
       der Gruppenreihe -- zusammen stellen sie sie mittig zwischen die
       beiden Linien. */
    padding-top: .625rem;
}

/* Die Zahlen des Events, über der Navigation.
   ----------------------------------------------------------------------
   Bewusst kleiner als die Kacheln auf der Fahrerauswahl: Die stehen einmal
   auf einer Seite und dürfen laut sein. Diese Leiste läuft auf achtzehn
   Seiten mit, und was überall steht, muss leise sein -- sonst liest man
   nach dem dritten Mal gar nichts mehr davon.

   Darum eine Zeile statt Kacheln, ohne Rahmen, mit dem Wert über der
   Beschriftung. Man überfliegt sie und findet die eine Zahl, die man
   gerade sucht. */
.event-kpi {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: flex-end;
    gap: .25rem 1.5rem;
    margin: 0;
    padding: 0;
}

.event-kpi-punkt {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.event-kpi-wert {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--trr-ink);
}

.event-kpi-label {
    margin: 0;
    font-size: .8125rem;
    letter-spacing: .04em;
    color: var(--trr-ink-soft);
}

/* Zwei Sorten Hervorhebung, und beide sind sparsam gemeint.
   „gut" ist das, was erreicht ist; „wach" das, wo noch etwas liegt. Mehr
   als die Zahl einzufärben passiert nicht -- eine Leiste mit vier farbigen
   Kästen wäre eine Ampelanlage. */
.event-kpi-punkt.ist-gut .event-kpi-wert  { color: var(--trr-teal-700); }
.event-kpi-punkt.ist-wach .event-kpi-wert { color: var(--trr-amber-600); }

/* Rot als dritte Stufe -- nur dort, wo eine Untergrenze gerissen ist.
   „wach" heißt: da liegt noch etwas. Das hier heißt: so findet es nicht
   statt. Der Ton ist derselbe wie beim Absage-Button, und das ist gewollt --
   es ist die Zahl, die zu ihm führt. */
.event-kpi-punkt.ist-schlimm .event-kpi-wert { color: var(--trr-hot); }

/*
 * Die Abendstärke -- eine eigene Zeile unter den gezählten Zahlen.
 * --------------------------------------------------------------------------
 * Sie sieht aus wie die Reihe darüber und ist es nicht: Dort steht, was
 * gezählt wurde, hier, was geschätzt ist. Deshalb eine Stufe leiser --
 * kleinere Zahlen, und die Überschrift „Wer bleibt" davor, die sagt, dass
 * hier eine andere Frage beantwortet wird.
 *
 * Die Überschrift steht links daneben und nicht darüber: Der Kopf trägt auf
 * achtzehn Seiten mit, und jede zusätzliche Zeile schiebt den Inhalt nach
 * unten.
 */
.event-abend {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: .75rem;
    flex-wrap: wrap;
}

.event-abend-kopf {
    margin: 0;
    font-size: .6875rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    font-weight: 600;
    color: var(--trr-ink-soft);
    white-space: nowrap;
}

/* Kleiner als die gezählte Reihe darüber: Eine Schätzung darf nicht lauter
   auftreten als eine Tatsache. */
.event-abend-zahlen {
    gap: .25rem 1.125rem;
}

.event-abend-zahlen .event-kpi-wert { font-size: 1rem; }
.event-abend-zahlen .event-kpi-label { font-size: .75rem; }

@media (max-width: 61.9375em) {
    .event-abend { justify-content: flex-start; }
}

/* Der Schnitt zwischen Menschen und Geld. Ein senkrechter Strich und kein
   größerer Abstand: Abstand allein liest sich bei umgebrochener Zeile wie
   ein Zufall. */
.event-kpi-punkt.ist-schnitt {
    padding-left: 1.5rem;
    border-left: 1px solid var(--trr-line);
}

@media (max-width: 47.9375em) {
    /* Auf dem Telefon eine scrollende Reihe statt vier Umbrüche: Die
       Leiste ist Beiwerk und darf nicht den halben ersten Bildschirm
       nehmen, bevor die eigentliche Seite anfängt. */
    .event-kpi {
        flex-wrap: nowrap;
        overflow-x: auto;
        gap: 1.25rem;
        scrollbar-width: none;
    }

    .event-kpi::-webkit-scrollbar { display: none; }
    .event-kpi-punkt { flex: 0 0 auto; }

    /* Ohne Umbruch trennt der Abstand schon genug. */
    .event-kpi-punkt.ist-schnitt { padding-left: 0; border-left: 0; }
}

/* Die obere Zeile des Streifens.
   ----------------------------------------------------------------------
   Sie traegt die Linie und den unteren Innenabstand -- frueher sass beides
   an der Gruppenreihe. Jetzt wechseln sich darin zwei Dinge ab: auf dem
   grossen Schirm die Gruppenreihe, auf dem Telefon der Aufklapper. Die
   Kante des Streifens darf davon nicht abhaengen.

   Das Zustandsabzeichen steht in beiden Faellen rechts daneben. */
.event-nav-oben {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem 1rem;
    flex-wrap: wrap;
    padding-bottom: .625rem;
    border-bottom: 1px solid var(--trr-line);
}

.event-nav-gruppen {
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom: 0;
    gap: .125rem .35rem;
    flex: 1 1 auto;
}

/* ------------------------------------------- Die Navigation auf dem Telefon

   Zwei Reihen nebeneinander gibt es dort nicht. Sie wurden zu drei
   waagerecht scrollenden Streifen, und man sah weder, wo man war, noch was
   es sonst gab -- jede Reihe musste man blind durchwischen.

   Stattdessen eine Zeile, die sagt wo man ist, und dahinter alle neunzehn
   Ziele nach Gruppen. Ein <details>: Das Aufklappen kann der Browser
   selbst, also braucht es dafuer kein Skript. */
.event-nav-handy { display: none; }

.event-nav-handy-kopf {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .625rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    cursor: pointer;
    list-style: none;   /* Das Dreieck des Browsers weg -- wir haben einen Pfeil */
}

.event-nav-handy-kopf::-webkit-details-marker { display: none; }

/* Wo man ist: Gruppe fett, Punkt dahinter. Zusammen sind sie der Satz, den
   das Telefon vorher gar nicht hatte. */
.event-nav-handy-hier { flex: 1 1 auto; font-weight: 600; min-width: 0; }

.event-nav-handy-punkt {
    font-weight: 400;
    color: var(--trr-ink-soft);
}

.event-nav-handy-punkt::before { content: ' \00b7  '; }

/* Der Pfeil dreht sich mit dem Zustand des <details> -- kein Skript noetig. */
.event-nav-handy-pfeil {
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    color: var(--trr-ink-soft);
    transition: transform .15s ease;
}

.event-nav-handy[open] .event-nav-handy-pfeil { transform: rotate(180deg); }

.event-nav-handy-liste {
    margin-top: .375rem;
    padding: .5rem 0;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-paper);
}

.event-nav-handy-gruppe {
    margin: .5rem 0 .125rem;
    padding: 0 .875rem;
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.event-nav-handy-gruppe:first-child { margin-top: 0; }

/* Ein Ziel je Zeile und ueber die volle Breite: Auf einem Telefon trifft
   man eine Zeile, keinen Reiter. */
.event-nav-handy-ziel {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .5rem .875rem;
    color: var(--trr-ink);
    text-decoration: none;
}

.event-nav-handy-ziel.is-off { color: var(--trr-ink-soft); }

.event-nav-handy-ziel.is-active {
    color: var(--trr-teal-700);
    font-weight: 600;
    background: var(--trr-row);
}

/*
 * Enger als die Reihe darunter -- und das ist eine Platzfrage.
 * ----------------------------------------------------------------------
 * Mit dem Monitor sind es neun Gruppen. In der alten Enge brauchten sie
 * rund 1400 Punkte, der Streifen ist aber auf 1296 gedeckelt: Die Leiste
 * rutschte auf zwei Zeilen, und damit war der eine Vorteil weg, den die
 * Zweiteilung hat -- oben die Gruppen, darunter ihre Punkte, in genau zwei
 * Zeilen.
 *
 * Drei Stellschrauben, alle drei ohne Verlust an Auskunft: weniger
 * Innenabstand, weniger Luft zwischen Zeichen und Wort, und die Sperrung
 * von einem Zehntel auf sechs Hundertstel. Zusammen rund 150 Punkte. Der
 * Schnitt bleibt derselbe -- klein, halbfett, gesperrt, in Versalien.
 *
 * Nicht gespart wurde am Zeichen. Daran erkennt man die Gruppe im
 * Vorbeischauen, und es ist das, was die obere Reihe von der unteren
 * unterscheidet -- oben Zeichen, unten Punkte.
 */
.event-nav-gruppen .event-nav-item {
    gap: .375rem;
    padding: .5rem .5rem;
    font-size: .875rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    border-bottom: 0;
    margin-bottom: 0;
}

/*
 * Der Zustandspunkt entfaellt in der Gruppenreihe -- nur dort.
 *
 * Er sagte dasselbe zweimal: Eine nicht zugeschaltete Gruppe steht ohnehin
 * gedaempft da (.is-off), und der hohle Kreis davor wiederholte das nur. In
 * der Reihe darunter bleibt er, denn dort ist er das einzige Zeichen -- die
 * Punkte tragen keines.
 *
 * Fuer die Vorleserin aendert sich nichts: Die Auskunft steht als Text im
 * Eintrag und war nie an diesem Kreis festgemacht.
 */
.event-nav-gruppen .event-nav-punkt { display: none; }

/* Dafuer traegt die Daempfung dort allein, was vorher zu zweit getragen
   wurde -- also etwas deutlicher als in der Reihe darunter, wo der Punkt
   danebensteht. */
.event-nav-gruppen .event-nav-item.is-off { opacity: .42; }

/* Ganz rechts in der Gruppenreihe -- dort steht er jeder Seite im Weg am
   wenigsten und faellt trotzdem ins Auge, weil rechts sonst nichts ist. */
.event-nav-zustand {
    margin-left: auto;
    align-self: center;
}

@media (max-width: 47.9375em) {
    /* In einer scrollenden Reihe waere "ganz rechts" irgendwo hinter dem
       Rand. Dann lieber gleich hinter den Gruppen. */
    .event-nav-zustand { margin-left: .5rem; }
}

.event-nav-icon {
    width: 1.05rem;
    height: 1.05rem;
    flex-shrink: 0;
}

/* Die offene Gruppe traegt einen Umriss und keine Flaeche.
   ----------------------------------------------------------------------
   Der Grund ist die Vorschau: Beim Ueberfahren bekommt eine Gruppe den
   gedeckten Grund, und wenn die offene denselben traegt, verliert man
   beim Hinuntergehen aus den Augen, wo man eigentlich ist. Ein Umriss
   ueberlebt jedes Ueberfahren, weil ihn sonst niemand bekommt. */
/* Die offene Gruppe: gefuellt und umrandet.
   ----------------------------------------------------------------------
   Die Fuellung kam bisher erst vom Skript, wenn man mit dem Zeiger
   darueberfuhr -- beim Laden stand die offene Gruppe also als leerer Umriss
   da und sah aus wie ein Button, den man noch druecken muss.

   Jetzt traegt sie beides von Anfang an, und ohne Skript genauso. Die
   Umrandung unterscheidet sie weiter von einer Gruppe, die man nur
   vorschaut: gefuellt heisst "hier siehst du gerade hin", umrandet heisst
   "hier bist du". */
.event-nav-gruppen .event-nav-item.is-active {
    color: var(--trr-teal-700);
    background: var(--trr-row);
    box-shadow: inset 0 0 0 1px var(--trr-teal-700);
}

/* Auch dann, wenn die Maus daraufsteht: Der Umriss bleibt, der gedeckte
   Grund kommt dazu. */
.event-nav-gruppen .event-nav-item.is-active:hover {
    color: var(--trr-teal-800);
    background: var(--trr-row);
}

/* Die Gruppe, deren Reihe gerade gezeigt wird -- auch wenn der Zeiger
   inzwischen unten bei den Punkten steht. Denselben Grund wie beim
   Ueberfahren: Es ist dieselbe Aussage, nur haelt sie laenger. */
.event-nav-gruppen .event-nav-item.ist-schau {
    color: var(--trr-ink);
    background: var(--trr-row);
}

/* Die Linie sitzt unter den Gruppen und nicht unter allem: Sie trennt die
   Ueberschriften von dem, was zu ihnen gehoert. Unter der zweiten Reihe
   waere sie ein Kasten um beide. */
.event-nav-unter {
    margin-bottom: 0;
    padding-left: .5rem;
    padding-top: .35rem;
    border-bottom: 0;
}

/* Derselbe abgeschraegte Balken wie in der Hauptleiste. Er faehrt einmal
   von links ein und steht dann still -- Bewegung bei der Ankunft ist
   Charakter, Dauerbewegung ist Unruhe. */
.event-nav-unter .event-nav-item::after {
    content: "";
    position: absolute;
    left: .875rem;
    right: .875rem;
    bottom: .15rem;
    height: 3px;
    background: currentColor;
    clip-path: polygon(0 0, 100% 0, calc(100% - 5px) 100%, 0 100%);
    transform: scaleX(0);
    transform-origin: left center;
    opacity: 0;
    transition: transform .26s cubic-bezier(.22, .8, .3, 1), opacity .26s ease;
}

.event-nav-unter .event-nav-item:hover::after,
.event-nav-unter .event-nav-item:focus-visible::after {
    transform: scaleX(1);
    opacity: .35;
}

.event-nav-unter .event-nav-item.is-active::after {
    transform: scaleX(1);
    opacity: 1;
}

/* Wer Bewegung abbestellt hat, bekommt den Balken sofort und ohne Einfahrt. */
@media (prefers-reduced-motion: reduce) {
    .event-nav-unter .event-nav-item::after { transition: none; }
}

/* Die vier Unterreihen liegen uebereinander in einer Zelle. So ist die Hoehe
   die der hoechsten, und beim Wechsel rueckt nichts -- die Seite darunter
   bliebe sonst bei jedem Ueberfahren in Bewegung. */
.event-nav-stapel {
    display: grid;
    border-top: 1px solid var(--trr-line);
}

.event-nav-stapel > .event-nav-unter {
    grid-area: 1 / 1;

    /* visibility und nicht display: Eine Reihe, die es nicht gibt, traegt
       auch nichts zur Hoehe der Zelle bei. */
    visibility: hidden;
}

.event-nav-stapel > .event-nav-unter.ist-offen {
    visibility: visible;
}

/* Nur wo es einen Zeiger gibt. Auf dem Telefon fuehrt ein Tippen auf die
   Gruppe zur ersten Seite darin -- eine Vorschau, die man antippen muss,
   um sie zu sehen, ist ein Klick ohne Ziel. */
@media (hover: hover) {
    .event-nav-gruppen .event-nav-item:hover {
        background: var(--trr-row);
        color: var(--trr-ink);
    }
}

.event-nav-item.is-off { opacity: .55; }

/* Hier stand das Abzeichen "aus", das hinter einem nicht zugeschalteten
   Punkt hing. Der Kreis vor dem Wort sagt dasselbe, braucht keinen Platz
   und laesst die Punkte gleich breit. */

/* Der Wechsel zum Telefon.
   ----------------------------------------------------------------------
   Hier stand einmal: lass die beiden Reihen waagerecht scrollen. Das war
   eine Notloesung -- drei scrollende Streifen uebereinander, und keiner
   davon zeigte, wo man ist.

   Jetzt tauschen die beiden Formen einfach die Plaetze: Die Reihen gehen,
   der Aufklapper kommt. Beide stehen im Dokument, es wird nichts
   umgebaut. */
@media (max-width: 47.9375em) {
    .event-nav-gruppen,
    .event-nav-stapel { display: none; }

    .event-nav-handy { display: block; flex: 1 1 100%; }

    /* Das Abzeichen unter den Aufklapper und nach links: Neben einer Zeile
       ueber die volle Breite bliebe rechts kein Platz, und darunter
       eingerueckt saehe es aus, als gehoerte es hinein. */
    .event-nav-oben {
        align-items: flex-start;
        gap: .625rem;
    }

    .event-nav-zustand { margin-left: 0; }
}

/* Die beiden Buttons ueber den Bildern.
   ----------------------------------------------------------------------
   Sie stehen ueber beiden Spalten und nicht in einer: Was man hochlaedt,
   landet mal links und mal rechts, und ein Button in einer Spalte sagte das
   Falsche. */
.bild-buttonreihe {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    margin-bottom: 1.5rem;
}

/* Die Masse im Fenster: als Liste und nicht im Fliesstext.
   ----------------------------------------------------------------------
   Genau danach sucht man, wenn man ein Bild zurechtschneidet -- und in
   einem Satz ueberliest man eine Zahl. */
.bild-masse {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: .35rem 1.25rem;
    margin: 1.25rem 0;
    padding: 1rem 1.25rem;
    border-radius: var(--trr-radius);
    background: var(--trr-row);
}

.bild-masse dt {
    font-size: .875rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
    font-weight: 600;
}

.bild-masse dd {
    margin: 0;
    color: var(--trr-ink);
}


/* Der Zeitplan: Titel und Infos untereinander.
   ----------------------------------------------------------------------
   Auf einem Aushang liest man zuerst die Spalte mit den Ueberschriften und
   erst dann, was dahinter steht. */
.zp-text {
    display: flex;
    flex-direction: column;
    gap: .15rem;
    min-width: 0;
}

.zp-titel {
    font-weight: 600;
    color: var(--trr-ink);
}

.zp-info {
    font-size: 1rem;
    line-height: 1.5;
    color: var(--trr-ink-soft);
}

/* Im Manager: die Spalte mit der Uhrzeit und die Marke am Beginn.
   ----------------------------------------------------------------------
   Eine feste Breite, weil die Tabelle table-layout: fixed traegt: Ein
   "width: 1%" hiesse dort woertlich ein Prozent, und die Uhrzeit lag unter
   dem Titel. */
.zp-spalte-zeit {
    width: 6.5rem;
    white-space: nowrap;
}

/* Damit die angesprungene Zeile nicht unter der festen Kopfleiste
   verschwindet: Der Anker landet sonst genau dort, wo die Navigation liegt,
   und man sieht die Zeile nicht, die man gerade umgelegt hat. */
.hl-zeile[id] { scroll-margin-top: 7rem; }

.hl-tabelle tbody .zp-spalte-zeit {
    vertical-align: top;
    padding-top: .8rem;
}

.zp-spalte-zeit .zp-zeit {
    display: block;
    font-variant-numeric: tabular-nums;
    color: var(--trr-ink);
}

/* Die Marke unter der Uhrzeit und nicht daneben: Nebeneinander passte
   "14:00 BEGINN" in keine Spalte, die schmal genug bleibt. */
.zp-start {
    display: inline-block;
    margin-top: .2rem;
    padding: .0625rem .375rem;
    border-radius: 999px;

    font-size: .8125rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    background: var(--trr-teal-050);
    color: var(--trr-teal-800);
}

/* Der Tag im Kopf des Fensters -- kleiner als der Titel, damit klar ist,
   dass er beschreibt und nicht benennt. */
.modal-title-tag {
    display: block;
    margin-top: .15rem;
    font-size: .875rem;
    font-weight: 400;
    color: var(--trr-ink-soft);
}

/* Die zweite Zeile in einer Tabellenzelle -- kleiner und gedeckt. */
.cell-sub {
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* Die Zulassungsliste: Gruppen, Namen, Bilanz.
   ----------------------------------------------------------------------
   Drei Gruppen, und die oberste ist die, die man in neun von zehn Faellen
   einfach durchhakt. */
/* Gruppenkoepfe in Listen -- bei der Zulassung und bei den Anmeldungen.
   ----------------------------------------------------------------------
   Beide Listen zeigen dieselben Familien, nur nach anderen Faechern
   sortiert: dort "wer darf", hier "wer hat". Dass sie gleich aussehen, ist
   deshalb kein Zufall, sondern der Punkt -- wer von der einen zur anderen
   wechselt, soll dieselbe Liste wiedererkennen.

   Ein gemeinsamer Satz Regeln und nicht zwei gleiche: Sonst zieht man beim
   naechsten Feilen einen nach und den anderen nicht. */
.admission-gruppe,
.booking-gruppe {
    /* Ueber die ganze Reihe und nicht als Kachel daneben: Eine
       Ueberschrift, die sich in dieselbe Spalte stellt wie das, was sie
       ueberschreibt, ordnet nichts -- sie steht dann einfach mittendrin. */
    grid-column: 1 / -1;
    margin: 1.5rem 0 .5rem;
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.admission-gruppe:first-child,
.booking-gruppe:first-child { margin-top: 0; }

.admission-gruppe-zahl,
.booking-gruppe-zahl {
    margin-left: .35rem;
    opacity: .65;
}

/* Der Hinweis hinter dem Kopf steht klein und ohne Versalien daneben: Er
   ist ein Halbsatz und keine zweite Ueberschrift. */
.booking-gruppe-hinweis {
    margin-left: .6rem;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    opacity: .75;
}

/* Die Vornamen unter dem Nachnamen: Sie beantworten die Frage, die beim
   Hinsehen kommt -- wer ist das noch mal? */
.admission-wer {
    display: block;
    font-size: .9375rem;
    color: var(--trr-ink);
}

/* Ruhende bleiben lesbar und bitten nicht um Aufmerksamkeit. Sie stehen
   unten, weil man sie selten meint -- nicht, weil sie weniger wert sind. */
.admission-item.ist-ruht { opacity: .62; }

/* Der Hinweis rechnet, entscheidet aber nicht. Deshalb warm und nicht rot:
   Es ist eine Beobachtung und kein Fehler. */
.admission-kuehl {
    display: inline-block;
    margin-left: .35rem;
    padding: .0625rem .375rem;
    border-radius: 999px;

    font-size: .8125rem;
    background: var(--trr-amber-100);
    color: var(--trr-amber-600);
}

/* ----------------------------------------------------------- Modulauswahl */

.module-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
    gap: 1rem;
}

.module-card {
    display: flex;
    flex-direction: column;
    gap: .75rem;
    padding: 1.125rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius);
    background: var(--trr-paper);
    transition: border-color .12s ease, background-color .12s ease;
}

.module-card.is-on {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
}

.module-toggle {
    display: grid;
    grid-template-columns: auto auto 1fr;
    gap: .75rem;
    align-items: start;
    cursor: pointer;
    margin: 0;
}

.module-toggle .form-check-input { margin-top: .25rem; }
.module-icon { color: var(--trr-teal-700); }
.module-body { display: flex; flex-direction: column; gap: .1875rem; }
.module-name { font-weight: 600; }
.module-hint { font-size: .875rem; color: var(--trr-ink-soft); line-height: 1.45; }

.module-count {
    font-size: .8125rem;
    color: var(--trr-teal-700);
    font-weight: 600;
}

.module-link {
    align-self: flex-start;
    font-size: .9375rem;
    font-weight: 600;
}

/* ------------------------------------------------------------ Fahrerauswahl */

.driver-summary {
    display: flex;
    flex-wrap: wrap;
    gap: .625rem;
    margin-bottom: 1.25rem;
}

.driver-count {
    flex: 1 1 8rem;
    display: flex;
    flex-direction: column;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    line-height: 1.2;
}

/* Ausnahmen sind der Grund, warum es diese Seite gibt -- stehen sie auf
   null, soll die Kachel nicht so aussehen, als fehlte etwas. Hervorgehoben
   wird sie deshalb erst, wenn es wirklich Ausnahmen gibt. */
.driver-count.is-marked {
    border-color: var(--trr-amber-600);
    background: var(--trr-amber-100);
}

.driver-count-value { font-size: 1.5rem; font-weight: 700; }
.driver-count-label { font-size: .875rem; color: var(--trr-ink-soft); }

.driver-family-link {
    float: right;
    font-size: .875rem;
    font-weight: 400;
}

.driver-rows { display: grid; gap: .5rem; }

/* Name, was gilt, ein Stift.
   ------------------------------------------------------------------------
   Die dritte Spalte war einmal vierzehn Zentimeter breit und trug zwei
   Haekchen und ein Textfeld -- fuer eine Frage, die bei neunundzwanzig von
   dreissig Personen gar nicht gestellt wird, weil das Alter sie beantwortet.
   Jetzt steht dort ein Stift, und die Zeile ist eine Zeile. */
.driver-row {
    display: grid;
    grid-template-columns: minmax(9rem, 1fr) 12rem 2.25rem;
    gap: .875rem;
    align-items: center;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.driver-row.is-exception {
    border-color: var(--trr-amber-600);
    background: var(--trr-amber-100);
}

/* Auf dem Handy stapeln statt seitwärts zu scrollen: Name oben, Rolle und
   Häkchen darunter. Eine Zeile pro Person bliebe sonst nur zur Hälfte
   sichtbar. */
@media (max-width: 767px) {
    .driver-row { grid-template-columns: 1fr; gap: .5rem; }
}

.driver-person { display: flex; flex-direction: column; line-height: 1.3; }
.driver-name { font-weight: 600; }
.driver-age { font-size: .875rem; color: var(--trr-ink-soft); }

.driver-role { display: flex; flex-wrap: wrap; align-items: center; gap: .375rem; }

.driver-badge {
    display: inline-block;
    padding: .125rem .5rem;
    border-radius: 999px;
    border: 1px solid var(--trr-line);
    font-size: .8125rem;
    font-weight: 600;
    color: var(--trr-ink-soft);
    white-space: nowrap;
}

.driver-badge.is-driver {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
    color: var(--trr-teal-700);
}

.driver-flag {
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--trr-warn);
}

.driver-switch { display: flex; flex-direction: column; gap: .375rem; }

.driver-switch .form-check-label {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-size: .875rem;
    cursor: pointer;
}

.driver-reason { font-size: .875rem; }

.driver-stale {
    margin: -.25rem 0 .25rem;
    padding: 0 .875rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* -------------------------------------------------------------- Preiszeilen */

.price-rows { display: grid; gap: .5rem; }

.price-row {
    display: grid;
    grid-template-columns: 1fr 9rem 7rem;
    gap: .875rem;
    align-items: center;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.price-row.is-free { opacity: .75; }

@media (max-width: 575px) {
    .price-row { grid-template-columns: 1fr 1fr; }
    .price-label { grid-column: 1 / -1; }
}

.price-label { display: flex; flex-direction: column; line-height: 1.3; }
.price-label .form-label { font-weight: 600; }
.price-hint { font-size: .8125rem; color: var(--trr-ink-soft); }

.price-active .form-check-label {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    font-size: .875rem;
    cursor: pointer;
}

.input-group-text {
    background: var(--trr-paper);
    border-color: var(--trr-line);
    color: var(--trr-ink-soft);
}

/* --------------------------------------------------------- Beispielrechnung */

.probe-list { display: grid; gap: .625rem; }

.probe {
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.probe.is-family {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
}

.probe-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .75rem;
}

.probe-name { font-weight: 600; font-size: 1rem; }

.probe-total {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--trr-teal-700);
    white-space: nowrap;
}

.probe-detail {
    margin-top: .1875rem;
    font-size: .875rem;
    color: var(--trr-ink);
    line-height: 1.45;
}

/* -------------------------------------------------------------- T-Shirt-Zeilen */

.shirt-rows { display: grid; gap: .5rem; }

.shirt-row {
    display: grid;
    grid-template-columns: 1.4fr 1fr 1fr 9rem;
    gap: .625rem;
    align-items: center;
    margin: 0;
    padding: 0;
    border: 0;
}

.shirt-head {
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--trr-ink-soft);
    padding-bottom: .25rem;
}

@media (max-width: 767px) {
    .shirt-row { grid-template-columns: 1fr 1fr; }
    .shirt-head { display: none; }
}

/* Der Gruppenname ist ein Eingabefeld, soll aber wie eine Beschriftung
   wirken — Rahmen erst beim Hineingehen. */
.price-name {
    font-weight: 600;
    border-color: transparent;
    background: transparent;
    padding-left: .25rem;
}

.price-name:hover  { border-color: var(--trr-line); background: var(--trr-paper); }
.price-name:focus  { border-color: var(--trr-teal-600); background: var(--trr-paper); }

/* ==========================================================================
   Anmeldung zu einem Event
   ========================================================================== */

/* ---------------------------------------------------------- Shirt-Bestellung */

.shirt-order { display: grid; gap: .5rem; }

.shirt-order-row {
    display: grid;
    grid-template-columns: 1fr auto 5rem;
    gap: .875rem;
    align-items: center;
    padding: .625rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.shirt-order-name { margin: 0; font-weight: 600; cursor: pointer; }
.shirt-order-price { color: var(--trr-ink-soft); font-size: 1rem; white-space: nowrap; }
.shirt-order-amount { text-align: center; }

@media (max-width: 575px) {
    .shirt-order-row { grid-template-columns: 1fr 4.5rem; }
    .shirt-order-price { grid-row: 2; grid-column: 1; }
    .shirt-order-amount { grid-row: 1 / span 2; grid-column: 2; align-self: center; }
}

/* -------------------------------------------------------- Umfrage-Antworten

   Jede Frage stand in einem eigenen Kasten, die Antworten darunter als
   Stapel bildschirmbreiter Balken. Bei fuenf kurzen Woertern -- Salat,
   Kuchen, Getraenke -- war das eine Treppe aus fast leeren Zeilen.

   Jetzt eine Kachel je Frage und die Antworten als Reihe, die umbricht:
   Kurze Woerter stehen nebeneinander, lange bekommen ihre eigene Zeile. Das
   richtet sich nach dem Wort und nicht nach dem Bildschirm. */

.frage-raster { margin-top: 1.25rem; }

.frage-titel {
    margin: 0;
    font-size: 1.0625rem;
    line-height: 1.35;
    color: var(--trr-ink);
}

.frage-text {
    margin: .3rem 0 0;
    font-size: .9375rem;
    line-height: 1.45;
    color: var(--trr-ink);
}

.frage-wahl {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-top: .875rem;
}

/* Das Kaestchen bleibt sichtbar: Ein Kreis heisst "eine Antwort", ein
   Kaestchen "so viele du willst". Wer es wegnimmt, muss den Satz darunter
   lesen -- und tut es nicht. */
.frage-knopf {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .45rem .8rem;

    background: rgba(255, 255, 255, .05);
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 1rem;
    line-height: 1.2;
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

.frage-knopf:hover { border-color: var(--trr-teal-600); }

.frage-knopf:has(input:checked) {
    border-color: var(--trr-teal-700);
    background: rgba(2, 176, 167, .12);
    color: var(--trr-ink);
}

.frage-knopf:has(input:focus-visible) {
    outline: 2px solid var(--trr-teal-600);
    outline-offset: 2px;
}

/* Das Zeichen sitzt sonst zu hoch: Es ist kleiner als die Zeile, und ohne
   Korrektur haengt es an deren Oberkante. */
.frage-knopf .form-check-input {
    margin: 0;
    flex: 0 0 auto;
}

/* Der Name ueber einer Antwortreihe -- bei Fragen, die jedem Einzelnen
   gelten.
   ------------------------------------------------------------------------
   Er ist keine Zierde, sondern die Zuordnung: Ohne ihn stehen drei gleiche
   Antwortreihen untereinander und niemand weiss, welche wem gehoert.

   Dieselbe kleine gesperrte Zeile wie die Kicker sonst im Portal, und mit
   Luft darueber: Sie trennt zwei Personen voneinander, und das muss sie
   ohne Strich tun -- ein Gitter aus Linien in einer Kachel waere eine
   Tabelle. Beim ersten Namen faellt die Luft weg, dort trennt schon die
   Frage. */
.frage-wer {
    margin: 1.1rem 0 0;
    font-family: var(--bs-body-font-family);
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-teal-800);
}

.frage-wer:first-of-type { margin-top: .875rem; }

/* Die Reihe sitzt dann direkt unter ihrem Namen und nicht mit dem vollen
   Abstand, den sie unter einer Frage haette. */
.frage-wer + .frage-wahl { margin-top: .4rem; }

.frage-art {
    margin: .75rem 0 0;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

/* ---------------------------------------------------------------- Übersicht */

/* --------------------------------------------------- Stimmt das so?

   Hier standen drei bis vier eigene Kaesten untereinander: die Anmeldung,
   die Antworten, der Ruecktritt. Auf der letzten Seite vor einer
   verbindlichen Zusage sah das aus wie vier Formulare -- dabei ist es eine
   einzige Frage, und die steht in der Ueberschrift.

   Jetzt eine Flaeche und darin Kacheln wie ueberall sonst. */

/* Ein Hinweis, der auf etwas Fehlendes zeigt, traegt Bernstein -- dieselbe
   Farbe wie ueberall, wo etwas nachzutragen ist. */
.form-text.ist-offen { color: var(--trr-amber-600); }

.pruef-raster { margin-top: 1.25rem; }

/* Ueberschrift links, "aendern" rechts -- auf einer Grundlinie, damit die
   beiden wie eine Zeile lesen und nicht wie zwei Dinge. */
.pruef-kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: .625rem;
}

.pruef-titel {
    margin: 0;
    font-size: 1.0625rem;
    line-height: 1.3;
    color: var(--trr-ink);
}

/* Der Weg zum Aendern ist leise: Er soll dasein, wenn man ihn sucht, und
   nicht mit dem Knopf am Fuss der Seite um Aufmerksamkeit ringen. */
.pruef-aendern {
    flex: 0 0 auto;
    font-size: .9375rem;
}

/* Der Ruecktritt in derselben Flaeche, aber mit einer eigenen Kante: Er ist
   das Einzige hier, das eine Bestaetigung verlangt. */
.pruef-ruecktritt { border-left: 2px solid var(--trr-teal-700); }

/* Diese Kachel hat keinen "aendern"-Kopf, also auch keinen Abstand von
   dort -- ohne ihn klebt der Satz an der Ueberschrift. */
.pruef-ruecktritt .pruef-titel { margin-bottom: .5rem; }

.pruef-ruecktritt .withdrawal-accept { margin-top: .875rem; }

.bill-role {
    display: inline-block;
    margin-left: .375rem;
    padding: 0 .375rem;
    border-radius: 999px;
    background: var(--trr-row-alt, var(--trr-row));
    border: 1px solid var(--trr-line);
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

/* ------------------------------------------------- Die Ueberweisung

   Sie ist das Einzige auf der Bestaetigung, das noch etwas verlangt. Darum
   eine eigene Flaeche und darin dieselben Kacheln wie sonst -- die
   Bankverbindung, der Verwendungszweck und der Betrag sind drei Dinge und
   keine Liste. */

.portal-flaeche.ist-zahlen { border-color: rgba(2, 176, 167, .35); }

/* Der Betrag ist die Nachricht: Man kommt auf diese Seite, um zu sehen, was
   zu ueberweisen ist. */
.zahl-kachel { text-align: center; }

.zahl-wort {
    margin: 0;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--trr-teal-800);
}

.zahl-betrag {
    margin: .25rem 0 0;
    font-size: 2rem;
    line-height: 1.1;
    font-weight: 700;
    color: var(--trr-teal-700);
    font-variant-numeric: tabular-nums;
}

.zahl-frist {
    margin: .35rem 0 0;
    font-size: .9375rem;
    color: var(--trr-ink-soft);
}

/* Der Verwendungszweck wird abgetippt oder mit dem Auge verglichen -- also
   gross genug, um ihn Zeichen fuer Zeichen zu lesen. */
.zahl-zweck {
    margin: 0 0 .5rem;
    font-size: 1.0625rem;
    font-weight: 600;
    color: var(--trr-ink);
}


.bill-subtotal {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .25rem 0;
    font-size: 1rem;
    color: var(--trr-ink-soft);
}

/* Auf der letzten Seite ist der Betrag die Nachricht.
   ------------------------------------------------------------------------
   Er stand dort in 1,125rem, also kaum groesser als eine Zeile der
   Aufstellung darueber -- und war damit gleichrangig mit "Kinder-Ticket".
   Wer gleich verbindlich zusagt, soll die Zahl gesehen haben, ohne sie zu
   suchen.

   Der Markenton und nicht Rot oder Weiss: Es ist kein Alarm, sondern das
   Ergebnis. */
.bill-total.is-final {
    margin-top: .75rem;
    padding-top: .875rem;
    border-top: 2px solid var(--trr-teal-700);
    font-size: 1.125rem;
}

.bill-total.is-final .bill-total-amount {
    font-size: 1.75rem;
    line-height: 1.1;
    color: var(--trr-teal-700);
}

.answer-list { margin: 0; }
.answer-list dt { font-weight: 600; }
.answer-list dd { margin: 0 0 .625rem; color: var(--trr-ink); }
.answer-list dd:last-child { margin-bottom: 0; }

/* Kurze Paare -- Name und Stimme, Name und Ja/Nein -- stehen nebeneinander
   statt untereinander: Bei fuenf Personen waeren das sonst zehn Zeilen fuer
   fuenf Auskuenfte. Erst wenn es eng wird, brechen sie um. */
@media (min-width: 30em) {
    .answer-list.ist-knapp {
        display: grid;
        grid-template-columns: auto 1fr;
        gap: .3rem 1rem;
    }

    .answer-list.ist-knapp dd { margin: 0; }
}

/* Der Betrag steht fuer sich und nicht am Fuss einer Liste: Er gehoert zu
   allem darueber, nicht zum letzten Abschnitt. Die Kachel braucht darum
   auch keinen Strich mehr obendrauf. */
/* Das Zahlungsziel unter dem Betrag -- leise, aber vorhanden: Ein Betrag
   ohne Termin liest sich wie "irgendwann". */
.bill-frist {
    margin: .5rem 0 0;
    font-size: .9375rem;
    color: var(--trr-ink-soft);
    text-align: right;
}

.pruef-summe .bill-total.is-final {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

.withdrawal-accept {
    display: flex;
    align-items: flex-start;
    gap: .625rem;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    cursor: pointer;
}

.withdrawal-accept:has(input:checked) {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
}

/* ------------------------------------------------------------ Überweisung */

.payment-card { border-color: var(--trr-teal-600); }

.payment-list { margin: 0; display: grid; gap: .5rem; }

.payment-list > div {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: .25rem 1rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--trr-line);
}

.payment-list > div:last-child { border-bottom: 0; padding-bottom: 0; }
.payment-list dt { color: var(--trr-ink-soft); font-size: .9375rem; font-weight: 400; }
.payment-list dd { margin: 0; font-weight: 600; }

/* IBAN und Verwendungszweck in gleichmäßiger Schrift: Sie werden Ziffer für
   Ziffer abgetippt oder mit dem Auge verglichen, und dabei hilft eine
   Schrift, in der jedes Zeichen gleich breit ist. */
.payment-iban,
.payment-reference {
    font-family: var(--trr-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    letter-spacing: .02em;
    word-break: break-all;
}

.payment-highlight dd { color: var(--trr-teal-700); }
.payment-amount { font-size: 1.25rem; }

.payment-note {
    margin: 1rem 0 0;
    font-size: .9375rem;
    color: var(--trr-ink);
}

/* Beide Knoepfe auf einer Hoehe.
   ------------------------------------------------------------------------
   Der eine steckt in einem Formular, der andere kommt aus dem
   Absage-Baustein -- zwei verschiedene Huellen. In einer Reihe, die ihre
   Kinder streckt (align-items: stretch ist die Vorgabe), wird das Formular
   so hoch wie die Reihe, sein Knopf bleibt oben, und der Nachbar sass
   sichtbar tiefer. */
.booking-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

/* ==========================================================================
   Anmeldungen aus Sicht des Veranstalters
   ========================================================================== */

.booking-rows { display: grid; gap: .5rem; }

/* Eine Zeile ist eine Tabellenzeile, also bekommt sie feste Spalten.
   ------------------------------------------------------------------------
   Vorher: drei Spalten, davon eine mit 1.4fr. Der Name nahm die halbe Seite,
   daneben klaffte Leere, und alles Weitere stapelte sich in zwei schmalen
   Zellen uebereinander. Weil nicht jede Familie alles hat, sass dieselbe
   Angabe bei jeder Zeile auf einer anderen Hoehe -- man konnte die Liste
   nicht hinunterlesen, sondern musste sie Zeile fuer Zeile absuchen.

   Jetzt sechs Spalten mit fester Breite. Sie stehen auch dann, wenn sie leer
   sind: Genau das haelt Betrag, Zustand, Feld und Button in Reih und Glied.
   Die einzige mitwachsende Spalte ist der Name -- alles andere hat eine
   bekannte Groesse, und der Rest gehoert dem, was am laengsten ist. */
.booking-row {
    display: grid;
    grid-template-columns: minmax(10rem, 1.4fr) 9rem minmax(11rem, auto);
    gap: .5rem .875rem;
    align-items: center;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/* Wer sich noch nicht gemeldet hat, steht gedämpft da -- sichtbar, aber
   nicht so laut wie die, bei denen etwas zu tun ist. */
.booking-row.is-quiet { opacity: .72; }

/* Die Anmeldungsliste des Veranstalters ist eine Tabelle, also bekommt sie
   feste Spalten.
   ------------------------------------------------------------------------
   Vorher teilte sie sich das Raster mit der Ticketliste der Gäste: drei
   Spalten, davon eine mit 1.4fr. Der Name nahm die halbe Seite, daneben
   klaffte Leere, und alles Weitere stapelte sich in zwei schmalen Zellen
   übereinander. Weil nicht jede Familie alles hat, saß dieselbe Angabe bei
   jeder Zeile auf einer anderen Höhe -- man konnte die Liste nicht
   hinunterlesen, sondern musste sie Zeile für Zeile absuchen.

   Jetzt sechs Spalten mit fester Breite, und sie stehen auch dann, wenn sie
   leer sind: Genau das hält Betrag, Zustand, Feld und Button in Reih und
   Glied. Die einzige mitwachsende Spalte ist der Name.

   Eine eigene Klasse und keine Änderung an .booking-row: Die Gästeansicht
   hat drei Zellen und säße in einem Sechs-Spalten-Raster falsch. Zwei
   Listen, die zufällig gleich aussahen, sind noch keine gemeinsame Sache. */
.booking-row.ist-liste {
    grid-template-columns:
        minmax(11rem, 1fr)  /* Familie: Name, Personen, Verwendungszweck */
        11rem               /* Betrag und was er macht -- ein Paket */
        24.5rem;            /* vier feste Faecher fuer die Griffe */
    /* Oben ausgerichtet: Links stehen bis zu drei Zeilen, rechts manchmal
       nur ein Button. Mittig zentriert schwebte der Button neben der Mitte
       des Namens und sähe aus, als gehöre er nirgends hin. */
    align-items: start;
}

@media (max-width: 61.9375em) {
    /* Unter 992 Punkt gehen die drei Spalten nicht mehr nebeneinander.
       Dann bricht die Zeile in zwei Etagen: oben Name und Geld, unten die
       Buttons. Geordnet bleibt es -- nur in zwei Reihen statt einer. */
    .booking-row.ist-liste { grid-template-columns: minmax(10rem, 1fr) 11rem; }
    .booking-row.ist-liste .booking-tun { grid-column: 1 / -1; }
}

/* Auf der Tickets-Seite dieselbe Machart wie die Highlight-Pillen.
   ------------------------------------------------------------------------
   Kein Rahmen, sondern ein flacher Verlauf von oben hell nach unten dunkel,
   dazu eine Lichtkante oben und ein Hauch Schatten unten: So liegt die Zeile
   auf der Seite statt in ihr. Eine Flaeche in einem Ton wirkte flach.

   Der Verlauf ist bewusst schwach. Wo man ihn als Verlauf erkennt, ist er zu
   stark.

   Und nur dort: In der Liste des Veranstalters stehen dieselben Zeilen, aber
   dort sind sie ein Arbeitsmittel und kein Auftritt -- ein Rahmen trennt
   vierzig Zeilen besser als vierzig Flaechen. */
.booking-row.ist-karte {
    border: 0;
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .105),
            rgba(255, 255, 255, .04)
        );
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .14),
        0 1px 2px rgba(0, 0, 0, .25);
}

/* Rund wie die Pillen waere hier falsch: Eine Zeile ueber die ganze Breite
   mit halbrunden Enden sieht aus wie ein Button, und ein Button ist sie
   nicht. Etwas weicher als die Kastenfassung aber schon. */
.booking-row.ist-karte { border-radius: var(--trr-radius); }

.booking-rows .booking-row.ist-karte + .booking-row.ist-karte { margin-top: .1rem; }

/* Zwei Buttons statt einem: "Zum Event" und "Eure Buchung". Der Name des
   Events war vorher der einzige Weg dorthin -- ein Wort in einer Zeile, das
   man erst als Verweis erkennt, wenn man darueberfaehrt.

   Deshalb bekommt die Spalte mehr Platz. Rechtsbuendig, damit die Buttons
   aller Zeilen in einer Flucht stehen: Bei einem Entwurf gibt es nur einen,
   und der soll nicht in der Mitte haengen. */
.booking-row.ist-karte .booking-action {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: .4rem;
}

@media (min-width: 768px) {
    .booking-row.ist-karte { grid-template-columns: minmax(10rem, 1.4fr) 9rem minmax(16rem, auto); }
}

/* Auf dem Telefon steht alles untereinander -- dann duerfen die Buttons
   links anfangen wie der Text darueber. */
@media (max-width: 767px) {
    .booking-row.ist-karte .booking-action { justify-content: flex-start; }
}

@media (max-width: 767px) {
    .booking-row { grid-template-columns: 1fr; }
}

.booking-family { display: flex; flex-direction: column; line-height: 1.3; }
.booking-name { font-weight: 600; }
.booking-meta { font-size: .875rem; color: var(--trr-ink-soft); }

/* Auf eigener Zeile und im Absage-Ton: Sie hebt die Zeile darueber auf, und
   das darf man nicht ueberlesen. Fett waere hier zu laut -- die Zeile steht
   in einer Liste, und die Farbe reicht. */
.booking-ausfall {
    display: block;
    margin-top: .15rem;
    color: var(--trr-hot);
}

/* Der Grund einer Absage, in der Liste des Veranstalters. Eingerückt und
   in Anführung gesetzt, damit auf einen Blick klar ist: Das hat die Familie
   geschrieben, das ist keine Angabe des Portals. */
.booking-note {
    display: block;
    margin-top: .3rem;
    padding-left: .7rem;
    border-left: 2px solid var(--trr-line);
    font-size: .875rem;
    font-style: italic;
    color: var(--trr-ink);
}

/* Der Anmeldeschluss über dem Button. Er ist der Grund, jetzt zu drücken --
   deshalb steht er davor und nicht als Fußnote darunter. */
.frist-hinweis {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-bottom: .85rem;
    font-size: 1rem;
    color: var(--trr-ink);
}

.frist-hinweis.is-urgent {
    color: var(--trr-amber-500);
    font-weight: 600;
}

.frist-icon { width: 1rem; height: 1rem; flex-shrink: 0; }

/* ----------------------------------------------------------- Absagen */

.absage { margin-top: .75rem; }

/* In einer Knopfreihe steht der Baustein neben anderen Knoepfen und nicht
   unter einem Text -- dort waere sein Abstand nach oben genau der Versatz,
   den man sieht. Dieselbe Ausnahme wie auf der Kachel und in der Leiste.

   Und das <form> daneben traegt 16 Punkte unter sich, aus dem Grundgeruest
   von Bootstrap. In einer Reihe, die ihre Kinder mittig setzt, zaehlt der
   Aussenabstand mit: Das Formular sass dadurch acht Punkte hoeher als sein
   Nachbar, und genau das war der sichtbare Versatz. */
.booking-actions .absage,
.booking-actions form { margin: 0; }

.absage-form {
    margin-top: .85rem;
    max-width: 32rem;
}

/* Der eigene Grund auf der Event-Seite. Derselbe Gedanke wie oben: Es ist
   ein Zitat und keine Aussage des Portals. */
.absage-grund {
    margin: 0 0 1rem;
    padding-left: .85rem;
    border-left: 3px solid var(--trr-line);
    font-style: italic;
    color: var(--trr-ink);
}

.booking-amount { display: flex; flex-direction: column; line-height: 1.3; }
.booking-total { font-weight: 600; }

/* Angesprungene Zeilen bleiben unter der Kopfleiste nicht hängen.
   ----------------------------------------------------------------------
   Die Navigationsleiste steht fest über der Seite. Ohne diesen Abstand
   schiebt der Browser die Zeile genau dorthin, wo sie verdeckt ist -- man
   springt und sieht nichts, was schlimmer ist als gar nicht zu springen.
   Ein Fingerbreit mehr, damit die Zeile nicht am Rand klebt. */
.booking-row[id],
.posten-row[id] {
    scroll-margin-top: calc(var(--nav-hoehe) + 1rem);
}

.booking-paid { font-size: .875rem; color: var(--trr-warn); }
.booking-paid.is-done { color: var(--trr-teal-700); }

/* „Termin steht" ist eine Auskunft und keine offene Aufgabe -- die warme
   Farbe von „noch offen" waere hier eine Aufforderung zu nichts. */
.booking-paid.ist-ruhig { color: var(--trr-ink-soft); }

/* Sponsoring steht bei der Familie, die es gegeben hat -- im Markenton, wie
   alles, was erreicht ist. Eine Rückzahlung dagegen ist eine offene
   Aufgabe und trägt die warme Farbe. */
.booking-sponsor { font-size: .875rem; color: var(--trr-teal-700); }
.booking-sponsor.ist-zurueck { color: var(--trr-hot); font-weight: 600; }

/* Der Umschalter ist ein Nebensatz und kein Button: Er kommt selten vor und
   darf neben "bezahlt" nicht um Aufmerksamkeit ringen. */
.booking-sponsor-tun .btn-link,
.posten-sponsor-tun {
    padding: 0;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
    text-decoration: underline;
}

.booking-sponsor-tun .btn-link:hover,
.posten-sponsor-tun:hover { color: var(--trr-ink); }

.booking-pay { display: flex; gap: .375rem; align-items: center; }
.booking-pay-amount { width: 6rem; text-align: right; }

/* Die Buttons einer Zeile: nebeneinander, nicht übereinander.
   ----------------------------------------------------------------------
   Vorher stapelten sich Feld, Button, „doch ein Versehen" und ein zweites
   Textfeld -- vier Etagen für eine Familie, und bei zwanzig Familien eine
   Seite, durch die man scrollt statt sie zu lesen.

   Jetzt liegt alles Kleine in einer Reihe unter dem Betragsfeld. Umbrechen
   darf sie, wenn der Platz nicht reicht; auf dem Telefon ist das der
   Normalfall. */
/* Betrag und Zustand als ein Paket, rechtsbuendig.
   ------------------------------------------------------------------------
   Sie standen in drei eigenen Spalten -- Betrag, Zustand, Sponsoring. Das
   hielt zwar Ordnung, zerriss aber, was zusammengehoert: Wie es um das Geld
   dieser Familie steht, ist eine Auskunft und nicht drei.

   Rechtsbuendig, weil man Zahlen an der Einerstelle vergleicht und nicht am
   Wortanfang. Und mit tabular-nums, damit die Ziffern gleich breit laufen:
   Sonst steht bei "9,00" die Neun woanders als bei "95,00" die Fuenf. */
.booking-geld {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
    line-height: 1.35;
}

.booking-soll {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.booking-stand { font-size: .875rem; }

/* Drei Toene, und jeder sagt etwas anderes.
   „gut"  -- erledigt, oder mehr als erledigt (Markenton)
   „wach" -- es fehlt noch etwas, aber in Ruhe (Bernstein)
   „rot"  -- es ist ueber der Zeit, oder es liegt fremdes Geld herum */
.booking-stand.ist-gut  { color: var(--trr-teal-700); }
.booking-stand.ist-wach { color: var(--trr-warn); }
.booking-stand.ist-rot  { color: var(--trr-hot); font-weight: 600; }

/* Die Buttonspalte. Als Folge von Bloecken erbte das Zahlungsformular hier
   den Standardabstand des Browsers unter einem <form> -- ein ganzes Rem, das
   niemand angeordnet hat und das jede Zeile um sechzehn Punkt hoeher machte.
   Bei zwanzig Familien ist das ein Drittel Bildschirm fuer nichts. */
/* Vier feste Faecher fuer die Griffe -- ueber alle Gruppen hinweg.
   ------------------------------------------------------------------------
   Vorher wurden die Buttons nur nebeneinander gereiht. Das sah in jeder
   Gruppe fuer sich ordentlich aus, aber untereinander nicht: Bei "Zugesagt"
   stand das Betragsfeld vorn, bei "Ohne Antwort" begann dort schon der erste
   Button. Zwei Reihen, die fast fluchten, wirken unruhiger als zwei, die es
   offensichtlich nicht tun.

   Jetzt ein Raster mit vier benannten Faechern. Jede Gruppe fuellt die, die
   sie braucht, und laesst die anderen leer -- dadurch stehen Feld, erster
   Button, zweiter Button und Stift bei jeder Familie an derselben Stelle.

   Die Breiten stehen in Variablen, weil das Zahlungsformular sie ein zweites
   Mal braucht: Es ist ein <form> und damit selbst nur ein Kaestchen im
   Raster; seine beiden Kinder muessen dieselbe Teilung noch einmal
   bekommen. Zwei Zahlen, die uebereinstimmen muessen, schreibt man nicht
   zweimal hin. */
.booking-tun {
    --tun-feld:  6rem;
    --tun-button: 7.5rem;
    --tun-stift: 2.25rem;
    --tun-luft:  .375rem;

    display: grid;
    grid-template-columns:
        var(--tun-feld) var(--tun-button) var(--tun-button) var(--tun-stift);
    gap: var(--tun-luft);
    align-items: center;
}

.booking-tun form { margin: 0; }

/* Das Zahlungsformular belegt die ersten beiden Faecher und teilt sich
   innen genauso auf. */
.booking-pay {
    grid-column: 1 / 3;
    display: grid;
    grid-template-columns: var(--tun-feld) var(--tun-button);
    gap: var(--tun-luft);
}

/* Die Faecher, in die eine Gruppe ihre Buttons legt. b und c sind die
   beiden Buttonplaetze, d der Stift; bc nimmt beide Buttonplaetze fuer einen
   laengeren Text. */
/* a ist das Feld ganz links -- bei den Zugesagten das Zahlungsfeld, bei den
   Ausstehenden frei fuer den Knopf, der die Anmeldung von Hand eintraegt. */
.tun-a  { grid-column: 1; }
.tun-b  { grid-column: 2; }
.tun-c  { grid-column: 3; }
.tun-d  { grid-column: 4; }
.tun-bc { grid-column: 2 / 4; }

/* Im Raster braucht kein Button mehr eine eigene Breite -- er fuellt sein
   Fach. Genau das laesst die Spalten untereinander fluchten, auch wenn die
   Woerter verschieden lang sind. */
.booking-tun .btn {
    width: 100%;
    text-align: center;
    white-space: nowrap;
    padding-inline: .25rem;
}

/* Der Stift traegt nur ein Zeichen: Er soll neben dem gefuellten Button
   nicht mitreden, sondern danebenstehen. */
.booking-stift { padding-inline: 0; }

.booking-button-icon {
    width: 1em;
    height: 1em;
    margin-right: .3rem;
    vertical-align: -.125em;
}

/* Die kleinen Verweise sind Nebensätze und keine Buttons: Sie kommen selten
   vor und dürfen neben „vermerken" nicht um Aufmerksamkeit ringen. */
.booking-tun .btn-link {
    padding: 0;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
    text-decoration: underline;
}

.booking-tun .btn-link:hover { color: var(--trr-ink); }

/* Der Verwendungszweck stand als eigenes Band quer unter der Zeile, mit
   Trennlinie darüber. Das war eine halbe Zeile Höhe für eine Angabe, die zur
   Familie gehört wie die Personenzahl -- also steht sie jetzt dort.

   Schreibmaschinenschrift bleibt: Man vergleicht ihn Zeichen für Zeichen mit
   dem Kontoauszug. */
.booking-referenz {
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

.booking-note { color: var(--trr-ink); font-style: italic; }

/* ------------------------------------------------------- Umfrageergebnisse

   Sie hiessen einmal .result-row, .result-bar und so weiter -- und die
   Seite mit den Spielergebnissen benutzte dieselben Namen fuer etwas ganz
   anderes. Zwei Regelsaetze mit demselben Selektor: Der spaetere gewann,
   und die Umfragebalken trugen jahrelang das Raster der Spielergebnisse.
   Aufgefallen ist es nie, weil das Ergebnis zufaellig ordentlich aussah.

   Jetzt heissen sie nach dem, was sie sind. Ein Name, den zwei Dinge
   teilen, gehoert keinem von beiden. */

.uf-zeile {
    display: grid;
    grid-template-columns: minmax(6rem, 1fr) 2fr 2.5rem;
    gap: .625rem;
    align-items: center;
    margin-bottom: .375rem;
    font-size: 1rem;
}

/* Die ausdrueckliche Enthaltung -- unter den Balken und ohne einen eigenen.
   Sie ist keine Antwort und darf deshalb nicht wie eine aussehen; sie ist
   aber eine Aussage und gehoert nicht weggelassen. */
.uf-enthaltung {
    margin: .625rem 0 0;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.uf-balken {
    display: block;
    height: .5rem;
    border-radius: 999px;
    background: var(--trr-line);
    overflow: hidden;
}

.uf-fuellung {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--trr-teal-600);
}

.uf-zahl { text-align: right; font-variant-numeric: tabular-nums; }

/* Die Balken ruecken vom Kopf ab -- sonst klebt die erste Antwort an der
   Frage und sieht aus wie ein Teil von ihr. */
.umfrage-eintrag .uf-zeile:first-of-type { margin-top: .75rem; }

/* Wer wie gestimmt hat -- dieselbe Umfrage mit Namen statt mit Balken.
   ------------------------------------------------------------------------
   Kein Rahmen je Zeile wie bei den Pflegelisten: Dort hakt man etwas ab,
   und ein Rahmen sagt "hier ist eine Aufgabe". Hier liest man nur, und
   zwoelf Kaesten untereinander waeren Laerm. Eine feine Trennlinie genuegt,
   um die Zeile vom Nachbarn zu loesen. */
.uf-namen {
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
}

.uf-name-zeile {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: .75rem;
    align-items: center;
    padding: .5rem 0;
    border-top: 1px solid var(--trr-line);
}

/* Bei einer Frage an die ganze Familie gibt es kein Bild -- die erste
   Spalte faellt weg, statt leer stehen zu bleiben. */
.uf-name-zeile:not(:has(.avatar)) { grid-template-columns: 1fr auto; }

.uf-name-text { min-width: 0; }
.uf-name-wer { margin: 0; font-weight: 600; }

.uf-name-familie {
    margin: 0;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* Die Enthaltung leiser als eine Antwort: Sie ist eine Aussage, aber nicht
   dieselbe -- und wer die Liste ueberfliegt, soll die Antworten finden. */
.uf-name-zeile.ist-enthaltung .uf-name-wer { font-weight: 500; }

.uf-name-antwort {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: .3125rem;
}

/* Die Antwort als Marke und nicht als Fliesstext: Bei Mehrfachauswahl sind
   es mehrere, und drei durch Komma getrennte Woerter liest man als eines. */
.uf-marke {
    display: inline-block;
    padding: .125rem .5rem;
    border-radius: 999px;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    font-size: .875rem;
    white-space: nowrap;
}

.uf-marke.ist-leer {
    background: none;
    border-style: dashed;
    color: var(--trr-ink-quiet);
    font-style: italic;
}

/*
 * Ein Block je Antwort -- alle Ja beieinander, alle Nein beieinander.
 *
 * Die Ueberschrift traegt dieselbe Zahl wie der Balken darueber, in derselben
 * Machart wie "Haben noch nicht geantwortet": Wort, Zahl im Kreis. Sie sind
 * Geschwister, also sehen sie gleich aus.
 */
.uf-block + .uf-block { margin-top: 1.5rem; }

.uf-block-kopf {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}

.uf-block-zahl {
    font-size: .8125rem;
    font-weight: 600;
    padding: .0625rem .4375rem;
    border-radius: 999px;
    background: var(--trr-row);
    color: var(--trr-ink-soft);
}

/* Die Enthaltung leiser als eine Antwort -- dieselbe Abstufung wie bei den
   Zeilen darin. */
.uf-block.ist-enthaltung .uf-block-kopf { color: var(--trr-ink-quiet); }

.uf-block-leer {
    margin: .5rem 0 0;
    font-size: .875rem;
    color: var(--trr-ink-quiet);
    font-style: italic;
}

/* Die erste Zeile eines Blocks braucht keine Linie nach oben -- darueber
   steht schon die Ueberschrift. */
.uf-block .uf-namen { margin-top: .5rem; }
.uf-block .uf-name-zeile:first-child { border-top: 0; }

/* Bei Mehrfachauswahl stehen alle Antworten einer Person daneben. Die, unter
   deren Ueberschrift sie gerade steht, tritt zurueck: Sie ist die
   Wiederholung, die anderen sind die Auskunft. */
.uf-marke.ist-dieser {
    background: none;
    color: var(--trr-ink-quiet);
}

@media (max-width: 35.9375em) {
    /* Auf dem Telefon Bild und Name oben, die Antworten darunter links --
       nebeneinander blieben fuer den Namen sonst zwei Woerter Platz. */
    .uf-name-zeile { grid-template-columns: auto 1fr; }
    .uf-name-zeile:not(:has(.avatar)) { grid-template-columns: 1fr; }
    .uf-name-antwort { grid-column: 2; justify-content: flex-start; }
    .uf-name-zeile:not(:has(.avatar)) .uf-name-antwort { grid-column: 1; }
}

/* ------------------------------------------------------------- Aufstellung */

.lineup-block + .lineup-block {
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--trr-line);
}

.lineup-head {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    margin-bottom: .25rem;
}

.lineup-title { font-weight: 600; }

.lineup-count {
    min-width: 1.5rem;
    padding: 0 .375rem;
    border-radius: 999px;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    font-size: .875rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.lineup-hint,
.lineup-empty {
    margin: 0 0 .5rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

.lineup-empty { margin-bottom: 0; }

.lineup-warning {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    margin: 1rem 0 0;
    padding: .625rem .75rem;
    border: 1px solid var(--trr-amber-600);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-amber-100);
    font-size: .9375rem;
}

.lineup-warning-icon { flex: 0 0 auto; color: var(--trr-warn); margin-top: .125rem; }

/* ==========================================================================
   Fotodatenbank
   ========================================================================== */

.album-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 1.25rem;
}

.album {
    display: block;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius);
    overflow: hidden;
    background: var(--trr-row);
    text-decoration: none;
    color: inherit;
    transition: border-color .12s ease, transform .12s ease;
}

.album:hover { border-color: var(--trr-teal-600); transform: translateY(-2px); }

.album-media {
    position: relative;
    display: block;
    aspect-ratio: 3 / 2;
    overflow: hidden;
    background: var(--trr-row-alt, var(--trr-row));
}

.album-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

.album-placeholder {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--trr-ink-soft);
    opacity: .5;
}

.album-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(6, 26, 32, .75) 0%, rgba(6, 26, 32, 0) 55%);
}

.album-count {
    position: absolute;
    left: .75rem;
    bottom: .625rem;
    color: #fff;
    font-size: .875rem;
    font-weight: 600;
}

.album-body { display: block; padding: .875rem 1rem 1rem; }
.album-name { display: block; font-weight: 600; }
.album-date { display: block; font-size: .875rem; color: var(--trr-ink-soft); }

/* ------------------------------------------------------------- Hochladen */

/* Der Kasten zum Hochladen stand ueber den Bildern und war das Erste, was
   man sah -- auf einer Seite, auf die man kommt, um Bilder anzusehen. Er
   liegt jetzt hinter einem Button, und der teilt sich eine Zeile mit dem Weg
   zum Bildschutz. Untereinander waren es zwei kurze Zeilen mit viel Luft
   rechts daneben. */
.galerie-tun {
    display: flex;
    flex-wrap: wrap;
    align-items: center;

    /* Mittig, wie der Kopfbereich darueber. Links angeschlagen standen zwei
       Buttons unter einer zentrierten Ueberschrift, als haette sie jemand
       vergessen zu ruecken. */
    justify-content: center;
    gap: 1.25rem;
    margin: 0 0 2rem;
}

.galerie-tun .safety-note { margin: 0; }

/* Wer beigesteuert hat -- und zugleich der Filter.
   ------------------------------------------------------------------------
   Es stand kurz im Kopfbereich und war dort eine Auskunft, die man liest und
   dann vergisst. Hier tut sie etwas: Ein Klick zeigt nur die Bilder einer
   Familie.

   Verweise und keine Buttons: Der Filter ist eine Adresse, und die laesst
   sich verschicken ("schau dir mal unsere an") und mit dem Zurueck-Button
   wieder verlassen. */

.galerie-filter {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem;
    margin: 0 0 1.25rem;
}

.galerie-filter-pille {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .25rem .8rem;

    /* Derselbe flache Verlauf wie bei den Highlight-Pillen. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .105),
            rgba(255, 255, 255, .04)
        );
    border-radius: 999px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14);

    font-size: .9375rem;
    color: var(--trr-ink-soft);
    text-decoration: none;
}

.galerie-filter-pille:hover { color: var(--trr-ink); }

/* Die gewaehlte traegt die Marke. Ohne sie waere nach dem Klick nicht zu
   erkennen, warum plotzlich weniger Bilder dastehen. */
.galerie-filter-pille.ist-aktiv {
    background: var(--trr-teal-700);
    color: #05201f;
    font-weight: 600;
    box-shadow: none;
}

.galerie-filter-zahl {
    font-size: .8125rem;
    font-weight: 700;
    color: var(--trr-teal-700);
}

.galerie-filter-pille.ist-aktiv .galerie-filter-zahl { color: rgba(5, 32, 31, .7); }

/* ------------------------------------------------------------ Bilderraster */

/* auto-fit und nicht auto-fill: Bei drei Bildern legte auto-fill vier
   Spalten an und liess die vierte leer -- die Bilder blieben klein, und
   rechts stand eine Luecke. auto-fit verteilt den Platz auf das, was da
   ist. */
.photo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: .875rem;
}

/* Das neueste Bild gross. Ein Raster aus lauter gleichen Quadraten ist eine
   Kontaktabzug-Ansicht; ein Album hat ein Aufmacherbild.

   Erst ab vier Bildern: Bei zweien waere das eine gross und das andere
   klein, und das sieht nach Versehen aus. */
@media (min-width: 48em) {
    .photo-grid:not(.ist-gefiltert):has(.photo:nth-child(4)) > .photo:first-child {
        grid-column: span 2;
        grid-row: span 2;
    }
}

.photo {
    position: relative;
    margin: 0;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    overflow: hidden;
    background: var(--trr-row);
}

/* Ausgeblendete Bilder sieht nur, wer sie ausgeblendet hat oder verwaltet.
   Gedämpft und mit Vermerk, damit sie nicht mit den anderen verwechselt
   werden. */
/* Der Muelleimer in der Ecke des Bildes.
   ------------------------------------------------------------------------
   Hier stand "ausblenden" in der Zeile darunter, zusammen mit einem Feld
   zum Beschriften. Beides ist weg: Das Feld hat niemand ausgefuellt, und
   wer sein eigenes falsches Bild loswerden will, blendet es nicht aus.

   In der Ecke und nicht in der Zeile: Der Button gehoert zu diesem einen
   Bild, und in einer Reihe von zwanzig Kacheln ist die Zuordnung sonst eine
   Frage.

   Gedeckt, bis man die Kachel anfaehrt -- ein Muelleimer auf jedem Bild
   waere eine Aufforderung. */
.photo-weg {
    position: absolute;
    top: .4rem;
    right: .4rem;
    z-index: 1;
}

.photo-weg button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    padding: 0;

    background: rgba(0, 0, 0, .55);
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 50%;
    color: rgba(255, 255, 255, .75);
    cursor: pointer;

    opacity: 0;
    transition: opacity .15s ease, color .15s ease, border-color .15s ease;
}

.photo-weg svg { width: .9rem; height: .9rem; }

/* Auf Telefon und Tablet gibt es kein Anfahren -- dort steht er immer da.
   Sonst waere er unerreichbar: Ein erster Tipp auf ein Bild oeffnet die
   Grossansicht, und ein Button, der erst beim Ueberfahren erscheint, wird
   nie ueberfahren.

   Zwei Bedingungen, weil eine nicht reicht. "hover: none" trifft das
   Telefon; "pointer: coarse" faengt die Faelle dazwischen -- ein Tablet mit
   angestecktem Stift meldet mitunter hover, zielt aber mit dem Finger.
   Ein Notebook mit Tastschirm meldet beides und behaelt das Anfahren, denn
   dort gibt es ja auch eine Maus.

   Nicht ganz deckend: Er soll auf dem Bild liegen und nicht darauf
   herumstehen. */
@media (hover: none), (pointer: coarse) {
    .photo-weg button {
        opacity: .85;

        /* Und groesser. 1,9rem sind rund 30 Bildpunkte -- fuer die Maus
           genug, fuer einen Finger nicht: Apple und Google nennen beide
           44 Punkte als Untergrenze, und darunter trifft man das Bild
           statt den Button. Auf dem Telefon oeffnet das dann die
           Grossansicht, und man versucht es noch einmal. */
        width: 2.75rem;
        height: 2.75rem;
    }

    .photo-weg svg { width: 1.0625rem; height: 1.0625rem; }
}

/* Mit der Tastatur erreichbar bleibt er ueberall: Wer sich durchtabbt,
   sieht ihn, sobald er dran ist. */
.photo:hover .photo-weg button,
.photo-weg button:focus-visible { opacity: 1; }

.photo-weg button:hover,
.photo-weg button:focus-visible {
    color: var(--trr-hot);
    border-color: var(--trr-hot);
}

/* Vom Filter weggenommen. Im Dokument stehen immer alle Bilder: Ohne
   Skripte setzt der Server die Klasse, mit Skripten schaltet sie der
   Browser um -- und dann braucht der Filter keinen Abruf mehr, und niemand
   landet nach einem Klick wieder oben auf der Seite. */
.photo.ist-ausgefiltert { display: none; }

.photo-link { display: block; aspect-ratio: 1 / 1; overflow: hidden; }

/* Das Aufmachbild ist doppelt so hoch wie breit -- das Quadrat gilt dort
   nicht, sonst bliebe unter ihm die Haelfte leer.

   Mit Filter gibt es keins: Der erste Sichtbare ist dann nicht unbedingt
   das erste Kind, und ein grosses Bild irgendwo mitten im Raster saehe nach
   Versehen aus. */
.photo-grid:not(.ist-gefiltert) > .photo:first-child {
    display: flex;
    flex-direction: column;
}

.photo-grid:not(.ist-gefiltert) > .photo:first-child .photo-link {
    aspect-ratio: auto;
    flex: 1 1 auto;
    min-height: 0;
}

.photo-link img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .18s ease;
}

.photo-link:hover img { transform: scale(1.04); }

/* --------------------------------------------------- Videos in der Galerie

   Ein Video liegt in derselben Tabelle wie ein Bild und in derselben Kachel.
   Genau deshalb braucht es ein Zeichen: Ohne das Dreieck ist eine
   Videokachel von einer Bildkachel nicht zu unterscheiden -- man tippt
   darauf, erwartet ein Bild und bekommt Bewegung und Ton. */
.photo-play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 3rem;
    height: 3rem;
    border-radius: 50%;

    /* Dunkel hinterlegt und nicht in der Markenfarbe: Das Dreieck liegt auf
       einem Standbild, dessen Farben wir nicht kennen. Ein halbdurchsichtiges
       Schwarz sitzt auf jedem Motiv, ein Türkis verschwindet auf dem
       nächsten Rasen. */
    background: rgba(0, 0, 0, .55);
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    transition: background .18s ease, transform .18s ease;
}

/* Das Dreieck selbst, aus Rändern gebaut -- ein Zeichen aus der Icon-Datei
   wäre hier ein zweiter Abruf für eine Form aus drei Linien. */
.photo-play::after {
    content: "";
    border-style: solid;
    border-width: .5rem 0 .5rem .8rem;
    border-color: transparent transparent transparent #fff;

    /* Optisch mittig und nicht mathematisch: Ein Dreieck wirkt in einem
       Kreis nach links gerutscht, wenn seine Bounding-Box zentriert ist. */
    margin-left: .18rem;
}

.photo-link:hover .photo-play {
    background: rgba(0, 0, 0, .72);
    transform: translate(-50%, -50%) scale(1.06);
}

/* Die Laufzeit unten rechts -- die eine Auskunft, die man vor dem Antippen
   haben will: drei Sekunden oder zwei Minuten. */
.photo-dauer {
    position: absolute;
    right: .4rem;
    bottom: .4rem;
    padding: .1rem .35rem;
    border-radius: var(--trr-radius-sm);
    background: rgba(0, 0, 0, .65);
    color: #fff;
    font-size: .75rem;
    font-variant-numeric: tabular-nums;
    line-height: 1.4;
    pointer-events: none;
}

/* --------------------------------------------------- Videos beim Hochladen

   Eine Zeile je Clip, mit Namen, Stand und Balken. Der Balken ist hier keine
   Zierde: Das Umrechnen dauert etwa halb so lang wie der Clip, und ohne
   Anzeige ist das von einem Absturz nicht zu unterscheiden. */
.video-auftraege {
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
    display: grid;
    gap: .625rem;
}

/* Der Medienspieler, aus dem das Standbild gezogen wird.
   ------------------------------------------------------------------------
   Er muss im Dokument haengen: Ein <video>, das nirgends haengt, laedt auf
   iOS keine Bilddaten -- es wird nie dargestellt, also holt Safari auch
   nichts. Sichtbar sein muss es deshalb aber nicht.

   Nicht "display: none": Das ist fuer Safari derselbe Fall wie gar nicht da.
   Stattdessen ein Punkt am Rand, den niemand bemerkt. */
.video-abseits {
    position: fixed;
    left: -9999px;
    top: 0;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

/* Die Ansage fuer Geraete, die nicht umrechnen koennen. Kein Alarmrot: Es
   ist niemandes Fehler, sondern eine Eigenschaft des Geraets -- und Bilder
   gehen ja weiter. */
.video-ansage {
    margin: .75rem 0 0;
    padding: .625rem .75rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* Zahl und Einheit nebeneinander: "5" allein sagt nicht, wovon. Ein
   Eingabefeld ueber die volle Breite fuer eine einstellige Zahl saehe
   ausserdem aus, als erwarte es mehr. */
.video-minuten {
    display: flex;
    align-items: center;
    gap: .5rem;
}

.video-minuten input { max-width: 6rem; }

.video-auftrag {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: .25rem .75rem;
    font-size: .8125rem;
}

.video-auftrag-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--trr-ink);
}

.video-auftrag-stand {
    color: var(--trr-ink-soft);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.video-auftrag-balken {
    grid-column: 1 / -1;
    height: .25rem;
    border-radius: 999px;
    background: var(--trr-line);
    overflow: hidden;
}

.video-auftrag-balken > div {
    height: 100%;
    width: 0;
    border-radius: inherit;
    background: var(--trr-teal-500);
    transition: width .2s ease;
}

/* Solange keine Zahl bekannt ist: ein wandernder Streifen.
   ------------------------------------------------------------------------
   Er sagt nicht, wie weit es ist, sondern dass es läuft — und das ist in
   diesem Moment die ehrlichere Auskunft: Beim Laden der Umrechen-Bibliothek
   weiß niemand, wie lange es noch dauert. Ein Balken auf null behauptete
   dagegen, es sei noch nichts geschehen, und sieht aus wie einer, der klemmt.

   Wer Bewegung im Betriebssystem abgeschaltet hat, bekommt einen ruhig
   gefüllten Balken. Die Auskunft „es läuft" bleibt, das Wandern entfällt. */
.video-auftrag-balken.ist-unbestimmt > div {
    width: 40%;
    transition: none;
    animation: video-wandern 1.2s ease-in-out infinite;
}

@keyframes video-wandern {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(250%); }
}

@media (prefers-reduced-motion: reduce) {
    .video-auftrag-balken.ist-unbestimmt > div {
        width: 100%;
        animation: none;
        opacity: .45;
    }
}

/* Fertig und fehlgeschlagen bleiben stehen, bis die Seite neu lädt. Wer fünf
   Clips schickt, will hinterher sehen, welcher davon nicht durchkam. */
.video-auftrag.ist-fertig .video-auftrag-stand { color: var(--trr-ok); }

.video-auftrag.ist-fehler .video-auftrag-stand { color: var(--trr-hot); }

.video-auftrag.ist-fehler .video-auftrag-balken > div { background: var(--trr-hot); }

.photo-caption {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .375rem;
    padding: .5rem .625rem .625rem;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

/* Uebrig bleibt, wer es gebracht hat. Die Beschriftung stand hier auch --
   ein Textfeld an jedem Bild, das niemand ausgefuellt hat -- und der Vermerk
   "ausgeblendet", den es nicht mehr gibt: Geloescht wird jetzt richtig. */
.photo-from { flex: 1 1 auto; }
.photo-mine { color: var(--trr-teal-700); font-weight: 600; }

/* ------------------------------------------------------------ Altersgrenzen */

.limit-rows { display: grid; gap: .5rem; }

.limit-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem 1rem;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.limit-label { display: flex; flex-direction: column; line-height: 1.3; }
.limit-label .form-label { font-weight: 600; }
.limit-hint { font-size: .875rem; color: var(--trr-ink-soft); }

.limit-input { display: flex; align-items: center; gap: .5rem; }
.limit-input .form-control { width: 5.5rem; text-align: center; }
.limit-unit { font-size: .9375rem; color: var(--trr-ink-soft); }

/* ------------------------------------------------- Hinweis zum Bildschutz */

.safety-note {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: -.5rem 0 1.25rem;
    font-size: .9375rem;
    color: var(--trr-ink);
}

/* In der Galerie steht sie direkt unter dem Absatz, der das Versprechen
   andeutet -- und braucht dort keinen negativen Abstand nach oben, sondern
   einen kleinen positiven. */
.seiten-gruss .safety-note { margin: .9rem 0 0; }

.safety-note-icon { flex: 0 0 auto; }

/* Mehrzeilig: Das Schloss oben statt mittig -- sonst schwebt es neben der
   zweiten Zeile. Und ohne den negativen Abstand nach oben, weil sie dann
   mitten im Text steht und nicht unter einem Absatz klebt. */
.safety-note.ist-mehrzeilig {
    align-items: flex-start;
    margin: 1rem 0 0;
}

.safety-note.ist-mehrzeilig .safety-note-icon { margin-top: .1875rem; }

/* Hinweise auf "Meine Familie" laufen nicht ueber die ganze Seite, sondern
   halten sich an die Breite des Textes darueber. Ein Kasten, der doppelt so
   breit ist wie das, worauf er sich bezieht, liest sich wie eine Warnung des
   Portals statt wie eine Anmerkung zur Familie. */
.familie-hinweis {
    max-width: 46rem;
    margin-inline: auto;
}

/* Die Nummer in der WhatsApp-Liste: Ziffernschrift mit gleichen Breiten,
   damit man beim Vergleichen zweier Zeilen nicht verrutscht. */
/* Die Frage je Person im Anmeldeweg.
   ------------------------------------------------------------------------
   Ein Kasten je Person statt einer Liste mit Kaestchen: Es ist eine eigene
   Frage an jeden, und sie wird einzeln beantwortet. */
.wa-fragen { display: grid; gap: .75rem; margin-top: 1rem; }

.wa-frage {
    padding: .875rem 1rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.wa-frage-name {
    float: none;
    width: auto;
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 .625rem;
    padding: 0;
}

.wa-wahl { display: flex; flex-wrap: wrap; gap: .5rem; }

/* Zwei gleich grosse Knoepfe: Es ist eine Wahl und keine Empfehlung. Dass
   der eine gewaehlt ist, sagt die Marke -- nicht die Groesse. */
.wa-knopf {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-paper);
    cursor: pointer;
    transition: border-color .12s ease, background-color .12s ease;
}

.wa-knopf:hover { border-color: var(--trr-teal-600); }

/* Gesperrt und nicht versteckt: Wer die Wahl nicht hat, soll sehen, dass es
   sie gibt und woran es liegt -- der Satz darunter sagt es in Worten. Eine
   Zeile, die gar nicht erst dasteht, sucht man vergeblich. */
.wa-knopf.ist-gesperrt {
    opacity: .45;
    cursor: default;
}

.wa-knopf.ist-gesperrt:hover { border-color: var(--trr-line); }

.wa-knopf:has(input:checked) {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
}

.wa-knopf:has(input:focus-visible) {
    outline: 3px solid var(--trr-teal-500);
    outline-offset: 2px;
}

/* Wer nicht in die Gruppe moechte -- leise unter der Abtippliste.
   Kleiner und ohne Rahmen: Es ist eine Auskunft und keine Aufgabe. */
.wa-ohne {
    margin-top: 1.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--trr-line);
}

.wa-ohne h3 {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 .875rem;
    color: var(--trr-ink-quiet);
}

.wa-ohne-zahl {
    font-size: .8125rem;
    font-weight: 600;
    padding: .0625rem .4375rem;
    border-radius: 999px;
    background: var(--trr-row);
    color: var(--trr-ink-soft);
}

.wa-ohne-liste {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem .75rem;
}

.wa-ohne-liste li {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: 1rem;
}

.wa-ohne-liste .text-body-secondary { font-size: .875rem; }

/* Die WhatsApp-Liste hat eine Spalte mehr als die uebrigen Pflegelisten:
   Bild, Name, Nummer, Button. Mit .ohne-schalter (drei Spalten) rutschte der
   Button in die naechste Zeile und der Name in 7rem Breite. */
.pflegezeile.wa-zeile {
    grid-template-columns: auto 1fr auto auto;
}

@media (max-width: 35.9375em) {
    /* Auf dem Telefon Bild und Name oben, Nummer und Button darunter. */
    .pflegezeile.wa-zeile { grid-template-columns: auto 1fr; }
    .pflegezeile.wa-zeile /* Ein Zahlenfeld fuer zwei Ziffern braucht keine volle Breite -- ein
   Eingabefeld, das dreissigmal groesser ist als sein Inhalt, sieht aus, als
   erwarte es mehr. */
.wa-tage { max-width: 8rem; }

.wa-nummer { grid-column: 2; }
    .pflegezeile.wa-zeile .pflege-buttons { grid-column: 2; justify-self: start; }
}

/* Erledigte Zeilen bleiben stehen und werden leise: Wer sie ausblendete,
   koennte einen Fehlklick nicht mehr zuruecknehmen -- und die Liste saehe
   nach der Haelfte aus, als waere sie kuerzer geworden. */
.pflegezeile.ist-erledigt { opacity: .55; }
.pflegezeile.ist-erledigt:hover { opacity: 1; }

.wa-nummer {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    white-space: nowrap;
}

/* Das Feld, das mit einem Haekchen erscheint -- die Handynummer zur
   WhatsApp-Gruppe.
   ------------------------------------------------------------------------
   Eingerueckt unter der Person, zu der es gehoert, sonst liest es sich wie
   eine eigene Frage.

   Sichtbar nur bei gesetztem Haekchen: :has() am vorhergehenden
   Geschwister. Ein Browser ohne :has() zeigt es immer -- und das ist die
   richtige Richtung: sichtbar und unnoetig ist besser als unsichtbar und
   gebraucht, denn ohne Nummer kommt die Anmeldung nicht durch. */
.survey-text {
    margin: -.25rem 0 .75rem 2rem;
    padding-left: .875rem;
    border-left: 2px solid var(--trr-teal-700);
}

@supports selector(:has(*)) {
    .survey-text { display: none; }

    .admission-item:has(input:checked) + .survey-text { display: block; }

    /* Im WhatsApp-Schritt haengt es am Ja: Der Kasten zeigt es, sobald in
       ihm ein Knopf mit dem Wert "ja" gewaehlt ist. */
    .wa-frage:has(input[value="ja"]:checked) .survey-text { display: block; }
}

/* Die zwei Buttons unter dem Safety-Check.
   ------------------------------------------------------------------------
   Nebeneinander und gleich gross: Es ist eine Wahl und keine Empfehlung mit
   einem Notausgang. Dass das Ja in der Marke steht und das Nein daneben in
   Grau, genuegt als Hinweis, welches der uebliche Weg ist.

   Auf schmalen Schirmen untereinander -- und das Ja bleibt oben. Ein Nein,
   das man als Erstes unter dem Daumen hat, ist kein Nein, sondern ein
   Versehen. */
.vertraulich-wahl {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    margin-top: 1.5rem;
}

.vertraulich-wahl form { margin: 0; }

@media (max-width: 35.9375em) {
    .vertraulich-wahl { flex-direction: column; }
    .vertraulich-wahl > * { width: 100%; }
    .vertraulich-wahl .btn { width: 100%; }
}

/* Die Bitte um Vertraulichkeit in der Begruessung.
   ------------------------------------------------------------------------
   Erbt von .safety-note das Schloss und die Anordnung, weicht aber in drei
   Dingen ab: Sie ist mehrzeilig, also oben ausgerichtet statt mittig --
   sonst schwebt das Schloss neben der zweiten Zeile. Sie steht mitten im
   Text, braucht also keinen negativen Abstand nach oben. Und sie ist in
   Textfarbe statt gedaempft: Alles andere in diesem Fenster erklaert, wo
   etwas liegt; dies hier ist das Einzige, worum gebeten wird. */
.begruessung-vertraulich {
    align-items: flex-start;
    margin: 1.25rem 0;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    font-size: 1rem;
    color: var(--trr-ink);
}

/* Das Schloss auf die Grundlinie der ersten Zeile heben. */
.begruessung-vertraulich .safety-note-icon { margin-top: .125rem; }

/* Sieht aus wie ein Link, ist aber ein Button -- er öffnet etwas auf dieser
   Seite und führt nicht auf eine andere. Wer mit der Tastatur unterwegs ist,
   erwartet bei Enter genau das. */
.safety-link {
    padding: 0;
    border: 0;
    background: none;
    color: var(--trr-teal-700);
    text-decoration: underline;
    text-underline-offset: .15em;
    font: inherit;
    cursor: pointer;
}

.safety-link:hover { color: var(--trr-teal-600); }

.safety-list { margin: 0 0 1rem; padding-left: 1.1rem; }
.safety-list li { margin-bottom: .75rem; }
.safety-list li:last-child { margin-bottom: 0; }

/* ---------------------------------------------------- Vergangene Events */

.past-events {
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--trr-line);
}

.past-events-title {
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
    margin-bottom: .5rem;
}

.past-list { list-style: none; margin: 0; padding: 0; }

.past-list a {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .5rem .625rem;
    border-radius: var(--trr-radius-sm);
    text-decoration: none;
    color: inherit;
}

.past-list a:hover { background: var(--trr-row); }
.past-name { font-weight: 600; }
.past-date { font-size: .875rem; color: var(--trr-ink-soft); white-space: nowrap; }

/* ------------------------------------------------------------ Bildansicht */

/* Die Seite darunter soll nicht mitscrollen, während man blättert. */
body.has-lightbox { overflow: hidden; }

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 1080;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 1rem;
    background: rgba(6, 26, 32, .94);
}

.lightbox[hidden] { display: none; }

.lightbox-figure {
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .75rem;
    min-height: 0;
    min-width: 0;
    flex: 1 1 auto;
    justify-content: center;
}

/* Die Bühne nimmt den übrigen Platz, das Bild passt sich ihr an. So bleibt
   die Leiste darunter stehen, wo sie ist -- egal ob Hoch- oder Querformat. */
.lightbox-stage {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 0;
    flex: 1 1 auto;
}

.lightbox-image {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: var(--trr-radius-sm);
    background: rgba(255, 255, 255, .06);
}

/* Das Video auf der Bühne -- dieselben Maße wie das Bild.

   max-height statt height: Ein hochkant gefilmter Clip ist höher als breit,
   und ohne die Grenze schöbe er die Zählung und den Streifen aus dem Bild. */
.lightbox-video {
    max-width: 100%;
    max-height: 100%;
    border-radius: var(--trr-radius-sm);
    background: #000;
}

.lightbox-caption {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: .25rem 1rem;
    color: rgba(255, 255, 255, .82);
    font-size: .9375rem;
    text-align: center;
    flex: 0 0 auto;
}

.lightbox-count { color: rgba(255, 255, 255, .55); font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------- Bedienleiste */

/* Alles zur Navigation an einem festen Platz. Standen die Pfeile neben dem
   Bild, wanderten sie mit dessen Breite -- bei jedem Format woandershin. */
.lightbox-bar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .625rem;
    width: 100%;
    max-width: 60rem;
    flex: 0 0 auto;
}

.lightbox-bar[hidden] { display: none; }

.lightbox-close,
.lightbox-prev,
.lightbox-next {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    border: 0;
    border-radius: 999px;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    font-size: 1.75rem;
    line-height: 1;
    cursor: pointer;
}

.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover { background: rgba(255, 255, 255, .24); }

.lightbox-close:focus-visible,
.lightbox-prev:focus-visible,
.lightbox-next:focus-visible,
.lightbox-thumb:focus-visible {
    outline: 3px solid #fff;
    outline-offset: 2px;
}

.lightbox-close {
    position: absolute;
    top: 1rem;
    right: 1rem;
    width: 2.5rem;
    height: 2.5rem;
    font-size: 1.5rem;
}

/* ------------------------------------------------------- Filmstreifen */

.lightbox-strip {
    display: flex;
    gap: .375rem;
    overflow-x: auto;
    padding: .25rem;
    scroll-behavior: smooth;
    /* Die Leiste soll nicht wachsen, wenn viele Bilder da sind. */
    min-width: 0;
}

.lightbox-thumb {
    flex: 0 0 auto;
    width: 4rem;
    height: 4rem;
    padding: 0;
    border: 2px solid transparent;
    border-radius: var(--trr-radius-sm);
    overflow: hidden;
    background: rgba(255, 255, 255, .08);
    cursor: pointer;
    opacity: .55;
    transition: opacity .12s ease, border-color .12s ease;
}

.lightbox-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.lightbox-thumb:hover { opacity: .85; }

.lightbox-thumb.is-current {
    opacity: 1;
    border-color: #fff;
}

/* Auf dem Handy nimmt der Streifen dem Bild den Platz, den es braucht --
   und gewischt wird dort ohnehin. Die Pfeile bleiben, mittig unter dem
   Bild, wo der Daumen sie erreicht. */
@media (max-width: 767px) {
    .lightbox-strip { display: none; }
    .lightbox { padding: .5rem; }
}

/* ==========================================================================
   Cocktail-Bar
   ========================================================================== */

/* Die Karte hat eine Breite, wie eine Karte sie hat, und steht in der Mitte.
   ----------------------------------------------------------------------
   Ohne Grenze lief das Raster ueber den ganzen Bildschirm: Auf einem breiten
   Monitor standen zwei Zeilen links und daneben eine halbe Seite Nichts --
   nicht, weil zu wenig da waere, sondern weil vier Spalten Platz war. Eine
   Karte im Lokal ist auch nicht so breit wie der Tresen.

   Der Titel steht im selben Rahmen. Nur das Raster mittig zu setzen hiesse,
   die Ueberschrift allein am linken Rand stehen zu lassen. */
.bar-seite {
    max-width: 58rem;
    margin-inline: auto;

    /* Ueber den Lichtern. Ohne eigene Ebene lae­gen sie darueber und
       daempften den Text. */
    position: relative;
    z-index: 1;
}

/* Unter dem Kopfbild braucht der Rückweg etwas Luft: Er steht sonst direkt
   an der Kante, an der das Bild ausläuft. */
.bar-zurueck { margin-bottom: 1.25rem; }

/* Die Lichter selbst -- dieselben drei wie auf den Seiten vor der Anmeldung
   (.page-plain::after). Die Werte stehen dort in Variablen, also nimmt sie
   diese Ebene mit: Wird der Schimmer dort einmal anders gemischt, aendert er
   sich hier mit. */
.bar-licht {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 0;
    background-image:
        radial-gradient(ellipse 70% 45% at 50% -8%,  var(--trr-glow-cue),  transparent 72%),
        radial-gradient(ellipse 55% 40% at 92% 108%, var(--trr-glow-warm), transparent 70%),
        radial-gradient(ellipse 45% 35% at 4% 78%,   var(--trr-glow-cue),  transparent 75%);
}

/* -------------------------------------------------------------- Der Zierat
 *
 * Zitronen, Minze, Eis -- dieselben Zeichnungen, die auf dem gedruckten
 * Blatt an den Seitenraendern stehen. Was dort schoen ist, soll am Schirm
 * nicht verschwinden.
 *
 * Sechs Stueck, links und rechts abwechselnd, jedes am Rand angeschnitten.
 * Angeschnitten und nicht ganz: Ein vollstaendiges Motiv ist ein Bild und
 * will angesehen werden. Ein halbes am Rand ist Zierrat und laesst die Karte
 * in Ruhe.
 *
 * Als Hintergrundbilder und nicht als Markup: Sechs img-Elemente, die nichts
 * bedeuten, waeren sechs Zeilen, die eine Vorlesehilfe ueberspringen muss.
 * Die Nummern stehen in design/cocktails/LIESMICH.txt.
 *
 * Fest im Fenster wie die Lichter -- der Zierat gehoert zum Rand der Seite
 * und nicht zum Text, der daran vorbeilaeuft.
 */
.bar-zierat {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 0;

    /* Umgedreht wie jede andere Zeichnung auch: Die Dateien sind schwarze
       Tinte, hier liegt Anthrazit darunter. Danach auf ein Zehntel
       heruntergedreht -- deutlicher waere es kein Zierat mehr, sondern ein
       zweiter Inhalt. */
    filter: invert(1) sepia(.2);
    opacity: .085;

    background-repeat: no-repeat;
    background-image:
        url("../img/deko/01.png"),
        url("../img/deko/16.png"),
        url("../img/deko/22.png"),
        url("../img/deko/12.png"),
        url("../img/deko/13.png"),
        url("../img/deko/21.png");
    background-position:
        -3% 6%,
        101% 20%,
        -4% 40%,
        102% 55%,
        -2% 74%,
        100% 90%;
    background-size:
        16rem auto,
        13rem auto,
        14rem auto,
        12rem auto,
        15rem auto,
        13rem auto;
}

/* Auf dem Telefon gibt es keinen Rand, an dem Zierat stehen koennte -- er
   laege unter der Schrift. Dann lieber keiner. */
@media (max-width: 62rem) {
    .bar-zierat { display: none; }
}

/* Auf Papier haben Lichter nichts verloren -- sie kosten Toner und bringen
   nichts. Dieselbe Haltung wie im Druck-Blatt weiter unten. */
@media print {
    /* Der Zierat geht mit. Auf dem Blatt, das aus dem Drucker kommt, steht
       er ohnehin -- dort setzt ihn CocktailPdf, in Ocker und passend zum
       Satzspiegel. Zweimal waere er zweimal. */
    .bar-licht,
    .bar-zierat { display: none; }

    /* Der Verlauf im Rahmen steht als fester Wert da und nicht in einer
       Variablen -- er wuerde auf Papier als tuerkiser Schleier landen. Auf
       Papier tut es eine Linie. */
    .cocktail {
        background: none;
        box-shadow: none;
        border: 1px solid var(--trr-line);
    }
}

.cocktail-block + .cocktail-block { margin-top: 2.75rem; }

.cocktail-heading {
    display: flex;
    align-items: baseline;
    gap: .625rem;
    font-size: 1.125rem;
    margin-bottom: .875rem;
}

.cocktail-heading-count {
    padding: 0 .5rem;
    border-radius: 999px;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    font-size: .875rem;
    font-weight: 400;
    color: var(--trr-ink-soft);
}

/* Zwei je Reihe. Mehr waeren zu schmal fuer eine Zutatenliste, eine waere
   eine Spalte aus Zeilen -- und dann steht rechts die halbe Seite leer. */
.cocktail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));

    /* Ohne Kasten trennt nur noch der Abstand. Er darf deshalb groesser
       sein als vorher -- sonst laufen zwei Eintraege ineinander. */
    gap: 1.75rem 2.5rem;
}

/* Bild links, Text rechts -- und kein Kasten drumherum.
   ----------------------------------------------------------------------
   Vorher lag das Bild oben und der Text darunter, beides in einer
   umrandeten Kachel. Bei einem Cocktail sind das zwei, drei Zutaten: Die
   Kachel war zu drei Vierteln Bild und zu einem Viertel Text, und der
   Rahmen zog um beides einen Strich, der nichts zusammenhielt, was nicht
   ohnehin zusammengehoerte.

   Eine Karte im Lokal hat keine Kaestchen. Sie hat ein Bild, einen Namen
   und darunter, was drin ist -- getrennt durch Luft und sonst nichts. */
.cocktail {
    display: grid;
    grid-template-columns: 6.5rem 1fr;
    gap: 1.125rem;
    align-items: center;

    /* Der Rahmen der Highlight-Kacheln von der Event-Seite: der Markenton
       diagonal ins Dunkle, oben eine hauchduenne Lichtkante, darunter ein
       weicher Schatten. Er fasst Bild, Namen und Zutaten zu einem Ding
       zusammen -- und weil es derselbe Rahmen ist wie dort, sieht die Karte
       nach diesem Portal aus und nicht nach einer eigenen Insel. */
    padding: .875rem;
    border-radius: 12px;
    background: linear-gradient(160deg, rgba(2, 176, 167, .2), rgba(0, 0, 0, .4));
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .1),
        0 1px 2px rgba(0, 0, 0, .25);
}

/* Das Glas. Hochformat, weil ein Glas hoch ist -- und weil das Hochformat
   in der Zeile die Hoehe gibt, die den Text daneben traegt.

   Kein Kasten, kein Grund, keine Ecke: Hier lag ein Foto, und ein Foto
   braucht einen Rahmen, damit es nicht ausfranst. Eine freigestellte
   Zeichnung steht fuer sich -- ein Kaestchen darum waere ein Rahmen um
   nichts. */
.cocktail-glas {
    aspect-ratio: 3 / 4;
    display: grid;
    place-items: center;
}

/* Die Kante am Bild bleibt neutral: Die Farbe traegt der Balken unter dem
   Namen. Zweimal dasselbe zu sagen macht es nicht deutlicher, sondern
   lauter. */

.cocktail-body { min-width: 0; }
.cocktail-name { font-size: 1.1875rem; margin-bottom: 0; }

/* Der abgeschraegte Balken unter dem Namen.
   ----------------------------------------------------------------------
   Derselbe wie unter dem offenen Punkt der Navigationsleiste, und aus
   demselben Baukasten wie die Wortmarke -- dort ist der Balken unter
   TRAKTORRALLYE genauso angeschraegt. Er trennt den Namen von den Zutaten
   und ist zugleich das Etikett: Tuerkis heisst alkoholfrei, Bernstein heisst
   mit Alkohol.

   Damit sagt die Farbe es ein zweites Mal -- nach der Ueberschrift des
   Abschnitts. Das ist Absicht: An einer Bar, an der Kinder stehen, greift
   man auch mal mitten in die Liste, ohne die Ueberschrift darueber noch im
   Kopf zu haben. */
.cocktail-name::after {
    content: "";
    display: block;
    height: 3px;
    margin: .5rem 0 .625rem;
    background: var(--trr-amber-600);
    clip-path: polygon(0 0, 100% 0, calc(100% - 5px) 100%, 0 100%);
}

.cocktail.is-free .cocktail-name::after { background: var(--trr-teal-600); }

.cocktail-text { margin: 0; font-size: 1rem; color: var(--trr-ink); }

/* Auf dem Telefon bleibt es bei Bild links und Text rechts -- gestapelt
   waere jede Zeile so hoch wie eine halbe Bildschirmseite. Nur das Bild
   wird etwas kleiner, damit dem Text genug Breite bleibt. */
@media (max-width: 34rem) {
    .cocktail { grid-template-columns: 5rem 1fr; gap: .875rem; }
}

/* --------------------------------------------------------- Die Wartetafel

   Was die Familie sieht, solange die Karte ein Entwurf ist.

   Vorher war es ein leerer Kasten von Rand zu Rand -- er sagte das Richtige
   und sah aus, als sei die Seite kaputt. Schmal und mittig sagt dasselbe und
   sieht aus wie eine Auskunft. */
.bar-tafel {
    max-width: 32rem;
    margin: 2.5rem auto;
    padding: 2.5rem 2rem;
    text-align: center;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius);
    background: linear-gradient(160deg, var(--trr-row), var(--trr-paper));
}

/* Das Glas gross und im Markenton: Es ist das Einzige auf der Tafel, das
   sagt, worauf man wartet. */
.bar-tafel-zeichen {
    display: grid;
    place-items: center;
    width: 4rem;
    height: 4rem;
    margin: 0 auto 1.25rem;
    border-radius: 50%;
    background: var(--trr-paper);
    border: 1px solid var(--trr-line);
    color: var(--trr-teal-700);
}

.bar-tafel-zeichen svg { width: 2rem; height: 2rem; }

.bar-tafel-titel { font-size: 1.375rem; margin-bottom: .75rem; }

.bar-tafel-satz {
    margin: 0 auto .75rem;
    max-width: 26rem;
    color: var(--trr-ink);
}

.bar-tafel .btn { margin-top: .75rem; }

/* --------------------------------------------------------- Die Karte auf Papier
 *
 * Am Fuss der Karte und mittig: Man liest erst, was es gibt, und entscheidet
 * danach, ob man das Blatt mitnehmen will. Oben stuende ein Ausgang vor dem
 * Eingang.
 *
 * Ein leiser Button und kein Aufruf. Die Seite selbst ist die Karte -- das
 * Blatt ist fuer den Kuehlschrank und den Tresen, und dafuer reicht ein
 * Hinweis, dass es es gibt. */
.bar-blatt {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: .75rem;
    margin: 3rem 0 0;
    padding-top: 1.75rem;
    border-top: 1px solid var(--trr-line);
}

.bar-blatt-satz {
    font-size: .875rem;
    color: var(--trr-ink);
}

/* Auf Papier ist der Button sinnlos: Man haelt das Blatt schon in der Hand. */
@media print {
    .bar-blatt { display: none; }
}

/* -------------------------------------------------------------- Kiosk */

.page-kiosk {
    margin: 0;
    background: #061a20;
    color: #fff;
    overflow: hidden;
}

.kiosk {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100vh;
    padding: 2.5vh 3vw;
}

/*
 * Der Kopf steht jetzt untereinander: Zeichen oben, Eventname darunter.
 * Nebeneinander war der Traktor ein Daumennagel neben dem Namen -- aus drei
 * Metern kein Logo, sondern ein Fleck.
 */
.kiosk-head {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .35rem;
    flex: 0 0 auto;
}

/* Auf dem Monitor an der Bar wird aus drei Metern gelesen. */
.kiosk-head .brand { --brand-breite: 42vw; }

/*
 * Und die Hoehe kommt vom Seitenverhaeltnis -- sonst nirgendwoher.
 * ---------------------------------------------------------------------
 * Ohne diese Zeile stand die Ersatzmarke (also: Event ohne eigenes
 * Zeichen) sechsmal zu hoch da und lief rechts aus dem Bild: 806 mal 489
 * Bildpunkte statt 806 mal 82.
 *
 * Der Grund ist eine Regel, die man selten braucht und hier zweimal
 * trifft. Der Kopf ist eine Spalte, die Marke also ein Flex-Kind, und ein
 * Flex-Kind hat von sich aus "min-height: auto" -- es darf nie kleiner
 * werden als sein Inhalt. Um diesen Inhalt zu messen, muss der Browser die
 * beiden Zeichnungen ausmessen; die stehen aber auf "height: 100%" und
 * beziehen sich damit auf genau die Hoehe, die gerade erst ermittelt
 * werden soll. Er nimmt dann ihre eigene Groesse aus dem viewBox -- und
 * die ist gross. Diese Groesse wurde zur Untergrenze, und das
 * Seitenverhaeltnis hatte nichts mehr zu sagen.
 *
 * "min-height: 0" nimmt die Untergrenze weg. Danach gilt wieder, was
 * gemeint war: Breite mal Verhaeltnis ergibt die Hoehe, und die
 * Zeichnungen fuellen sie aus.
 *
 * Bewusst nur hier und nicht auf .brand-reihe selbst: Wer die Marke in
 * eine weitere Spalte stellt, laeuft in dasselbe -- aber das gehoert dann
 * an jene Stelle geprueft und nicht hier vorweggenommen.
 */
.kiosk-head .brand-reihe { min-height: 0; }

/* Der Eventname tritt zurück -- er benennt, das Zeichen darüber steht für
   die Sache. */
.kiosk-event {
    font-size: 1.1vw;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .5);
}

.kiosk-stage {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
}

/* Alle Folien liegen übereinander; sichtbar ist immer genau eine. Ein
   Wechsel per Ein- und Ausblenden statt per Nachladen: Der Bildschirm läuft
   den ganzen Abend, und ein Netzaussetzer soll ihn nicht leeren. */
.kiosk-slide {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    gap: 4vw;
    opacity: 0;
    visibility: hidden;
    transition: opacity .6s ease;
}

.kiosk-slide.is-current { opacity: 1; visibility: visible; }

/* Das Glas auf dem Monitor. Schmaler als das Foto vorher: Eine Zeichnung ist
   Strich und Luft, und in halber Bildschirmbreite verliert sie sich. Ein
   Drittel, und der Name daneben bekommt den Platz, den er auf drei Metern
   Entfernung braucht. */
.kiosk-media {
    /*
     * Weder wachsen noch schrumpfen. Vorher stand hier "0 1 32%", und damit
     * hing die Groesse des Glases am Namen daneben: Ein langer Name zog die
     * Textspalte auf und drueckte das Glas zusammen. Von Folie zu Folie war
     * es dann verschieden gross -- genau die Unruhe, wegen der die Fotos
     * den gezeichneten Glaesern gewichen sind.
     */
    flex: 0 0 32%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Kein runder Rahmen mehr: Der gehoerte zum Foto. Eine freigestellte
   Zeichnung hat keine Kante, die man abrunden koennte. */
.kiosk-media .glas-bild {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
}

/* Der Rest, und zwar unabhaengig vom Inhalt: Grundbreite 0 heisst, dass
   die Spalte immer denselben Platz bekommt -- der Name bestimmt nicht
   mehr, wie breit er sein darf. */
.kiosk-text { flex: 1 1 0; min-width: 0; }

.kiosk-kind {
    font-size: 1.5vw;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .55);
    margin-bottom: .5rem;
}

/* Alkoholfrei sticht hervor -- aus drei Metern Entfernung soll man das
   sehen, ohne die Beschreibung zu lesen. */
.kiosk-kind.is-free { color: var(--trr-teal-500, #3fb6c6); }

/*
 * Der Name des Cocktails.
 * ---------------------------------------------------------------------
 * Zwei Regeln arbeiten hier gegeneinander, und das musste aufgeloest
 * werden: Weiter oben steht fuer die ganze Seite "overflow-wrap:
 * break-word" -- ein Wort, das sonst ueber den Rand liefe, wird
 * aufgebrochen. Auf einem Formular ist das richtig; hier war es falsch.
 * "Frostschutzmittel" stand als "Frostschutzmit" und "tel" in zwei
 * Zeilen, und aus drei Metern liest das niemand als ein Wort.
 *
 * Also bricht hier kein Wort mehr auf. Passt ein Name nicht, wird nicht
 * er zerlegt, sondern die Schrift kleiner -- das erledigt kiosk.js, das
 * misst und die Groesse setzt. Die Zahl unten ist die vorgesehene
 * Groesse und damit die Obergrenze; kleiner wird es nur, wenn es muss.
 */
.kiosk-name {
    font-size: 6vw;
    line-height: 1.05;
    margin: 0 0 1.5vh;
    overflow-wrap: normal;
    hyphens: manual;
}

.kiosk-description {
    font-size: 2.1vw;
    line-height: 1.4;
    color: rgba(255, 255, 255, .82);
    margin: 0;
}

.kiosk-progress {
    flex: 0 0 auto;
    height: .35rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, .12);
    overflow: hidden;
    margin-top: 2vh;
}

.kiosk-progress-bar {
    display: block;
    height: 100%;
    width: 0;
    background: var(--trr-teal-500, #3fb6c6);
}

.kiosk-progress-bar[hidden] { display: none; }

/* Hochkant hängender Monitor oder Tablet: untereinander statt nebeneinander. */
@media (max-aspect-ratio: 1/1) {
    .kiosk-slide { flex-direction: column; gap: 2vh; text-align: center; }
    .kiosk-media { flex: 0 1 50%; width: 100%; }

    /*
     * Ueber die ganze Breite, und das ist keine Kosmetik. Die Folie steht
     * hier als Spalte, und "align-items: center" bemisst ihre Kinder quer
     * dazu -- also nach ihrem Inhalt. Ein langes Wort machte damit die
     * Textspalte breiter als die Folie, statt in ihr aufzulaufen. Die
     * Spalte war dann immer genau so breit wie noetig, es passte immer,
     * und kiosk.js hatte nichts zu verkleinern: Der Name lief einfach aus
     * dem Bild.
     */
    .kiosk-text { align-self: stretch; }

    .kiosk-name { font-size: 8vw; }
    .kiosk-description { font-size: 3.4vw; }
    .kiosk-kind { font-size: 2.6vw; }
}

/* --------------------------------------------------------- Karte bearbeiten

   Hier standen die Regeln fuer einen Stapel offener Formulare: je Cocktail
   ein Bild, vier Felder, ein Speichern-Button. Bei zwoelf Cocktails waren das
   achtundvierzig Eingabefelder untereinander.

   Jetzt eine Tabelle. Feste Spalten, damit Schalter und Buttons aller Zeilen
   genau untereinander stehen -- am Abend an der Bar hakt man sie der Reihe
   nach ab, und das geht nur, wenn die Stelle dieselbe bleibt. */

.pflegeliste {
    list-style: none;
    margin: 1.25rem 0 0;
    padding: 0;
    display: grid;
    gap: .5rem;
}

.pflegezeile {
    display: grid;
    grid-template-columns: 2.5rem 3rem 1fr 7rem auto;
    gap: .875rem;
    align-items: center;
    padding: .625rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/* Nicht auf der Karte: gedaempft und gestrichelt. Der Eintrag ist da, er
   steht nur heute Abend nicht am Tresen. */
.pflegezeile.ist-aus { opacity: .55; border-style: dashed; }

/* Ohne Schalter und ohne Nummer -- die E-Mail-Texte.
   ----------------------------------------------------------------------
   Dort gibt es nichts an- und auszuschalten und nichts umzusortieren: Die
   Liste folgt dem, was das Portal kann, und nicht dem, was jemand einstellt.
   Ohne diese Zeile faenden Text, Abzeichen und Buttons die Spalten des
   Schalters und der Nummer vor -- der Name stuende dann in 2,5rem Breite
   und braeche nach jedem zweiten Buchstaben um. */
.pflegezeile.ohne-schalter { grid-template-columns: 1fr 7rem auto; }

/* Angesprungene Zeilen bleiben nicht unter der festen Kopfleiste haengen --
   wie in den Zahlungslisten und der Fahrerauswahl. Das gilt ohne Skript;
   mit Skript stellt es die Zeile ohnehin dorthin, wo sie vorher stand. */
.pflegezeile[id] {
    scroll-margin-top: calc(var(--nav-hoehe) + 1rem);
}

/* ------------------------------------------------------------ Der Schalter

   Ein Button, der wie ein Kippschalter aussieht. Ein echtes Kaestchen braeuchte
   ein Skript, das es abschickt, oder einen zweiten Button daneben -- ein Button
   tut es mit einem Klick und ohne beides. */

.pflege-schalter { margin: 0; }

.pflege-kippe {
    display: block;
    width: 2.25rem;
    height: 1.25rem;
    padding: 0;
    border: 1px solid var(--trr-line);
    border-radius: 999px;
    background: var(--trr-paper);
    cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease;
}

.pflege-kippe-button {
    display: block;
    width: .875rem;
    height: .875rem;
    margin-left: .125rem;
    border-radius: 50%;
    background: var(--trr-ink-soft);
    transition: transform .15s ease, background-color .15s ease;
}

.pflege-kippe[aria-checked="true"] {
    background: var(--trr-teal-700);
    border-color: var(--trr-teal-700);
}

.pflege-kippe[aria-checked="true"] .pflege-kippe-button {
    background: var(--trr-on-primary);
    transform: translateX(1rem);
}

@media (prefers-reduced-motion: reduce) {
    .pflege-kippe, .pflege-kippe-button { transition: none; }
}

/* ----------------------------------------------------------- Glas und Text */

.mix-glas {
    width: 3rem;
    aspect-ratio: 3 / 4;
    display: grid;
    place-items: center;
}

/* Das Glas in der Arbeitsliste. Etwas hoeher als breit, damit ein Stielglas
   nicht auf die Haelfte schrumpft, um in ein Quadrat zu passen. */
.mix-glas .glas-bild { padding: .15rem; }

.pflege-text { min-width: 0; }
.pflege-name { margin: 0; font-weight: 600; }

/* Der Inhalt auf zwei Zeilen gedeckelt: Er ist hier die Erinnerung, was drin
   ist, und nicht das Rezept. Vollstaendig steht er im Fenster. */
.pflege-satz {
    margin: .125rem 0 0;
    font-size: .9375rem;
    color: var(--trr-ink);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.pflege-abzeichen { justify-self: start; }

/* ------------------------------------------------------------- Die Buttons */

.pflege-buttons {
    display: flex;
    align-items: center;
    gap: .375rem;
    justify-self: end;
}

.pflege-buttons form { margin: 0; }

.pflege-pfeile { display: flex; flex-direction: column; gap: .125rem; }

/* Klein und leise: Die Reihenfolge aendert man einmal beim Anlegen der Karte,
   nicht staendig. Ein Pfeil in Buttongroesse neben "Bearbeiten" und "Loeschen"
   waere ein dritter Button, der so wichtig aussieht wie die anderen. */
.pflege-pfeil {
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1rem;
    padding: 0;
    border: 0;
    border-radius: 3px;
    background: transparent;
    color: var(--trr-ink-soft);
    cursor: pointer;
}

.pflege-pfeil svg { width: .75rem; height: .75rem; }
.pflege-pfeil:hover:not(:disabled) { background: var(--trr-paper); color: var(--trr-ink); }

/* Am Rand seiner Art gibt es keinen Nachbarn zum Tauschen. Ausgegraut und
   nicht versteckt: Sonst ruecken die beiden Pfeile bei der ersten und der
   letzten Zeile uebereinander. */
.pflege-pfeil:disabled { opacity: .25; cursor: default; }

/* Das Bild im Fenster neben dem Feld, damit man weiss, was man ersetzt. */
/* Die Vorschau des Event-Logos auf der Seite "Titelbilder".
   ----------------------------------------------------------------------
   Sie hatte gar keine Regel. Am Bild stehen width und height als Attribute
   -- die richtigen Masse der Datei, damit die Seite beim Laden nicht
   nachrutscht --, und ohne Gegenwert galten sie auch als Groesse: Ein Logo
   von 1200 Punkten sprengte die Karte.

   Hoehe begrenzt und nicht Breite: Ein Logo ist mal quer und mal hochkant,
   und in einer Reihe sollen alle gleich hoch stehen. Der Grund ist ein
   Karo-Muster, damit man sieht, wo ein durchsichtiges PNG aufhoert --
   sonst raet man, ob der weisse Rand zum Bild gehoert. */
.event-logo-preview {
    margin: 0;
    display: inline-block;
    padding: .75rem;
    border-radius: var(--trr-radius-sm);
    border: 1px solid var(--trr-line);
    background-color: var(--trr-row);
    background-image:
        linear-gradient(45deg, rgba(255, 255, 255, .04) 25%, transparent 25%),
        linear-gradient(-45deg, rgba(255, 255, 255, .04) 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, .04) 75%),
        linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, .04) 75%);
    background-size: 16px 16px;
    background-position: 0 0, 0 8px, 8px -8px, -8px 0;
}

.event-logo-preview img {
    display: block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 6rem;
}

.event-logo-preview figcaption {
    margin-top: .5rem;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
    text-align: center;
}

/* Das Titelbild in den Einstellungen: quer und ueber die Kartenbreite -- so,
   wie es oben auf der Startseite auch liegt. */
.titelbild-vorschau {
    display: block;
    width: 100%;

    /* height: auto ist hier der entscheidende Teil.
       -------------------------------------------------------------------
       Am Bild stehen width und height als Attribute -- sie sagen dem
       Browser die Masse, bevor die Datei da ist, damit die Seite nicht
       nachrutscht. Sie wirken aber auch als Angabe: Ohne dieses auto bliebe
       die Hoehe bei den 1121 Bildpunkten aus dem Attribut stehen, und das
       aspect-ratio darunter kaeme gar nicht zum Zug. Die Vorschau war dann
       in der Breite beschnitten und in der Hoehe vollstaendig -- also
       genau nicht das, was oben auf der Startseite steht. */
    height: auto;

    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/* Auf schmalen Schirmen bricht die Zeile: Schalter, Bild und Name oben,
   Abzeichen und Buttons darunter. Fuenf Spalten nebeneinander gibt es auf
   einem Telefon nicht. */
@media (max-width: 47.9375em) {
    .pflegezeile {
        grid-template-columns: 2.5rem 3rem 1fr;

        /* Untereinander duerfen die Zeilen enger stehen als nebeneinander:
           .875rem trennen zwei Spalten, drei Stapel darunter reissen sie
           auseinander. */
        row-gap: .5rem;
    }

    /* Abzeichen und Buttons je ueber die volle Breite.
       ------------------------------------------------------------------
       Vorher stand das Abzeichen in der Bildspalte und die Buttons in der
       Restspalte daneben. Beides passte dort nicht hinein: "Alkoholfrei"
       ist breiter als drei Zentimeter und lag ueber den Pfeilen, und Pfeile,
       Bearbeiten und Loeschen zusammen waren breiter als der Rest der Zeile.
       Weil eine Rasterspalte nicht schmaler wird als ihr Inhalt, wuchs die
       ganze Zeile ueber den Schirm hinaus -- die Seite liess sich seitwaerts
       schieben, und der Loeschen-Button lag hinter dem Rand.

       Nicht eingerueckt, sondern am linken Rand: Die Buttons brauchen jeden
       Millimeter, den es gibt, sonst faengt dasselbe Spiel eine Stufe
       tiefer wieder an. */
    .pflege-abzeichen { grid-column: 1 / -1; }

    .pflege-buttons {
        grid-column: 1 / -1;
        justify-self: start;

        /* Und wenn selbst die volle Breite nicht reicht -- ein schmales
           Telefon, ein langer Buttontext --, bricht die Reihe um, statt die
           Zeile zu sprengen. Das gilt fuer alle Pflegelisten: Die anderen
           setzen ihre Buttons zwar in eine eigene Spalte, aber ohne Umbruch
           ist auch die nie schmaler als ihr Inhalt. */
        flex-wrap: wrap;
    }

    /* Ohne Schalter bleibt nichts, was oben stehen muesste: Name, Abzeichen
       und Buttons untereinander. */
    .pflegezeile.ohne-schalter { grid-template-columns: 1fr; }
    .pflegezeile.ohne-schalter .pflege-abzeichen,
    .pflegezeile.ohne-schalter .pflege-buttons { grid-column: 1; }
    .pflegezeile.ohne-schalter .pflege-buttons { justify-self: start; }

    /* Die Stationen haben eine Nummer, aber keinen Schalter: Nummer und Name
       oben, Code und Buttons darunter -- und die beiden unteren fangen unter
       dem Namen an und nicht unter der Nummer. */
    .pflegezeile.ohne-kippe { grid-template-columns: 3rem 1fr; }
    .pflegezeile.ohne-kippe .pflege-abzeichen,
    .pflegezeile.ohne-kippe .pflege-buttons { grid-column: 2; }
    .pflegezeile.ohne-kippe .pflege-buttons { justify-self: start; }
}

/* ------------------------------------------------------------- Zugaenge */

.account-rows { display: grid; gap: .5rem; }

.account-row {
    display: grid;
    grid-template-columns: minmax(10rem, 1.6fr) 10rem auto auto;
    gap: .75rem;
    align-items: center;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    margin: 0;
}

.account-row.is-off { opacity: .6; border-style: dashed; }

@media (max-width: 991px) {
    .account-row { grid-template-columns: 1fr; }
}

.account-who { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.account-name { font-weight: 600; }
.account-meta { font-size: .875rem; color: var(--trr-ink-soft); }

.account-self {
    margin-left: .375rem;
    padding: 0 .375rem;
    border-radius: 999px;
    background: var(--trr-teal-050);
    color: var(--trr-teal-700);
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
}

.account-flags { display: flex; flex-wrap: wrap; gap: .75rem; }

.account-flag {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    font-size: .9375rem;
    cursor: pointer;
    white-space: nowrap;
}

.account-flag-icon { color: var(--trr-ink-soft); }

/* ------------------------------------------- Tabelle als Karten (Handy) */

/*
 * Auf schmalen Bildschirmen wird aus jeder Zeile eine Karte. Seitwärts zu
 * scrollen ist auf einem Telefon die schlechteste aller Lösungen: Man sieht
 * nie die ganze Zeile und weiß nie, ob rechts noch etwas kommt.
 *
 * Der Weg über CSS statt über zweierlei Markup hat einen Grund: Auf dem
 * großen Bildschirm bleibt es eine echte Tabelle, mit allem, was
 * Screenreader daraus machen können. Die Spaltennamen kommen auf dem Handy
 * aus data-label und stehen deshalb nur einmal im Quelltext.
 */
@media (max-width: 767px) {
    .table-cards { overflow-x: visible; }

    .table-cards table,
    .table-cards tbody,
    .table-cards tr,
    .table-cards th,
    .table-cards td { display: block; width: auto; }

    .table-cards thead { display: none; }

    .table-cards tr {
        border: 1px solid var(--trr-line);
        border-radius: var(--trr-radius-sm);
        background: var(--trr-row);
        padding: .875rem;
        margin-bottom: .625rem;
    }

    .table-cards tr:last-child { margin-bottom: 0; }

    .table-cards th,
    .table-cards td {
        border: 0;
        padding: .25rem 0;
        text-align: left;
    }

    /* Der Spaltenname vor dem Wert -- sonst steht dort eine Zahl ohne
       Zusammenhang. */
    .table-cards td[data-label]::before {
        content: attr(data-label) ": ";
        color: var(--trr-ink-soft);
        font-size: .875rem;
    }

    .table-cards td.num { text-align: left; }

    .table-cards .row-actions {
        margin-top: .5rem;
        padding-top: .625rem;
        border-top: 1px solid var(--trr-line);
    }

    .table-cards .row-actions::before { content: none; }
}

/* --------------------------------------------------------- Meine Familie */

/* Eine Karte je Person, im Hochformat.
   ------------------------------------------------------------------------
   Vorher war es eine Liste aus Zeilen mit einem Kreis von zweieinhalb
   Zentimetern daneben -- man erkannte niemanden darauf. Und in jeder Zeile
   hingen ein Datumsfeld und zwei Aufklapper: Formulare, die immer dastanden,
   auch wenn niemand etwas aendern wollte. Aus sechs Personen wurden achtzehn
   Formulare.

   Jetzt traegt die Karte, was man wissen will, und ein Button oeffnet ein
   Fenster mit allem, was man aendern kann. */

/* Hoechstens drei nebeneinander.

   Vorher fuellten die Karten die Zeile, so viele wie hineinpassten -- auf
   einem breiten Fenster waren das vier oder fuenf, und dann war die Karte
   ein Streifen. Drei ist die Zahl, bei der das Gesicht noch gross und die
   Zeile noch ruhig ist.

   Deshalb eine Obergrenze fuer die Spalte (19rem) statt 1fr, dazu eine fuer
   das Raster: 3 x 19 + 2 x 1 = 59. Ein vierter Platz passt nicht mehr
   hinein, auch auf einem sehr breiten Schirm nicht. Und was uebrig bleibt,
   steht mittig -- bei zwei Personen sind das zwei Karten in der Mitte statt
   zwei ueberdehnter Flaechen. */
.kin-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 19rem));
    justify-content: center;
    gap: 1rem;
    max-width: 59rem;
    margin: 0 auto 1.5rem;
}

.kin-karte {
    display: flex;
    flex-direction: column;

    /* Derselbe flache Verlauf wie bei den Pillen und den Ticketzeilen. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .085),
            rgba(255, 255, 255, .03)
        );
    border-radius: var(--trr-radius);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .12),
        0 1px 3px rgba(0, 0, 0, .3);
    overflow: hidden;
}

/* Wem der Geburtstag fehlt, bekommt eine Kante in Bernstein. Nicht rot: Es
   ist nichts kaputt, es fehlt nur etwas. */
.kin-karte.hat-luecke {
    box-shadow:
        inset 0 2px 0 var(--trr-amber-500),
        inset 0 3px 0 rgba(255, 255, 255, .1),
        0 1px 3px rgba(0, 0, 0, .3);
}

/* ------------------------------------------------------------- Der Kopf

   Bild, Name, Geburtstag -- mittig untereinander.

   Vorher fuellte das Bild die halbe Karte im Hochformat, drei zu vier. Das
   war gross, aber es war auch ein Ausschnitt: Ein quadratischer Avatar in
   einem hochkanten Rahmen wird oben und unten beschnitten, und getroffen hat
   es meist die Stirn. Der Kreis zeigt das ganze Bild -- und ist dieselbe
   Form wie ueberall sonst im Portal. */

.kin-kopf {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 1.25rem 1rem .75rem;

    /* Ein Hauch der Leitfarbe hinter dem Gesicht, nach unten auslaufend: So
       hat der Kopf einen Boden, ohne dass ein Strich noetig waere. */
    background: linear-gradient(
        to bottom,
        rgba(2, 176, 167, .1),
        rgba(2, 176, 167, 0) 75%
    );
}

/* Die Hoehe steht fest und haengt nicht am Inhalt.

   Das "du" liegt zwar ausserhalb des Flusses, aber der Kreis darunter ist
   ein inline-flex und sitzt damit auf einer Textzeile -- und wo eine
   Textzeile ist, ist auch Platz fuer Unterlaengen. Auf der Karte mit dem
   "du" fiel das anders aus als auf den anderen, und die Namen standen um
   ein paar Punkte versetzt. Als Flex-Kasten mit fester Hoehe gibt es keine
   Textzeile mehr, an der sich etwas ausrichten koennte. */
.kin-bild {
    position: relative;
    display: flex;
    height: 7rem;
}

/* Ein feiner Ring statt des Haarrahmens: Der Kreis steht hier allein auf
   einer Flaeche und darf sich davon absetzen. */
.kin-bild .avatar {
    border-color: transparent;
    box-shadow:
        0 0 0 2px rgba(2, 176, 167, .35),
        0 2px 8px rgba(0, 0, 0, .35);
}

/* "du" unten am Kreis statt in der Ecke der Karte. Am Kreis gehoert es zum
   Gesicht; in der Ecke sah es aus wie eine Marke auf der Karte. */
.kin-du {
    position: absolute;
    left: 50%;
    bottom: -.4rem;
    transform: translateX(-50%);

    padding: .1rem .5rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;

    background: var(--trr-teal-700);
    color: #05201f;
    border-radius: 999px;

    /* Der Ring trennt die Pille vom Kartengrund dahinter. Er stand auf
       var(--trr-bg) -- ein Token, das es nicht gibt -- und fiel damit
       ersatzlos weg: eine ungueltige Farbe macht die ganze Zeile
       ungueltig, nicht nur die Farbe. */
    box-shadow: 0 0 0 2px var(--trr-paper);
}

.kin-name {
    margin: 1rem 0 0;
    font-family: var(--bs-body-font-family);
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.25;
}

.kin-zeile { margin: .2rem 0 0; font-size: .875rem; color: var(--trr-ink-soft); }
.kin-missing { color: var(--trr-warn); font-weight: 600; }

/* ----------------------------------------------------------- Die Angaben

   Zwei Zeilen je Feld, wie bei den Pillen auf der Event-Seite: oben, worum
   es geht, darunter, was gilt.

   Anders als dort liegt die Betonung unten. Auf der Event-Seite ist die
   obere Zeile die Sache selbst ("SPIELE") und die untere ihr Beiwerk; hier
   ist die obere nur der Name des Feldes. "KATEGORIE" gross und "Erwachsen"
   klein waere ein Schild, das lauter spricht als das, was darauf steht.

   Vorher standen hier nackte Woerter: "Erwachsen" und "noch kein Zugang".
   Beide sagten etwas, aber keines sagte, worueber. */

.kin-fakten {
    list-style: none;
    margin: 0;
    padding: 0 .875rem;

    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.kin-fakt {
    display: flex;
    flex-direction: column;
    padding: .45rem .75rem;
    line-height: 1.3;

    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .075),
            rgba(255, 255, 255, .03)
        );
    border-radius: var(--trr-radius-sm, .5rem);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08);
}

.kin-fakt-wort {
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.kin-fakt-wert {
    font-size: .9375rem;
    font-weight: 600;
    color: var(--trr-ink);
}

.kin-fakt-wert.ist-an    { color: var(--trr-teal-700); }
.kin-fakt-wert.ist-offen { color: var(--trr-warn); }

/* Was gar nicht geht, steht gedeckt da und nicht in Bernstein: Bernstein
   heisst "da fehlt noch etwas", und ein Achtjaehriger hat nichts nachzuholen.
   Er wird einfach aelter. */
.kin-fakt-wert.ist-blass,
.kin-fakt-wert .ist-blass { color: var(--trr-ink-soft); font-weight: 400; }

/* Wo die Platzierung herkommt.

   Eine Zeile, und was nicht hineinpasst, endet mit Punkten. Ueber zwei
   Zeilen gelesen wurde aus "9. Rasenmaehertraktorrallyemeisterschaft" ein
   "9. Rasenmaehertraktorrallyemeister-schaft" -- das Wort ist laenger als
   die Karte breit ist, und dann bricht es irgendwo.

   Abgeschnitten bleibt der Anfang stehen, und der traegt hier die Auskunft:
   die Ordnungszahl. Der ganze Name steht im title und damit im Tooltip. */
.kin-fakt-wo {
    margin-top: .1rem;
    font-size: .8125rem;
    color: var(--trr-ink-soft);

    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Der Button am Fuss, immer auf gleicher Hoehe: Die Karten sind
   unterschiedlich hoch, weil die Namen es sind -- und weil nicht jeder eine
   Platzierung hat. */
.kin-tun { margin-top: auto; padding: .875rem; }
.kin-tun .btn { width: 100%; }

.kin-fussnote { margin: 0; text-align: center; }

/* ---------------------------------------------------- Im Fenster dahinter */

.kin-feld { margin: 0; }

/* Ein Geburtstag, der schon feststeht: als Angabe und nicht als Feld. Ein
   graues Eingabefeld sieht aus wie eines, das gerade nicht geht -- dieses
   geht gar nicht mehr, und das ist etwas anderes. */
.kin-fest {
    margin: 0 0 .35rem;
    font-size: 1.0625rem;
    font-weight: 600;
    color: var(--trr-ink);
}
.kin-feld-zeile { display: flex; flex-wrap: wrap; gap: .5rem; }
.kin-feld-zeile .form-control { flex: 1 1 10rem; }

.kin-trenner {
    margin: 1.5rem 0;
    border-color: var(--trr-line);
    opacity: 1;
}

/* Die frueheren Initialen (.member-avatar) sind Avataren gewichen. Die Regel
   bleibt fuer den Fall, dass irgendwo noch Initialen gebraucht werden. */

/* ================================================================= Avatare */

.avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    border-radius: 999px;
    overflow: hidden;
    background: var(--trr-teal-050);
    color: var(--trr-teal-700);
    border: 1px solid var(--trr-line);
}

.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Die Silhouette sitzt sonst randlos im Kreis und wirkt wie abgeschnitten. */
.avatar-symbol { width: 55%; height: 55%; }

.avatar-sm { width: 2rem;   height: 2rem; }
.avatar-md { width: 2.75rem; height: 2.75rem; }
.avatar-lg { width: 4.5rem;  height: 4.5rem; }

/* Der grosse Kreis auf der Personenkarte. Sieben Zentimeter statt der
   viereinhalb von avatar-lg: Auf dieser Seite ist das Gesicht die
   Hauptsache, ueberall sonst begleitet es nur einen Namen.

   Hier stand einmal avatar-karte mit 100 Prozent Breite und Hoehe -- der
   Avatar fuellte einen Rahmen im Hochformat und wurde dafuer oben und unten
   beschnitten. */
.avatar-xl { width: 7rem;    height: 7rem; }

/* ----------------------------------------------------------- Zuschneiden */

.crop { display: none; margin-top: 1rem; }
.crop.is-active { display: block; }

.crop-stage {
    position: relative;
    width: 17.5rem;
    max-width: 100%;
    aspect-ratio: 1 / 1;
    margin: 0 auto;
    border-radius: var(--trr-radius);
    overflow: hidden;
    background: var(--trr-row);
    cursor: grab;
    touch-action: none;
}

.crop-stage:active { cursor: grabbing; }
.crop-stage canvas { display: block; width: 100%; height: 100%; }

/* Der Kreis ist nur eine Maske darüber: Das Bild darunter bleibt sichtbar,
   damit man sieht, was gleich wegfällt, statt blind zu schieben. */
.crop-mask {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: rgba(6, 26, 32, .55);
    -webkit-mask: radial-gradient(circle at 50% 50%, transparent 49.5%, #000 50%);
    mask: radial-gradient(circle at 50% 50%, transparent 49.5%, #000 50%);
}

.crop-ring {
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: 50%;
    box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .85);
}

.crop-controls {
    display: flex;
    align-items: center;
    gap: .75rem;
    max-width: 17.5rem;
    margin: .75rem auto 0;
}

.crop-controls input[type="range"] { flex: 1 1 auto; }
.crop-hint { text-align: center; font-size: .875rem; color: var(--trr-ink-soft); margin: .5rem 0 0; }

/* Der Avatar in der Aufstellung: Die Zeile war bisher zweispaltig. */
.driver-guest { display: flex; align-items: center; gap: .625rem; flex-wrap: wrap; }
.driver-guest .avatar { order: -1; }
.driver-guest-name { flex: 1 1 auto; }

.crop-note { margin-top: .75rem; font-size: .9375rem; }
.crop-note[hidden] { display: none; }

/* ------------------------------------------------------------- Belegung */

.occupancy {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    margin: 0 0 1rem;
    padding: .625rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    font-size: .9375rem;
    color: var(--trr-ink-soft);
}

.occupancy-icon { flex: 0 0 auto; margin-top: .125rem; }

/* Erst wenn es eng wird, faellt der Hinweis auf. Eine Zahl, die immer
   dringlich aussieht, wird nach dem dritten Mal nicht mehr gelesen. */
.occupancy.is-tight {
    border-color: var(--trr-teal-600);
    background: var(--trr-teal-050);
    color: var(--trr-ink);
}

.occupancy.is-full {
    border-color: var(--trr-amber-600);
    background: var(--trr-amber-100);
    color: var(--trr-ink);
}

.occupancy.is-full .occupancy-icon { color: var(--trr-warn); }

/* Der sachliche Regelfall traegt kein Symbol -- ein Ausrufezeichen an einer
   Zahl, die noch niemanden draengt, waere ein falsches Versprechen. */
.occupancy > span { flex: 1 1 auto; }

/* --------------------------------------------------------------- Wer kommt */

/* ------------------------------------------------- Wer kommt: die Gaeste

   Kleine Karten statt einer Namensliste.

   Vorher stand je Gast eine Zeile da: ein Kreis von zweieinhalb
   Zentimetern und daneben Name und Familie. Das war eine Liste, und man
   las sie von oben nach unten. Es sind aber keine Eintraege, es sind
   Leute -- ein Gesicht ueber dem Namen macht aus vierzig Zeilen vierzig
   Gesichter, und ein Raster liest man auf einen Blick statt Zeile fuer
   Zeile. */

.gaeste-gruppe + .gaeste-gruppe { margin-top: 2.25rem; }

/* Erwachsene und Kinder getrennt, mit ihrer Zahl daneben. Die Zahl ist die
   Auskunft, nach der am haeufigsten gefragt wird -- "wie viele Kinder
   kommen" entscheidet, ob sich die Huepfburg lohnt. */
.gaeste-kopf {
    display: flex;
    justify-content: center;
    align-items: baseline;
    gap: .5rem;
    margin: 0 0 1rem;

    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.gaeste-zahl {
    padding: .05rem .45rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, .08);
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: 0;
    color: var(--trr-ink);
}

/* Neun Karten je Reihe bei voller Spaltenbreite: Bei vierzig Gaesten sind
   das fuenf Reihen. Groessere Karten waeren schoener und der Abschnitt
   doppelt so lang -- er steht am Ende der Seite, und dort will niemand
   mehr scrollen.

   Flex und kein Raster, damit jede Reihe mittig steht -- auch die letzte.
   Im Raster stehen die Spalten fest, und die letzte Reihe fing dann links
   an, waehrend rechts eine Luecke blieb. Bei 26 Gaesten in Neuerreihen
   sind das acht leere Plaetze am Ende, und die sahen aus wie ein
   Abbruch. */
.gaeste-raster {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .75rem .5rem;
}

/* 8rem, und die eine Zahl regelt beide Faelle.
   ----------------------------------------------------------------------
   Auf dem Schreibtisch passen damit sechs Karten plus fuenf Fugen in die
   52rem der Spalte (6 x 128 + 5 x 8 = 808 Punkte), eine siebte nicht mehr.
   Auf einem Telefon von 390 Punkten passen zwei (2 x 128 + 8 = 264), eine
   dritte nicht (400). Genau so soll es sein -- und es braucht dafuer keine
   Ausnahmeregel fuer schmale Schirme.

   Vorher waren es 6rem und damit acht je Reihe. Das Gesicht war dann so
   gross wie in einer Namensliste, und dafuer haetten wir die Karten nicht
   gebraucht. */
.gast-karte {
    flex: 0 0 8rem;

    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: .5rem;
    padding: 1rem .5rem;
    min-width: 0;

    /* Derselbe flache Verlauf wie bei den Pillen und den Ticketkarten. */
    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .075),
            rgba(255, 255, 255, .03)
        );
    border-radius: var(--trr-radius-sm);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
}

.gast-name {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--trr-ink);

    /* Ein langer Vorname sprengt sonst die Spalte: "Maximilian" ist
       breiter als die Karte. Und keine Silbentrennung -- "Maximi-lian"
       ueber zwei Zeilen ist schlimmer als "Maximili…". */
    max-width: 100%;
    hyphens: manual;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Der Nachname klein darunter -- er ist die Unterscheidung, wenn zwei
   Sandras kommen.

   Zwei Zeilen, und erst danach Punkte.
   ----------------------------------------------------------------------
   Auf einer Zeile endete "Mustermann-Musterfrau" nach der Haelfte mit
   Punkten, und wer so heisst, stand mit einem halben Namen da. Zwei
   Zeilen fassen so gut wie jeden Namen; was dann immer noch nicht passt,
   endet mit Punkten und steht vollstaendig im title.

   Ohne Silbentrennung: Die Seite trennt sonst ueberall automatisch, und
   das ist im Fliesstext richtig -- ein Trennstrich ist besser als eine
   Luecke. In einem Namen ist er eine Behauptung ueber die Sprache, und
   bei Nachnamen liegt sie oft daneben. Am vorhandenen Bindestrich bricht
   es trotzdem, und das ist keine Trennung, sondern ein Umbruch an der
   Stelle, an der der Name selbst eine hat.

   Und die Hoehe steht fest, ob eine Zeile gebraucht wird oder zwei: So
   sind alle Karten gleich hoch, und die Reihe hat eine gerade Unterkante.
   Sonst wackelten die Karten, je nachdem wie lang der Name ist. */
.gast-familie {
    max-width: 100%;
    min-height: 2.5em;
    font-size: .8125rem;
    line-height: 1.25;
    color: var(--trr-ink);

    hyphens: manual;

    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Wer faehrt, wer sitzt hinten, wer schaut zu.
   ----------------------------------------------------------------------
   Als kleine Marke unter dem Namen und in drei Toenen: Fahren ist die
   Hauptsache und steht in der Leitfarbe, der Sozius faehrt mit und steht
   gedaempft daneben, der Zuschauer tritt zurueck.

   Leicht abgesetzt und nicht bunt: Drei kraeftige Farben in einem Raster
   aus vierzig Karten waeren ein Flickenteppich, und die Rolle ist die
   dritte Auskunft auf der Karte -- nach dem Gesicht und dem Namen. */
.gast-rolle {
    margin-top: .1rem;
    padding: .05rem .4rem;

    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .04em;
    line-height: 1.4;

    border-radius: 999px;
    background: rgba(255, 255, 255, .06);
    color: var(--trr-ink-soft);
}

.gast-rolle.ist-driver {
    background: rgba(2, 176, 167, .18);
    color: var(--trr-teal-700);
}

.gast-rolle.ist-passenger {
    background: rgba(2, 176, 167, .09);
    color: rgba(255, 255, 255, .72);
}

/* Der Supervisor in Bernstein und nicht in der Leitfarbe: Die gehoert dem
   Fahren, und er faehrt gerade nicht. Bernstein heisst im Portal "hier ist
   etwas anders als sonst", und genau das ist er -- die einzige Rolle, die
   nicht die Familie waehlt. */
.gast-rolle.ist-supervisor {
    background: rgba(232, 165, 42, .16);
    color: var(--trr-warn);
}

/* Dieselbe Marke im Manager, neben "Ausnahme". */
.driver-flag.ist-aufsicht {
    background: rgba(232, 165, 42, .16);
    color: var(--trr-warn);
    border-color: transparent;
}

.driver-aufsicht { margin-top: .35rem; }

/* --------------------------------------------- Wer noch mitwollte (Manager)

   Eine schlichte Liste: Name, Groesse der Familie, seit wann. Mehr weiss
   das Portal darueber auch nicht -- vermerkt wird, dass jemand den Button
   gedrueckt hat, und sonst nichts. */

.interesse-liste {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.interesse-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .35rem .9rem;
    padding: .5rem .75rem;

    background: var(--trr-row);
    border-radius: var(--trr-radius-sm);
}

.interesse-name { font-weight: 600; }

/* Wer schon freigegeben ist, traegt eine Kante in der Marke: Er steht noch
   auf der Liste, weil er noch nicht gebucht hat -- aber die Tuer ist fuer
   ihn offen, und das soll man sehen, ohne den Button zu lesen. */
.interesse-zeile.ist-frei {
    box-shadow: inset 2px 0 0 var(--trr-teal-700);
}

/* Der Button ganz rechts, hinter dem Datum. */
.interesse-tun { margin-left: .25rem; }

.interesse-koepfe,
.interesse-wann { font-size: .875rem; color: var(--trr-ink-soft); }

/* Der Rest der Zeile schiebt Datum und Button nach rechts. */
.interesse-wann { margin-left: auto; }

/* Die Notiz in der Tunleiste, wenn das Interesse schon vermerkt ist. Kein
   Button mehr: Was getan ist, laesst sich nicht noch einmal tun. */
/* Der Absagegrund in der Leiste: eine Zeile, und was nicht hineinpasst,
   endet mit Punkten. Ganz steht er im title. */
.tunleiste-grund {
    max-width: 22rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tunleiste-notiz {
    font-size: .9375rem;
    font-weight: 600;
    color: var(--trr-warn);
}

/* ==========================================================================
   Spiele, Aufstellung und Wertung

   Diese Seiten werden auf einer Wiese benutzt, am Handy, zwischen zwei
   Läufen. Dort zählt Treffsicherheit mehr als Eleganz: große Felder, große
   Ziffern, und die Startnummer immer an derselben Stelle.
   ========================================================================== */

/* --------------------------------------------------------------- Spieleliste */

/* Die Zeile selbst kommt aus der Pflegeliste weiter oben -- dieselbe wie bei
   den Cocktails. Hier stehen nur die beiden Felder, die es dort nicht gibt.

   Vorher war jedes Spiel eine aufgeklappte Karte mit vier Feldern und einem
   Speichern-Button. Bei neun Spielen waren das sechsunddreissig Felder
   untereinander, die alle gleich aussahen. */

/* Die Nummer ist der Ablauf des Tages -- man sucht das dritte Spiel, nicht
   „Slalom mit Anhänger". Sie steht dort, wo in der Cocktailliste das Glas
   steht, und ist deshalb auf dessen Spalte gerechnet. */
.spiel-nummer {
    justify-self: center;
    width: 1.875rem;
    height: 1.875rem;
    display: grid;
    place-items: center;
    border-radius: 999px;
    background: var(--trr-teal-700);
    color: var(--trr-on-primary);
    font-weight: 700;
    font-size: .9375rem;
    font-variant-numeric: tabular-nums;
}

/* Ein ausgeschaltetes Spiel laeuft heute nicht mit. Die Nummer bleibt
   trotzdem stehen -- sie ist die Reihenfolge und nicht die Teilnahme --,
   aber sie hoert auf, nach Markenton zu rufen. */
.pflegezeile.ist-aus .spiel-nummer {
    background: var(--trr-row);
    color: var(--trr-ink-soft);
    box-shadow: inset 0 0 0 1px var(--trr-line);
}

/* Der Weg zu den Ergebnissen, mit dem Stand darin: „wie weit sind wir?" und
   „weitertippen" sind am Rallyetag dieselbe Bewegung. */
.spiel-stand {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    white-space: nowrap;
}

.spiel-stand-zahl {
    font-variant-numeric: tabular-nums;
    font-size: .875rem;
    padding: 0 .375rem;
    border-radius: 999px;
    background: var(--trr-paper);
    color: var(--trr-ink-soft);
}

/* Vollzaehlig: Das ist die Zahl, auf die man am Tag hinarbeitet, und sie
   soll man von weitem sehen. */
.spiel-stand-zahl.ist-voll {
    background: var(--trr-teal-050);
    color: var(--trr-teal-900);
}

/* ------------------------------------------------------------ Die Stationen

   Der Posten auf der Wiese: ein Mensch mit einem Handy, der ein oder mehrere
   Spiele abnimmt. */

/* Eine Spalte weniger als bei den Spielen: Ein Posten hat keinen Schalter --
   es gibt ihn oder es gibt ihn nicht. Ohne diese Zeile faende die Nummer die
   Schalterspalte vor und der Name die Nummernspalte.

   Erst ab der Tabletbreite, und das ist keine Feinheit, sondern eine
   Reparatur: Die Telefonregel dafuer steht tausend Zeilen weiter oben bei den
   Pflegelisten, und zwei gleich starke Regeln entscheidet die spaetere. Diese
   hier ist die spaetere -- sie galt damit auch auf dem Telefon, und die vier
   Spalten standen dort nebeneinander, bis die Zeile ueber den Rand hing. */
@media (min-width: 48em) {
    .pflegezeile.ohne-kippe { grid-template-columns: 3rem 1fr 7rem auto; }
}

/* Der Notcode zum Abtippen. Ziffern in gleicher Breite und in Zweiergruppen:
   Er wird am Telefon vorgelesen, und dabei soll das Auge die Gruppen nicht
   jedes Mal neu suchen. */
.station-code {
    font-variant-numeric: tabular-nums;
    letter-spacing: .04em;
    white-space: nowrap;
}

/* Die Spiele eines Postens im Fenster -- untereinander und zum Anklicken,
   dieselbe Machart wie bei den Zustandsfeldern. Man liest die Liste ab und
   hakt an, was dieser eine Mensch abnimmt. */
.station-spielwahl { display: grid; gap: .25rem; margin-top: .5rem; }

.station-spiel {
    display: flex;
    align-items: flex-start;
    gap: .625rem;
    padding: .5rem .625rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    cursor: pointer;
}

.station-spiel:hover { border-color: var(--trr-ink-soft); }

.station-spiel:has(input:checked) {
    border-color: var(--trr-teal-700);
    background: var(--trr-teal-050);
}

.station-spiel .form-check-input { margin-top: .2rem; flex: 0 0 auto; }

.station-spiel-text {
    display: flex;
    flex-direction: column;
    line-height: 1.35;
    min-width: 0;
}

.station-spiel-name { font-weight: 600; overflow-wrap: break-word; }

/* Haengt das Spiel schon an einem anderen Posten, steht es dabei: Anhaken
   nimmt es dem anderen weg, und das soll niemanden ueberraschen. */
.station-spiel-satz { font-size: .8125rem; color: var(--trr-ink-soft); }

/* Die Spiele ohne Posten -- eine Liste ohne Punkte, weil sie keine Aufzaehlung
   ist, sondern der Stapel, der abends auf dem Tisch liegt. */
.liste-schlicht {
    list-style: none;
    margin: .75rem 0 0;
    padding: 0;
    display: grid;
    gap: .25rem;
}

/* Zwischen den Spielen wechseln, ohne zurück zur Liste zu müssen -- im
   laufenden Betrieb ist jeder Umweg einer zu viel. */
.game-switch {
    display: flex;
    flex-wrap: wrap;
    gap: .375rem;
    margin-bottom: 1.25rem;
}

.game-switch-item {
    padding: .3125rem .625rem;
    border: 1px solid var(--trr-line);
    border-radius: 999px;
    background: var(--trr-row);
    font-size: .875rem;
    text-decoration: none;
    color: var(--trr-ink);
}

.game-switch-item:hover { border-color: var(--trr-teal-700); }

.game-switch-item.is-active {
    background: var(--trr-teal-700);
    border-color: var(--trr-teal-700);
    color: var(--trr-on-primary);
}

/* ------------------------------------------------------ Ergebnisse eintragen */

.result-row {
    display: grid;
    grid-template-columns: minmax(11rem, 1.2fr) minmax(11rem, .8fr) minmax(13rem, 1fr);
    gap: .875rem;
    align-items: center;
    padding: .625rem .75rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.result-row + .result-row { margin-top: .5rem; }

/* Nicht gewertet (§7): sichtbar anders, aber nicht durchgestrichen -- die
   Person ist angetreten, nur das Spiel zählt für sie nicht. */
.result-row.is-void { border-style: dashed; opacity: .72; }

.result-person { display: flex; align-items: center; gap: .5rem; min-width: 0; }

.result-number {
    flex: 0 0 auto;
    min-width: 1.75rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--trr-ink-soft);
}

.result-name { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.result-role { font-size: .8125rem; color: var(--trr-ink-soft); }

.result-value { display: flex; align-items: center; gap: .375rem; }

/* Groß genug, um sie mit klammen Fingern zu treffen. */
.result-input {
    max-width: 7rem;
    font-size: 1.125rem;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.result-unit { font-size: .875rem; color: var(--trr-ink-soft); }

/*
 * Fuer die Vorleserin da, fuer das Auge nicht.
 * ---------------------------------------------------------------------------
 * Die Klasse kommt sonst aus Bootstrap -- und die Erfassung auf der Wiese
 * laedt Bootstrap nicht. Dort stand die versteckte Beschriftung deshalb im
 * Klartext auf der Seite ("Minuten bei Memory"), und niemand konnte sich
 * erklaeren, woher das kommt.
 *
 * Also hier, im eigenen Stylesheet, das jedes Layout laedt. Dieselbe Regel
 * wie bei Bootstrap; wo Bootstrap dabei ist, gewinnt schlicht die spaetere,
 * und beide sagen dasselbe.
 */
.visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

/*
 * Die beiden Zeitraeder -- Minute und Sekunde.
 * ---------------------------------------------------------------------------
 * Ein select und kein Zahlenfeld: Auf dem iPhone ist genau das jenes
 * Rasterrad, das man von dort kennt, und zwar ohne eine Zeile JavaScript. Auf
 * dem Schreibtisch bleibt es eine Auswahlliste.
 *
 * Die Einheit steht hinter dem Rad und nicht davor -- man liest "1 min 23 s"
 * in der Reihenfolge, in der man es auch sagt.
 */
.zeitfelder { display: flex; align-items: center; gap: .5rem; }
.zeitfeld { display: flex; align-items: center; gap: .25rem; }
.zeitfeld-einheit { font-size: .875rem; color: var(--trr-ink-soft); }

/* Mit sichtbarer Beschriftung steht das Wort ueber dem Rad und nicht
   daneben: So liest man "Minuten" und darunter die Zahl, statt in einer
   Zeile aus Wort, Rad, Wort, Rad die Zuordnung zu suchen. */
.zeitfelder.ist-beschriftet .zeitfeld {
    flex-direction: column;
    align-items: stretch;
    gap: .25rem;
}

.zeitfeld-name {
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* Nur so breit wie noetig: zwei Ziffern und der Pfeil. Zwei Auswahlfelder in
   voller Breite naehmen der Zeile den Platz, den die Platzierung daneben
   braucht. */
.result-select {
    width: auto;
    min-width: 4.5rem;
    font-size: 1.125rem;
    font-variant-numeric: tabular-nums;
}

.result-rank {
    margin-left: auto;
    padding: .125rem .375rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-teal-050);
    border: 1px solid var(--trr-teal-100);
    font-size: .875rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.result-flags { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .875rem; }
.result-flags .form-check-label { font-size: .875rem; }
.result-note { flex: 1 1 8rem; min-width: 7rem; }

/* Wer die Zahl draussen eingetragen hat. Eigene Zeile in der Flexreihe --
   sie gehoert zur Zeile und nicht zwischen die Haekchen. */
.result-quelle {
    flex: 1 0 100%;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

@media (max-width: 47.9375em) {
    .result-row { grid-template-columns: 1fr; gap: .5rem; }
    .result-rank { margin-left: 0; }
}

/* ------------------------------------------------------------- Aufstellung */

.starter-row {
    display: grid;
    grid-template-columns: minmax(12rem, 1.4fr) minmax(14rem, 1fr) 5rem;
    gap: .875rem;
    align-items: center;
    padding: .625rem .75rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.starter-row + .starter-row { margin-top: .5rem; }

/* Wer am Eventtag umgesetzt wurde, weicht von seiner Anmeldung ab. Das soll
   auffallen: Es ist die Ausnahme und die einzige Zeile, die jemand von Hand
   angefasst hat. */
.starter-row.is-changed {
    border-color: var(--trr-amber-600);
    background: var(--trr-amber-100);
}

.starter-person { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.starter-name { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; font-weight: 600; }
.starter-meta { font-size: .8125rem; font-weight: 400; color: var(--trr-ink-soft); }

.starter-role { display: flex; flex-wrap: wrap; gap: .25rem .875rem; }

.starter-role-option {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    font-size: .9375rem;
    cursor: pointer;
}

.starter-number .form-control { text-align: center; font-variant-numeric: tabular-nums; }

.starter-note {
    grid-column: 1 / -1;
    margin: 0;
    font-size: .875rem;
    color: var(--trr-ink);
}

/* Der Weg zur Fahrerkennung. Eine eigene Zeile und keine vierte Spalte: Die
   drei oben sind die Aufstellung, dieser Knopf ist der Renntag -- und auf
   einem schmalen Schirm waere die vierte Spalte ohnehin die erste, die
   bricht. */
.starter-kennung { grid-column: 1 / -1; justify-self: start; }

/* ----------------------------------------------------- Das Kennungsfenster */

.kennung-fenster { text-align: center; }

/* Weisser Grund unter dem Code, mitten in einer dunklen Seite: Ein Scanner
   erwartet dunkel auf hell. Umgekehrt lesen ihn viele Telefone gar nicht --
   und der eine, der es tut, steht dann allein auf der Wiese richtig. */
.kennung-qr {
    display: inline-block;
    padding: .75rem;
    border-radius: var(--trr-radius-sm);
    background: #fff;
    line-height: 0;
}

.kennung-qr img { width: 15rem; height: 15rem; max-width: 100%; }

/* Die Adresse im Klartext -- fuer Geraete ohne Kamera und fuer die
   Pruefumgebung. Sie darf ueberall umbrechen: Ein Link, der die Seite breiter
   macht als den Schirm, ist auf einem Telefon schlimmer als einer, der
   dreizeilig ist. */
.kennung-link {
    margin: .75rem 0 0;
    font-size: .8125rem;
    overflow-wrap: anywhere;
}

/* Zum Abtippen, wenn keine Kamera will: gleiche Zeichenbreiten und Luft
   dazwischen, damit man die Stelle wiederfindet, an der man war. */
.kennung-code {
    margin: .875rem 0 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 1.125rem;
    letter-spacing: .12em;
    overflow-wrap: break-word;
}

@media (max-width: 47.9375em) {
    .starter-row { grid-template-columns: 1fr 5rem; }
    .starter-person { grid-column: 1 / -1; }
}

/* ------------------------------------------------------------------ Joker */

.joker-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .875rem;
    padding: .4375rem 0;
    border-bottom: 1px solid var(--trr-line);
}

.joker-row:last-of-type { border-bottom: 0; }
.joker-check { flex: 1 1 12rem; display: flex; align-items: center; gap: .5rem; }
.joker-game { flex: 1 1 14rem; max-width: 20rem; }

/* Im Stationsmodus steht hier kein Auswahlfeld, sondern der Stand: Gesetzt
   wird die Karte draussen beim Betreuer, hier liest man nur nach, ob sie
   schon gespielt ist. Gedaempft, weil es eine Auskunft ist und keine
   Eingabe -- sonst greift man danach. */
.joker-stand { font-size: .9375rem; color: var(--trr-ink-soft); }

/* ------------------------------------------------------------- Siegertabelle */

/* Bei acht Spielen wird die Tabelle breiter als jedes Handy. Sie schiebt sich
   dann für sich, damit nicht die ganze Seite seitwärts läuft. */
.table-scroll { overflow-x: auto; }

.standings-table { font-variant-numeric: tabular-nums; margin-bottom: .75rem; }
.standings-table th, .standings-table td { vertical-align: middle; }

.standings-place { width: 3.5rem; text-align: right; font-weight: 700; }

.standings-game { text-align: center; white-space: nowrap; }
.standings-game-no { display: none; }
.standings-game-name { font-size: .875rem; }

/* Auf schmalen Geräten nur die Spielnummer -- acht Namen nebeneinander
   passen nirgends, acht Ziffern schon. */
@media (max-width: 61.9375em) {
    .standings-game-no { display: inline; font-weight: 700; }
    .standings-game-name { display: none; }
}

.standings-total { text-align: right; white-space: nowrap; }
.standings-total strong { font-size: 1.125rem; }

.standings-person { display: flex; align-items: center; gap: .5rem; }
.standings-name { display: block; font-weight: 600; line-height: 1.2; }
.standings-meta { display: block; font-size: .8125rem; font-weight: 400; color: var(--trr-ink-soft); }

.standings-points { font-weight: 700; font-size: 1.0625rem; line-height: 1.2; }

/* Platz und Ergebnis stehen zusammen unter der Punktzahl.
   ----------------------------------------------------------------------
   Frueher hing der Platz als blasses "1." rechts neben der Zahl. Das war
   sparsam und missverstaendlich: Zwei Zahlen nebeneinander liest man als
   eine Angabe. Untereinander ist klar, was die Hauptsache ist und was sie
   erklaert. */
.standings-value {
    display: block;
    font-size: .75rem;
    line-height: 1.3;
    color: var(--trr-ink-soft);
    margin-top: .0625rem;
}
.standings-empty { color: var(--trr-ink-soft); }
.standings-void { font-size: .8125rem; color: var(--trr-ink-soft); font-style: italic; }
.standings-penalty { display: block; font-size: .8125rem; color: var(--trr-hot); }

/* Das Joker-Spiel ist der Grund, warum jemand vorne steht -- ohne Markierung
   liest sich die verdoppelte Zahl wie ein Rechenfehler. */
.standings-game.is-joker {
    background: var(--trr-amber-100);
    box-shadow: inset 0 0 0 1px var(--trr-amber-600);
    border-radius: var(--trr-radius-sm);
}

.standings-legend { display: block; margin-top: .25rem; }
.standings-legend .is-joker { padding: 0 .25rem; background: var(--trr-amber-100); border-radius: 4px; }

/* Die ersten drei. Zurückhaltend -- eine Tabelle, in der ein Platz leuchtet,
   liest sich schlechter als eine, in der er nur etwas heller ist. */
.standings-table tr.is-podium td { background: var(--trr-teal-050); }
.standings-table tr.is-place-1 td { background: var(--trr-amber-100); font-weight: 600; }

.standings-kids { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--trr-line); }
.standings-kid-list { display: flex; flex-wrap: wrap; gap: .5rem .875rem; }

.standings-kid {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    font-size: .9375rem;
}

/* ------------------------------------------------------------- Regelwerk */

.rulebook-paragraph {
    margin: 1.5rem 0 .375rem;
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--trr-teal-700);
}

.rulebook-paragraph:first-child { margin-top: 0; }

.rulebook-title {
    margin: 1.75rem 0 .375rem;
    font-size: 1.125rem;
    font-weight: 700;
}

.rulebook-text { margin: 0 0 .75rem; max-width: 42rem; line-height: 1.6; }

/* Ein Regelwerk tippt man in einem Zug. Events Breite und eine Schrift mit
   gleichen Ziffernbreiten machen die Paragraphenstriche untereinander
   sichtbar. */
.rulebook-input { font-size: 1rem; line-height: 1.55; }

.plain-list { list-style: none; margin: 0; padding: 0; }
.plain-list li { padding: .25rem 0; }

/* ------------------------------------------------------ Wer wird es wohl? */

/* Die Bühne vor der Freigabe. Nur eine Karte ist sichtbar, alle liegen
   übereinander -- so springt beim Wechsel nichts, gleichgültig wie lang die
   Namen sind. */
.guess {
    text-align: center;
    padding: 1.5rem 0 .5rem;
}

.guess-slogan {
    margin: 0 0 1.25rem;
    font-family: "Bitter", Georgia, serif;
    font-size: 1.25rem;
    color: var(--trr-ink-soft);
}

/* Die Buehne muss so hoch sein wie die hoechste Karte darin.
   ------------------------------------------------------------------------
   Die Karten liegen absolut uebereinander (inset: 0) -- sie messen sich
   also nicht selbst aus, sondern richten sich nach diesem Wert. Wer den
   Kreis vergroessert, muss hier mit: 11rem Kreis + zwei Fugen a .5rem +
   Name (1,125rem) + Nummer (.875rem), beide bei Zeilenhoehe 1,6, sind
   15,2rem. 15,5rem laesst etwas Luft -- die Zeilenhoehe haengt an der
   Schrift, und ein halber Bildpunkt zu wenig schneidet die Nummer ab.

   Vorher stand hier 8,5rem zu einem Kreis von 5,5rem -- dieselbe Rechnung
   mit den alten Zahlen. */
.guess-stage {
    position: relative;
    min-height: 15.5rem;
}

.guess-card {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .5rem;
    opacity: 0;
    transform: scale(.94);
    transition: opacity .5s ease, transform .5s ease;
    pointer-events: none;
}

.guess-card.is-current { opacity: 1; transform: none; }

/* Der grosse Kreis ist hier die Hauptsache und kein Beiwerk: Die halbe
   Seite ist ein Ratespiel, und geraten wird ueber das Gesicht. Elf statt
   fuenfeinhalb Zentimeter -- damit steht er ueber avatar-xl (7rem, die
   Personenkarte) und ist der groesste Kreis im Portal.

   Der Ring bleibt drei Punkte stark: Er soll den Kreis fassen und nicht
   mit ihm wachsen, sonst wird aus einer Fassung ein Reifen. */
.guess-card .avatar {
    width: 11rem;
    height: 11rem;
    box-shadow: 0 0 0 3px var(--trr-teal-600);
}

.guess-name { font-size: 1.125rem; font-weight: 600; }
.guess-number { font-size: .875rem; color: var(--trr-ink-soft); }

/* Ohne Bewegung stehen alle nebeneinander statt nacheinander: dieselbe
   Auskunft, nur ruhig. */
.guess.is-still .guess-stage {
    position: static;
    min-height: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.25rem;
}

.guess.is-still .guess-card {
    position: static;
    opacity: 1;
    transform: none;
    transition: none;
    inset: auto;
}

@media (prefers-reduced-motion: reduce) {
    .guess-card { transition: none; }
}

.guess-heading {
    margin: 1.5rem 0 .75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--trr-line);
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.guess-list { display: flex; flex-wrap: wrap; gap: .5rem 1.25rem; }

.guess-entry {
    display: inline-flex;
    align-items: center;

    /* Etwas mehr Luft als sonst neben einem Namen: Der Kreis ist hier
       doppelt so gross, und die alten sieben Punkte sahen daneben aus wie
       ein Versehen. */
    gap: .75rem;
    font-size: 1rem;
}

/* Vier statt zwei Zentimetern -- doppelt so gross wie ein Kreis sonst in
   einer Aufzaehlung.
   ------------------------------------------------------------------------
   Ein Wort dazu, warum das hier und nicht in der Ansicht steht: Die Ansicht
   ruft den Avatar mit "sm", und das bleibt richtig -- sm ist die Groesse
   fuer einen Kreis neben einem Namen, und daran aendert sich nichts. Diese
   eine Liste will ihn nur groesser, weil sie dieselben Gesichter zeigt wie
   das Ratespiel darueber. Wer .avatar-sm anfasst, aendert vierzig andere
   Stellen mit. */
.guess-entry .avatar {
    width: 4rem;
    height: 4rem;
}

/* ------------------------------------------------- Zugang: Kennungen und Reset */

.account-logins {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem .875rem;
    margin-top: .25rem;
}

.account-login { display: inline-flex; align-items: baseline; gap: .3125rem; }

.account-login-art {
    font-size: .8125rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--trr-ink-soft);
}

.account-login code { font-size: .875rem; }

/* Aufgeklappt statt dauerhaft sichtbar: Ein Passwortfeld in jeder Zeile
   macht aus einer Übersicht ein Formular, und benutzt wird es selten.

   Steht als eigene Zeile unter dem Zugang, nicht darin: Die Zeile ist ein
   Formular fuer die Rollen, und ein Formular im Formular gibt es in HTML
   nicht. Der eingerueckte Rand links haelt beides sichtbar zusammen. */
.account-reset {
    margin: -.375rem 0 .25rem 1.25rem;
    padding: 0 .875rem .5rem;
    border-left: 2px solid var(--trr-line);
    font-size: .9375rem;
}

.account-reset > summary {
    cursor: pointer;
    padding: .375rem 0;
    color: var(--trr-ink-soft);
}

.account-reset > summary:hover { color: var(--trr-teal-700); }

.account-reset-form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .75rem 1rem;
    margin: .5rem 0 .75rem;
}

.account-reset-field { flex: 1 1 16rem; max-width: 22rem; }
.account-reset-field .form-label { margin-bottom: .25rem; }
.account-reset-check { display: inline-flex; align-items: center; gap: .375rem; padding-bottom: .4375rem; }

/* Das einmal gezeigte Passwort. Auffällig, weil es genau eine Gelegenheit
   gibt, es zu lesen -- danach ist es fort. */
.account-secret {
    display: flex;
    flex-direction: column;
    gap: .375rem;
    margin: .5rem 0 .25rem;
    padding: .875rem 1rem;
    border: 1px solid var(--trr-amber-600);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-amber-100);
}

.account-secret-label { font-weight: 600; }

.account-secret-value {
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: .04em;
    user-select: all;
}

.account-secret-hint { font-size: .875rem; color: var(--trr-ink-soft); }

/* ------------------------------------------------- Vertraute Geräte */

/* Das Kästchen unter der Code-Eingabe. Etwas Abstand nach oben, damit es
   nicht am Eingabefeld klebt und wie dessen Fußnote wirkt. */
.trust-check { margin-top: -.25rem; }

.device-list {
    list-style: none;
    margin: 0;
    padding: 0;
    border-top: 1px solid var(--trr-line);
}

.device-item {
    display: flex;
    flex-direction: column;
    gap: .15rem;
    padding: .7rem 0;
    border-bottom: 1px solid var(--trr-line);
}

.device-name { font-weight: 600; }
.device-meta { font-size: .875rem; color: var(--trr-ink-soft); }

/* Das Gerät, an dem man gerade sitzt, hervorheben -- sonst muss der Nutzer
   raten, welche Zeile er selbst ist, bevor er etwas widerruft.
   Farben aus den Themenvariablen: beide wechseln mit hell und dunkel
   bereits von selbst, ein eigener Dunkelblock waere hier doppelt. */
.device-badge {
    display: inline-block;
    margin-left: .4rem;
    padding: .05rem .45rem;
    border-radius: 999px;
    background: var(--trr-teal-100);
    color: var(--trr-teal-600);
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .02em;
}

/* --------------------------------------------- Zweiten Faktor ablösen */

.totp-remove {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: .75rem 1.25rem;
}

.totp-remove-field { flex: 1 1 16rem; max-width: 22rem; }

/* Der Button steht auf der Höhe des Feldes, nicht auf der des Hinweises
   darunter -- sonst hängt er in der Luft. */
.totp-remove > .btn { margin-top: 1.9rem; }

@media (max-width: 35.9375em) {
    .totp-remove > .btn { margin-top: 0; }
}

/* ---------------------------------------------------- Umfrage-Ergebnisse */

/* Ohne Trennstrich, wie im Ablauf daneben: Innerhalb eines Kastens
   braucht es ihn, sonst verschwimmen zwei Fragen zu einer. Ohne Kasten
   reicht der Abstand -- und die fette Frage darueber faengt das Auge
   ohnehin. */
.tally + .tally { margin-top: 2rem; }
.tally-question { margin: 0 0 .625rem; font-weight: 600; }
.tally-empty { margin: 0; font-size: .9375rem; color: var(--trr-ink-soft); }

.tally-bars { list-style: none; margin: 0; padding: 0; display: grid; gap: .375rem; }

.tally-row {
    display: grid;
    grid-template-columns: minmax(6rem, 10rem) 1fr 2.5rem;
    gap: .625rem;
    align-items: center;
}

.tally-label { font-size: 1rem; }

/* Der Balken ist Beiwerk: Die Zahl daneben sagt dasselbe, nur genauer. Für
   Bildschirmleser ist er deshalb ausgeblendet. */
.tally-bar {
    height: .5rem;
    border-radius: 999px;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    overflow: hidden;
}

.tally-bar > span {
    display: block;
    height: 100%;
    background: var(--trr-teal-600);
    border-radius: 999px;
}

.tally-count {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.tally-row.is-zero .tally-label,
.tally-row.is-zero .tally-count { color: var(--trr-ink-soft); font-weight: 400; }

/* --------------------------------------------------------- Offene Posten */

.posten-event {
    margin: 1.5rem 0 .625rem;
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
}

.posten-event:first-child { margin-top: 0; }
.posten-event a { color: inherit; text-decoration: none; }
.posten-event a:hover { color: var(--trr-teal-700); }
.posten-event-datum { font-weight: 400; letter-spacing: 0; text-transform: none; }

.posten-row {
    display: grid;
    grid-template-columns: minmax(11rem, 1.3fr) minmax(10rem, 1fr) minmax(14rem, auto);
    gap: .75rem 1rem;
    align-items: center;
    margin: 0 0 .5rem;
    padding: .75rem .875rem;
    border: 1px solid var(--trr-line);
    border-left: 3px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/* Der linke Streifen trägt den Zustand. Farbe allein wäre zu wenig -- der
   Text daneben sagt dasselbe noch einmal. */
.posten-row.is-offen     { border-left-color: var(--trr-amber-600); }
.posten-row.is-teilweise { border-left-color: var(--trr-teal-600); }
.posten-row.is-bezahlt   { border-left-color: var(--trr-ok); opacity: .78; }

.posten-wer { display: flex; flex-direction: column; gap: .125rem; min-width: 0; }
.posten-familie { font-weight: 600; }
.posten-meta { font-size: .875rem; color: var(--trr-ink-soft); }
.posten-referenz code { font-size: .8125rem; word-break: break-all; }

.posten-betrag { display: flex; flex-direction: column; gap: .125rem; }
.posten-soll { font-size: 1.125rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.posten-zustand { font-size: .875rem; }
.posten-zustand.is-open { color: var(--trr-warn); }
.posten-zustand.is-part { color: var(--trr-teal-700); }
.posten-zustand.is-done { color: var(--trr-ok); }
.posten-zustand.is-over { color: var(--trr-hot); font-weight: 600; }
.posten-zustand.is-sponsor { color: var(--trr-teal-700); }
.posten-notiz { font-size: .8125rem; color: var(--trr-ink); font-style: italic; }

/* Die Spur der Erinnerung. Gedaempft und nicht warnfarben: Sie meldet
   nichts, was zu tun waere -- sie sagt, was schon getan wurde. */
.posten-erinnert {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

.posten-erinnert-icon { width: .875rem; height: .875rem; flex: none; }

.posten-aktion { display: flex; flex-wrap: wrap; gap: .375rem; align-items: center; }
.posten-feld { max-width: 7.5rem; }

@media (max-width: 47.9375em) {
    .posten-row { grid-template-columns: 1fr; }
    .posten-feld { max-width: none; flex: 1 1 6rem; }
}

/* ------------------------------------------------------- Datensicherung */

.backup-rows { display: grid; gap: .5rem; }

.backup-row {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: .75rem 1rem;
    align-items: center;
    padding: .625rem .875rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

/* Was beim nächsten Lauf verschwindet, soll man vorher sehen -- nicht
   hinterher vermissen. */
.backup-row.is-doomed { border-style: dashed; opacity: .7; }

.backup-wann { display: flex; flex-direction: column; gap: .125rem; min-width: 0; }
.backup-datum { font-weight: 600; }
.backup-name code { font-size: .8125rem; word-break: break-all; color: var(--trr-ink-soft); }
.backup-groesse { font-variant-numeric: tabular-nums; white-space: nowrap; }
.backup-aktion { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.backup-warnung { font-size: .8125rem; color: var(--trr-warn); }

.backup-cron {
    margin: 0 0 1rem;
    padding: .875rem 1rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    font-size: .875rem;
    overflow-x: auto;
}

@media (max-width: 35.9375em) {
    .backup-row { grid-template-columns: 1fr; }
}

/* ------------------------------------------------ Geführte Erstanmeldung */

.onboarding-check {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    padding: .875rem 1rem;
    border: 1px solid var(--trr-teal-600);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-teal-050);
    font-weight: 600;
}

.onboarding-check .form-check-input { margin-top: .1875rem; flex: 0 0 auto; }

/* Zwei Zusagen untereinander brauchen Luft dazwischen. Ohne sie beruehren
   sich zwei tuerkise Rahmen, und aus zwei Fragen wird optisch eine mit
   einem Strich in der Mitte. */
.onboarding-check + .onboarding-check { margin-top: .75rem; }

/* Hier lagen .onboarding-rows/-row/-name: die Zeilen der Geburtstagsseite
   aus der gefuehrten Erstanmeldung. Die Seite gibt es nicht mehr -- gefragt
   wird jetzt dort, wo es gebraucht wird. .onboarding-check bleibt: Das
   Haekchen steht weiter unter der Einwilligung zum Bildschutz. */

/* Die drei Saetze in der Begruessung.
   ------------------------------------------------------------------------
   Etwas mehr Luft als bei .safety-list: Dort liest man eine Aufzaehlung von
   Zusagen am Stueck, hier drei getrennte Orte im Portal -- und zwischen
   ihnen soll das Auge anhalten. */
.willkommen-liste {
    margin: 0 0 1rem;
    padding-left: 1.1rem;
}

.willkommen-liste li { margin-bottom: .875rem; }
.willkommen-liste li:last-child { margin-bottom: 0; }

/* Der Name der Sache auf einer eigenen Zeile.
   ------------------------------------------------------------------------
   Vorher lief er im Fliesstext weiter: fett, dann ein Leerzeichen, dann die
   Erklaerung. Beim Ueberfliegen -- und ueberflogen wird so eine Liste immer --
   verschwimmt beides zu einem Absatz, und der fette Anfang ist nur noch eine
   Betonung statt einer Ueberschrift.

   Als eigene Zeile findet das Auge zuerst die drei Namen und liest darunter
   weiter, wenn es einen davon braucht. */
.willkommen-liste.ist-benannt > li > strong {
    display: block;
    margin-bottom: .125rem;
}

/* Und ein Satz, der fuer sich stehen soll: die eine Folge, die zaehlt. Sie
   im selben Absatz mit dem Beiwerk zu mischen hiesse, sie zu verstecken. */
.willkommen-liste .ist-kern,
.portal-kachel .ist-kern {
    display: block;
    margin-bottom: .25rem;
}

/* ------------------------------------------------ Die Fenster des Portals */

/* Ein Fenster, das informiert, und keins, das etwas verlangt.
   ------------------------------------------------------------------------
   Vorher war es ein grauer Kasten mit einem helleren Kasten darin -- der
   Hinweis am Fuss trug denselben Verlauf wie eine Meldung auf der Seite und
   sah dadurch aufgeklebt aus. Zwei Flaechen uebereinander auf engem Raum,
   und das Ganze las sich gepresst.

   Umgedreht: Der Verlauf liegt jetzt aussen, das Fenster selbst ist die
   Flaeche. Der Hinweis darin verliert seinen Grund und behaelt nur die
   farbige Kante -- er ist eine hervorgehobene Stelle im Text und kein
   zweites Schild.

   Dazu Luft und ein Gesicht: mehr Rand, keine Trennlinien, und der Traktor
   als Wasserzeichen in der Ecke. Ein Fenster, das beim ersten Besuch
   aufgeht, ist der erste Eindruck der Seite -- es darf nach dem Portal
   aussehen und nicht nach einem Systemdialog.

   Die Klasse hiess einmal .hinweis-fenster. Dann bekam die Glocke dieselbe
   Aufmachung, und eine Merkliste ist kein Hinweis -- ein Name, der nur auf
   den ersten Aufruf passt, wird beim zweiten zur kleinen Luege. */
.portal-dialog { max-width: 620px; }

/* Eine Seite, die man liest oder ausfuellt -- schmaler als der uebrige
   Inhalt.
   ------------------------------------------------------------------------
   Eine Zeile ueber die volle Breite eines grossen Schirms verliert man beim
   Zuruecksprung an den Zeilenanfang, und ein Formular mit drei Feldern sieht
   darin verloren aus.

   Hiess einmal .bildschutz-seite, weil die Einwilligung die erste war. Beim
   zweiten Aufruf -- der Adressaenderung -- war der Name eine falsche
   Faehrte. */
.portal-seite {
    max-width: 48rem;
    margin-inline: auto;
}

/* Der Kopf steht mittig im Kasten -- samt Strich vor dem Vorspann, wie die
   Abschnittsueberschriften auf der Startseite. Ein Kasten hat keine Kante,
   an der ein linksbuendiger Titel sich ausrichten koennte. */
.bildschutz-kopf {
    margin-bottom: 1.5rem;
    text-align: center;
}

.bildschutz-kopf .hero-kicker { justify-content: center; }

/* Die Schrittanzeige gehoert jetzt in den Kasten und darf darin nicht wie
   ein zweiter Kopf wirken. */
.portal-seite .step-track { margin-bottom: 1.5rem; }

/* Die Flaeche selbst -- in einem Fenster und auf einer Seite dieselbe.
   ------------------------------------------------------------------------
   Die Einwilligung zum Bildschutz ist bewusst eine Seite und kein Fenster:
   Man kommt an ihr nicht vorbei, und das soll man merken. Aussehen soll sie
   trotzdem wie der Rest -- ein Kasten im Bootstrap-Grau neben Fenstern mit
   Verlauf und Marke sieht aus wie eine Seite aus einem anderen Programm.

   Deshalb zwei Namen fuer eine Flaeche: .portal-fenster fuer die Fenster,
   .portal-flaeche fuer alles andere, was so aussehen soll. Die Randmasse
   weiter unten gelten nur den Fenstern -- eine Seite bringt ihre eigenen
   mit. */
.portal-fenster,
.portal-flaeche {
    position: relative;

    /* Der Schimmer kommt aus derselben Ecke wie die Marke -- ein Licht und
       ein Gegenstand, nicht zwei unabhaengige Effekte. */
    background:
        radial-gradient(110% 80% at 100% 0%, rgba(2, 176, 167, .13), transparent 62%),
        linear-gradient(to bottom, #242931, #191c22);
    overflow: hidden;
}

.portal-fenster .modal-header  { padding: 1.5rem 1.75rem 1rem; border-bottom: 0; }
.portal-fenster .modal-body    { padding: .25rem 1.75rem 1.5rem; }
.portal-fenster .modal-footer  { padding: 1rem 1.75rem 1.5rem; border-top: 0; }
.portal-fenster .modal-title   { font-size: 1.35rem; }

/* Angeschnitten und nicht mittig: Ein ganzer Traktor in der Ecke waere ein
   Bild, ein angeschnittener ist ein Wasserzeichen.

   Die Zeichnung aus dem Logo und nicht der Traktor aus dem Zeichensatz --
   das eine ist die Marke, das andere ein Piktogramm fuer "faehrt selbst".
   Und der Umriss, nicht die Flaeche: Bei so wenig Deckkraft wird aus der
   Flaeche ein Fleck, waehrend die Linien eine Zeichnung bleiben. Dass sie
   dafuer mehr Deckkraft braucht, liegt an ihrer duennen Strichstaerke --
   ein Fuenftel klingt viel und ist ein Hauch. */
.fenster-marke {
    position: absolute;
    top: -2rem;
    right: -2.25rem;
    width: 13rem;

    color: var(--trr-teal-700);
    opacity: .2;
    pointer-events: none;
}

.fenster-marke svg { display: block; width: 100%; height: auto; }

/* Bei sieben Schritten steht der Traktor mitten im letzten.
   ------------------------------------------------------------------------
   Oben rechts ist er richtig, solange dort nichts steht -- in den Fenstern
   und auf dem Bildschutz mit seinen drei Schritten ist das so. Die Anmeldung
   hat sieben, und der siebte liegt genau unter ihm; "Stimmt das so" war
   durch die Radspeichen kaum noch zu lesen.

   Also nach unten, wo der Kasten ausklingt. Er bleibt angeschnitten und in
   der Ecke -- nur in der anderen. */
.portal-flaeche.ist-treppe .fenster-marke {
    top: auto;
    bottom: -2rem;
}

.portal-fenster .willkommen-liste li { margin-bottom: 1.25rem; }

/* Die Namen in der Leitfarbe -- der helle Ton und nicht der Markenton
   selbst: Auf dieser Flaeche liegt teal-700 zu nah an der Textfarbe, und
   zwei aehnlich helle Toene uebereinander flimmern eher, als dass sie sich
   abheben. teal-800 setzt sich ab und bleibt ruhig. */
.portal-fenster .willkommen-liste.ist-benannt > li > strong {
    color: var(--trr-teal-800);
}

/* Der Hinweis im Fenster: nur die Kante, kein Grund.
   Tuerkis und nicht orange -- er erklaert, wie das Portal arbeitet, und
   meldet keinen Missstand. Auf der Seite darunter steht die orange Notiz
   fuer das, was gerade wirklich fehlt; zweimal dieselbe Farbe kurz
   hintereinander macht beide leiser. */
.portal-fenster .notiz {
    --flash-farbe: var(--trr-teal-700);

    background: none;
    box-shadow: inset 3px 0 0 var(--flash-farbe);
    border-radius: 0;
    margin: 1.5rem 0 0;
}

/* Ausser sie warnt wirklich.
   ------------------------------------------------------------------------
   Die Zeile darueber setzt tuerkis fuer jede Notiz im Fenster -- und
   ueberschrieb damit auch .ist-achtung, das eine Zeile weiter oben im
   Stylesheet steht. Der Sperrsatz auf "Meine Familie" war deshalb tuerkis,
   obwohl er als Warnung gedacht war und so auch angekuendigt wurde.

   Aufgefallen beim Nachmessen der Farbe, nicht beim Ansehen: Tuerkis auf
   dunklem Grund sieht neben orange richtig aus, solange man nicht weiss,
   was dort stehen sollte. */
.portal-fenster .notiz.ist-achtung { --flash-farbe: var(--trr-warn); }
.portal-fenster .notiz.ist-schlimm { --flash-farbe: var(--trr-hot); }

/* Ein Button, im Text genannt.
   ------------------------------------------------------------------------
   Wo eine Erklaerung auf etwas Anklickbares zeigt, soll man es wiederfinden.
   Der Name als blosser Fliesstext geht darin unter -- man liest ueber ihn
   hinweg und sucht danach auf der Seite nach etwas, das man schon gelesen
   hat.

   Als Chip und nicht in nichtproportionaler Schrift. Die trifft man im
   Protokoll des Veranstalters, und dort steht auch wirklich ein technischer
   Bezeichner ("family.avatar"); "Eure Buchung" ist dagegen gewoehnlicher
   Text auf einem Button. Nichtproportional saehe er aus wie ein Dateiname
   und saesse mit seiner kleineren Schrift schief in der Zeile.

   Der Chip ist stattdessen ein Miniaturbild der Sache selbst: dieselbe
   Rundung, dieselbe Leitfarbe, nur flach. Wer ihn liest, hat den Button
   schon gesehen, bevor er ihn sucht.

   white-space: nowrap, damit eine Beschriftung aus zwei Woertern nicht am
   Zeilenende auseinanderfaellt -- ein halber Button in der einen und ein
   halber in der naechsten Zeile ist kein Bild mehr, sondern ein Fehler. */
.button-name {
    display: inline-flex;
    align-items: center;
    gap: .3em;
    padding: .05em .4em;

    background: rgba(2, 176, 167, .12);
    border-radius: 6px;
    box-shadow: inset 0 0 0 1px rgba(2, 176, 167, .28);

    color: var(--trr-teal-800);
    font-weight: 600;
    white-space: nowrap;

    /* inline-flex sitzt auf der Grundlinie seines Kastens und nicht auf der
       des Textes -- ohne diese Zeile stuende der Chip einen Hauch zu hoch
       zwischen den Woertern. */
    vertical-align: -.15em;
}

/* Nennt der Chip einen Punkt der Leiste, traegt er dessen Zeichen: Man sucht
   dort oben nach einem Bild und nicht nach einem Wort. Etwas kleiner als die
   Schrift daneben -- ein Zeichen in Textgroesse wirkt groesser als sie. */
.button-name-icon {
    width: .9em;
    height: .9em;
    flex: 0 0 auto;
}

/* Die Orte des Portals als Kacheln.
   ------------------------------------------------------------------------
   Drei Saetze in einer Liste standen hier und waren zu wenig: Die Leiste hat
   vier Ziele und drei Zeichen, und wer von dreien liest, sucht die uebrigen
   vier spaeter selbst.

   Als Raster, weil es eine Uebersicht ist und keine Erzaehlung -- man liest
   nicht von oben nach unten, sondern sucht das eine, das man gerade braucht.
   Und mit dem Zeichen aus der Leiste in jeder Kachel: Nicht der Text sagt,
   wo etwas liegt, sondern das Bild. Man sieht es hier und erkennt es dort
   wieder.

   Zwei Spalten und nicht drei: Bei dreien blieben je Kachel gut zwei Woerter
   Zeilenbreite, und aus zwei Saetzen wuerden sechs Zeilen. */
/* Die Ueberschrift ueber einer Gruppe -- mittig, leise, in Versalien wie die
   Kicker sonst im Portal. Sie steht anstelle einer Trennlinie: Ein Strich
   sagt nur, dass hier etwas anderes anfaengt, ein Wort sagt auch was. */
.portal-raster-kopf {
    margin: 1.5rem 0 .625rem;

    font-family: var(--bs-body-font-family);
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    text-align: center;
    color: var(--trr-ink-soft);
}

.portal-raster {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .75rem;
    margin-top: 1.25rem;
}

/* Eine Kachel ueber die ganze Breite -- fuer die, die zu viel Inhalt hat,
   um sich eine Spalte mit einer anderen zu teilen. */
.portal-kachel.ist-breit { grid-column: 1 / -1; }

/* Die Rundknoepfe untereinander: eine Zeile je Stueck.
   Sie sind eine andere Sorte Sache als die vier Ziele -- eine Trennlinie
   dazwischen waere ein Strich, der sagt, was die Anordnung schon sagt. */
.portal-raster.ist-untereinander { grid-template-columns: minmax(0, 1fr); }

/* Dieselbe Machart wie die Pillen auf der Eventseite: kein Rahmen, sondern
   ein flacher Verlauf mit Lichtkante. Ein Rahmen um sieben Kaesten ergaebe
   ein Gitter, und das Fenster saehe aus wie eine Tabelle. */
.portal-kachel {
    padding: .875rem 1rem 1rem;

    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .06),
            rgba(255, 255, 255, .02)
        );
    border-radius: var(--trr-radius-sm);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .1),
        0 1px 2px rgba(0, 0, 0, .25);
}

/* ==========================================================================
   Wer kommt mit -- die Personen als Karten
   ==========================================================================
   Es war eine Liste aus Haekchen mit Name und Alter daneben. Das war eine
   Abfrage; hier geht es aber um Menschen, und die erkennt man am Gesicht
   schneller als am Namen.

   Gebaut wie die Kacheln darueber, nur hochkant: derselbe Verlauf, dieselbe
   Lichtkante, derselbe Radius. Auf dieser Flaeche soll nichts aussehen wie
   aus einem anderen Programm. */
.pers-wahl {
    /* Reihe statt Raster.
       --------------------------------------------------------------------
       Mit auto-fill und 1fr wurden aus drei Karten drei Sechstel Breite und
       die halbe Reihe blieb leer. Mit einem Deckel im Raster stimmte die
       Breite, aber die Zahl der Spalten nicht: Ein Raster rechnet sie aus
       der Hoechstbreite aus, und auf mittleren Schirmen umbrach die dritte
       Karte, obwohl sie noch gepasst haette.

       Eine Reihe rechnet mit der Mindestbreite und packt nach links. Die
       Karten wachsen bis 13,5rem und nicht weiter -- sonst wuerden aus zwei
       Karten zwei Plakate.

       Mittig statt links: Der Deckel von 13,5rem bleibt richtig, aber drei
       Karten in einem breiten Panel liessen rechts ein Loch von fast der
       halben Breite. Das las sich nicht als grosszuegig, sondern als
       abgeschnitten. Zentriert ist die Flaeche links und rechts gleich
       leer, und das wirkt gewollt. An den Kartenbreiten aendert es nichts. */
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    margin: 1.5rem 0 0;
    padding: 0;
    border: 0;
}

.pers-karte {
    position: relative;
    flex: 1 1 10.5rem;
    max-width: 13.5rem;

    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .3rem;

    padding: 1.25rem 1rem;
    text-align: center;

    background:
        linear-gradient(
            to bottom,
            rgba(255, 255, 255, .06),
            rgba(255, 255, 255, .02)
        );
    border: 1px solid transparent;
    border-radius: var(--trr-radius-sm);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .1),
        0 1px 2px rgba(0, 0, 0, .25);

    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

/* Das Haekchen traegt die Auswahl und bleibt ein echtes Formularfeld -- die
   Tastatur erreicht es, ein Vorleser nennt es. Sichtbar ist davon nur, was
   die Karte tut. Nicht display:none: Das nimmt es aus der Reihenfolge der
   Tastatur, und die Karte waere dann nur noch mit der Maus zu bedienen. */
.pers-haken {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.pers-karte:hover { border-color: var(--trr-teal-600); }

/* Ausgewaehlt: Rahmen im Markenton und ein Hauch davon im Grund. */
.pers-karte:has(.pers-haken:checked) {
    border-color: var(--trr-teal-700);
    background-color: rgba(2, 176, 167, .07);
}

/* Der Ring der Tastatur gehoert um die Karte und nicht um ein Feld, das
   niemand sieht. */
.pers-karte:has(.pers-haken:focus-visible) {
    outline: 2px solid var(--trr-teal-600);
    outline-offset: 2px;
}

.pers-bild { line-height: 0; }
.pers-bild .avatar { width: 4.5rem; height: 4.5rem; }

.pers-name {
    margin-top: .5rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--trr-ink);
}

.pers-alter { font-size: .875rem; color: var(--trr-ink-soft); }

/* Die Freikarte in Bernstein -- dieselbe Farbe wie das Ticket auf der
   Kachel der Startseite und im Fenster davor. */
.pers-frei {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    margin-top: .35rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-amber-500);
}

.pers-frei-icon { width: .9rem; height: .9rem; }

/* Der Streifen unten.
   ------------------------------------------------------------------------
   Er steht immer da und wechselt nur sein Wort. Erschiene er erst beim
   Auswaehlen, spraengen die Karten in der Hoehe, sobald man eine abwaehlt --
   und eine Karte ohne Streifen sagte nicht, was ein Klick bewirkt. */
.pers-streifen {
    display: block;
    width: 100%;

    /* Nach unten geschoben und ueberall gleich weit vom Rand.
       --------------------------------------------------------------------
       Mit festem Abstand nach oben hing der Streifen an dem, was ueber ihm
       stand: Wer eine Freikarte hat, hat eine Zeile mehr -- dessen Streifen
       rutschte bis an die Kante, waehrend er bei den anderen mitten in der
       Karte sass. Zwei Karten nebeneinander sahen dann verschieden gebaut
       aus.

       auto schiebt ihn in jeder Karte ganz nach unten; das Polster der Karte
       haelt ueberall denselben Abstand zum Rand. Was darueber fehlt, wird zu
       Luft und nicht zu einer anderen Position. */
    margin-top: auto;
    padding: .4rem .5rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;

    background: rgba(255, 255, 255, .05);
    color: var(--trr-ink-soft);
}

.pers-ja { display: none; }

.pers-karte:has(.pers-haken:checked) .pers-streifen {
    background: var(--trr-teal-700);
    color: #062b29;
}

.pers-karte:has(.pers-haken:checked) .pers-ja   { display: inline; }
.pers-karte:has(.pers-haken:checked) .pers-nein { display: none; }

/* Ohne Geburtstag geht es nicht weiter. Die Karte bleibt stehen -- wer
   fehlt, soll sehen, dass er fehlt -- nimmt aber keinen Klick mehr an. Im
   Streifen steht dafuer der Weg zum Nachtragen. */
.pers-karte.ist-gesperrt {
    cursor: default;
    opacity: .65;
}

.pers-karte.ist-gesperrt:hover { border-color: transparent; }

/* Bernstein nur, wo wirklich etwas fehlt.
   ------------------------------------------------------------------------
   Die Farbe hing an der Sperre -- und die gibt es aus zwei Gruenden: weil
   ein Geburtstag fehlt, und weil jemand die Aufsicht fuehrt. Das erste ist
   ein Mangel, das zweite eine Tatsache. "Fuehrt die Aufsicht" in Warnfarbe
   las sich wie ein Fehler. */
.pers-alter.ist-mangel { color: var(--trr-amber-600); font-weight: 600; }

.pers-streifen.ist-fehlt { background: rgba(242, 169, 59, .12); }
.pers-streifen.ist-fehlt a { color: var(--trr-amber-500); text-decoration: none; }
.pers-streifen.ist-fehlt a:hover { text-decoration: underline; }

/* Auf dem Telefon zwei Karten nebeneinander und die Reihe voll.
   ------------------------------------------------------------------------
   Der Deckel von 13,5rem liess dort eine leere Spalte stehen: eine Karte je
   Zeile, rechts daneben nichts. Zwei halbe Breiten fuellen die Reihe und
   sparen zugleich die Haelfte des Scrollens. */
@media (max-width: 30em) {
    /* Zwei nebeneinander, und nicht wachsen: Eine dritte Person allein in
       der zweiten Reihe waere sonst ein Plakat neben zwei Karten. */
    .pers-karte {
        flex: 0 1 calc(50% - .5rem);
        max-width: none;
    }
}

/* Ohne :has() -- aeltere Browser -- bliebe die Karte stumm. Dann traegt
   wenigstens das Haekchen selbst die Auskunft, sichtbar in der Ecke. */
@supports not selector(:has(*)) {
    .pers-haken {
        position: static;
        width: auto;
        height: auto;
        opacity: 1;
        pointer-events: auto;
    }
}

/* Der Kopf einer Kachel sieht aus wie ein Punkt in der Leiste: Zeichen und
   Wort nebeneinander, Versalien, dieselbe Sperrung. Das ist der Zweck der
   ganzen Uebersicht -- man liest hier ein Bild und erkennt es dort wieder.
   Stuende es hier anders gesetzt, waere es eine Beschreibung der Leiste
   statt ihres Abbilds.

   .nav-icon und .nav-label kommen unveraendert von dort. Sie hier
   nachzubauen hiesse, zwei Stellen zu pflegen, die gleich aussehen
   muessen. */
.portal-kachel-kopf {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 .375rem;

    /* Der Ring hebt die Zeile hoeher als eine nackte Zeichenzeile -- der
       Abstand darunter darf dann kleiner sein, sonst faellt die Kachel
       auseinander. */
    min-height: 1.5rem;

    /* Die Grundschrift und nicht Bitter: Als Ueberschrift erbt der Kopf die
       Schreibschrift der Titel -- in der Leiste steht aber die Grundschrift,
       und genau die soll man wiedererkennen. */
    font-family: var(--bs-body-font-family);
    font-size: .875rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-teal-800);
}

.portal-kachel-text {
    margin: 0;
    font-size: .9375rem;
    line-height: 1.45;
    color: var(--trr-ink);
}

/* Eine Kachel, die von einer Freikarte handelt, traegt Bernstein.
   ------------------------------------------------------------------------
   Dieselbe Farbe wie das Ticket auf der Kachel der Startseite: Es ist
   dieselbe Sache, und man soll sie wiedererkennen, ohne sie zu lesen. */
.portal-kachel.ist-frei .portal-kachel-kopf { color: var(--trr-amber-500); }

/* Auf dem Telefon untereinander. Zwei Spalten waeren dort je etwa
   sechzehn Zeichen breit -- "Meine Familie" allein braucht dreizehn. */
@media (max-width: 480px) {
    .portal-raster { grid-template-columns: minmax(0, 1fr); }
}

/* Die Fusszeile eines Fensters: was links steht, links -- der Button rechts.
   ------------------------------------------------------------------------
   Bootstrap stellt im Fuss alles nach rechts. Was dort sonst noch steht --
   heute die Schrittanzeige des Einstiegsfensters -- landete damit direkt
   neben dem Button und sah aus, als gehoerte es zu ihm.

   Hier stand einmal das Kaestchen "nicht mehr zeigen", und mit ihm eine
   Regel fuer schmale Schirme: untereinander, der Button unten. Sie war der
   Handy-Fehler. `flex: 1 1 14rem` am Kaestchen meinte eine Breite, solange
   der Fuss eine Zeile war -- in einer Spalte ist flex-basis die Hoehe, und
   das Kaestchen nahm sich vierzehn Zeilen Platz. Der Button stand ganz
   unten, dazwischen gaehnte das halbe Fenster, und fuer den eigentlichen
   Inhalt blieb die obere Haelfte.

   Das Kaestchen ist weg, und mit ihm die Regel. Was hier steht, ist heute
   schmal genug fuer eine Zeile -- auch auf dem Telefon. */
.hinweis-fuss {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

/* Eine Liste braucht oben etwas mehr Luft als ein Absatz.
   Ohne Trennlinie unter der Ueberschrift steht die erste Zeile der Glocke
   sonst direkt unter dem Titel und liest sich wie seine Fortsetzung. */
.portal-fenster .todo-list { margin-top: .625rem; }

/* Auf dem Telefon nimmt sich die Marke zurueck: Dort ist das Fenster halb
   so breit, und ein Traktor derselben Groesse laege quer ueber dem Text. */
@media (max-width: 575.98px) {
    .portal-fenster .modal-header { padding: 1.25rem 1.25rem .75rem; }
    .portal-fenster .modal-body   { padding: .25rem 1.25rem 1.25rem; }
    .portal-fenster .modal-footer { padding: .75rem 1.25rem 1.25rem; }
    .fenster-marke { width: 9rem; top: -1.25rem; right: -1.5rem; }
}

/* ------------------------------------------------ Hintergrundfilm im Kiosk */

/* Liegt hinter allem und nimmt keine Klicks an. Fixiert und nicht absolut:
   Der Kiosk ist genau einen Bildschirm hoch, und ein Film, der mitscrollt,
   könnte an der Kante abreißen. */
.kiosk-backdrop {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
}

/* Formatfüllend zuschneiden statt stauchen. Ein 16:9-Film auf einem
   21:9-Monitor sähe sonst aus wie in die Breite gezogen -- und niemand
   stellt einen Bildschirm an die Bar, damit die Gäste über verzerrte
   Cocktails reden. */
.kiosk-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/*
 * Der Schleier. Ohne ihn hängt die Lesbarkeit davon ab, was der Film gerade
 * zeigt -- bei einer hellen Stelle verschwindet weiße Schrift. Nach unten
 * dichter, weil dort der Name und die Zutaten stehen.
 */
.kiosk-scrim {
    position: absolute;
    inset: 0;
    background:
        linear-gradient(to bottom,
            rgba(6, 26, 32, .72) 0%,
            rgba(6, 26, 32, .58) 35%,
            rgba(6, 26, 32, .82) 100%);
}

/* Der Inhalt gehört über den Film. Ohne diese Zeile läge er darunter und
   wäre unsichtbar -- der Film hat einen Stapelkontext. */
.kiosk { position: relative; z-index: 1; }

/*
 * Wer Bewegung abgestellt hat, bekommt das Standbild. Der Film wird dabei
 * nicht nur angehalten, sondern ausgeblendet: Ein pausierter Film zeigt
 * irgendeinen Einzelbild-Zufall, das Plakat dagegen ist ausgesucht.
 */
@media (prefers-reduced-motion: reduce) {
    .kiosk-video { display: none; }

    /* Der Pfad steht hier und nicht im Markup: Die Sicherheitsregel des
       Portals verbietet Formatierung im HTML. Die Klasse sagt nur, ob es
       ein Standbild ueberhaupt gibt. */
    .kiosk-backdrop.has-poster {
        background-image: url("../video/bar.jpg");
        background-size: cover;
        background-position: center;
    }
}

/* ------------------------------------------------------ Balkenbreiten

   Die Sicherheitsregel des Portals verbietet Formatierung im Markup
   (style-src 'self' ohne 'unsafe-inline'). Ein style-Attribut wird
   deshalb stillschweigend verworfen -- der Balken stand danach immer
   auf voller Breite, und niemandem fiel es auf, weil ein voller
   Balken nicht nach einem Fehler aussieht.

   Fuenferschritte statt genauer Prozente: Bei einer Balkenbreite von
   ein paar hundert Pixeln ist der Unterschied zwischen 62 und 60
   Prozent nicht zu sehen, und die genaue Zahl steht ohnehin daneben.
   Die Regel dafuer aufzuweichen waere ein schlechter Tausch. */

.w-0 { width: 0%; }
.w-5 { width: 5%; }
.w-10 { width: 10%; }
.w-15 { width: 15%; }
.w-20 { width: 20%; }
.w-25 { width: 25%; }
.w-30 { width: 30%; }
.w-35 { width: 35%; }
.w-40 { width: 40%; }
.w-45 { width: 45%; }
.w-50 { width: 50%; }
.w-55 { width: 55%; }
.w-60 { width: 60%; }
.w-65 { width: 65%; }
.w-70 { width: 70%; }
.w-75 { width: 75%; }
.w-80 { width: 80%; }
.w-85 { width: 85%; }
.w-90 { width: 90%; }
.w-95 { width: 95%; }
.w-100 { width: 100%; }

/* Die Symbolsammlung selbst wird nie gezeichnet -- sie ist nur der Vorrat,
   aus dem <use> schoepft. Ohne diese Zeile bekaeme die SVG-Wurzel in
   manchen Browsern ihre Standardgroesse und risse auf jeder Seite eine
   Luecke von 300 x 150 Pixeln. */
.icon-sprite { display: none; }

/* ============================================================ Kiosk: Karte

   Die Liste rechts löst das Problem, an dem ein Karussell scheitert: Wer
   wissen will, was es gibt, müsste sonst einen vollen Umlauf abwarten.
   ========================================================================= */

/* Der Körper teilt sich in Bühne und Karte. Die Karte bekommt eine feste
   Breite statt eines Anteils -- ihre Zeilen müssen aus drei Metern lesbar
   sein, und das hängt an Zentimetern, nicht an Prozenten. */
.kiosk-body {
    display: flex;
    gap: 3vw;
    flex: 1 1 auto;
    min-height: 0;
}

.kiosk-body > .kiosk-stage { flex: 1 1 auto; }

/*
 * Das Glaskästchen. Milchglas entsteht aus drei Dingen zugleich: einem
 * halbdurchsichtigen Grund, der Unschärfe dahinter und einer hellen Kante
 * obenherum. Fehlt die Kante, sieht es aus wie ein grauer Kasten.
 *
 * backdrop-filter kostet Rechenleistung. Auf einem alten Tablet an der Bar
 * kann das ruckeln -- deshalb steht darunter ein Grund, der auch ohne
 * Unschärfe trägt.
 */
.kiosk-list {
    flex: 0 0 clamp(16rem, 24vw, 26rem);

    /*
     * Raster statt Flexbox, und das ist kein Geschmack: "Kopf oben, Legende
     * unten, Liste nimmt den Rest" ist mit grid-template-rows eine Zeile.
     * Mit Flexbox hing es an flex-basis, min-height und der Inhaltshöhe
     * zugleich -- das Fenster kam auf 682 Bildpunkte, obwohl 805 zur
     * Verfügung standen, und unter dem letzten Eintrag klaffte eine Lücke.
     */
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    min-height: 0;
    padding: 1.5rem 1.25rem;
    border-radius: 1.5rem;
    border: 1px solid rgba(255, 255, 255, .18);
    background: rgba(255, 255, 255, .08);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .25),
        0 24px 60px rgba(0, 0, 0, .35);
}

.kiosk-list-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 1rem;
    font-size: .9vw;
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .6);
}

.kiosk-list-count {
    padding: .1rem .5rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, .12);
    letter-spacing: 0;
}

/*
 * Das Fenster, durch das man auf die Liste sieht. Oben und unten laufen die
 * Einträge weich aus -- eine harte Kante sähe aus, als wäre der Text
 * abgeschnitten; ein Verlauf sagt "hier geht es weiter".
 */
.kiosk-list-window {
    position: relative;
    min-height: 0;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to bottom,
        transparent 0, #000 8%, #000 92%, transparent 100%);
    mask-image: linear-gradient(to bottom,
        transparent 0, #000 8%, #000 92%, transparent 100%);
}

.kiosk-list-items {
    list-style: none;
    margin: 0;
    padding: 0;
    transition: transform .6s cubic-bezier(.4, 0, .2, 1);
}

.kiosk-list-item {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .55rem .25rem;
    font-size: 1.15vw;
    color: rgba(255, 255, 255, .55);
    transition: color .4s ease, transform .4s ease;
}

/* Der laufende Eintrag. Nicht nur heller, sondern auch etwas größer und
   leicht eingerückt -- Farbe allein reicht aus drei Metern nicht. */
.kiosk-list-item.is-current {
    color: #fff;
    font-weight: 600;
    transform: translateX(.35rem) scale(1.06);
    transform-origin: left center;
}

.kiosk-list-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * Der Punkt sagt, ob Alkohol drin ist -- die Frage, die an einer Bar am
 * häufigsten gestellt wird, und auf einer Rallye erst recht: Wer noch fahren
 * muss, sucht genau danach. Deshalb steht dieselbe Auskunft unten noch
 * einmal als Legende; ein Farbpunkt ohne Erklärung ist nur ein Farbpunkt.
 */
.kiosk-list-dot {
    flex: 0 0 auto;
    width: .6rem;
    height: .6rem;
    border-radius: 999px;
    background: var(--trr-amber-500);
    box-shadow: 0 0 0 3px rgba(242, 169, 59, .18);
}

.kiosk-list-dot.is-free {
    background: var(--trr-teal-500);
    box-shadow: 0 0 0 3px rgba(2, 176, 167, .28);
}

.kiosk-list-legend {
    display: flex;
    align-items: center;
    /* Umbrechen erlaubt: Ausgeschrieben brauchen beide Seiten mehr Platz als
       vorher, und auf einem schmaleren Monitor sollen sie untereinander
       rutschen statt aus der Leiste zu laufen. */
    flex-wrap: wrap;
    column-gap: 1.1rem;
    row-gap: .35rem;
    margin: 1rem 0 0;
    padding-top: .75rem;
    border-top: 1px solid rgba(255, 255, 255, .12);
    font-size: .85vw;
    color: rgba(255, 255, 255, .5);
}

/* Punkt und Wort gehoeren zusammen. Als Geschwister koennte der Umbruch
   zwischen sie fallen -- dann staende ein nackter Punkt am Zeilenende. */
.kiosk-list-legend-item {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    white-space: nowrap;
}

/*
 * Der Auslauf verschwindet dort, wo nichts mehr folgt. Am Anfang und am
 * Ende ist die Liste zu Ende -- ein Verlauf wuerde dort den ersten und den
 * letzten Eintrag wegblenden und wie eine Luecke aussehen.
 */
.kiosk-list-window.is-at-start {
    -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 92%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 0, #000 92%, transparent 100%);
}

.kiosk-list-window.is-at-end {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 8%, #000 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #000 8%, #000 100%);
}

/* Beides zugleich heisst: Die Liste passt vollstaendig ins Fenster. */
.kiosk-list-window.is-at-start.is-at-end {
    -webkit-mask-image: none;
    mask-image: none;
}

/* Das Logo des Events statt der Marke. Es steht für sich und braucht keinen
   Namen daneben -- wer davorsteht, ist ohnehin auf dem Event. Deshalb darf es
   auch etwas größer sein als das Zeichen des Portals. */
.kiosk-logo {
    max-height: 7vh;
    width: auto;
    max-width: 26vw;
    object-fit: contain;
}

/* Auf schmalen Schirmen wandert die Karte unter die Bühne. Ein Kiosk hängt
   selten am Hochformat -- aber wenn doch, soll er nicht zerfallen. */
@media (max-aspect-ratio: 1/1) {
    .kiosk-body { flex-direction: column; }
    .kiosk-list { flex: 0 0 auto; max-height: 38vh; }
    .kiosk-list-item { font-size: 2.4vw; }
    .kiosk-list-head, .kiosk-list-legend { font-size: 1.8vw; }
}

/* Ohne Bewegung springt die Liste, statt zu gleiten. */
@media (prefers-reduced-motion: reduce) {
    .kiosk-list-items { transition: none; }
    .kiosk-list-item { transition: none; }
}


/* ==========================================================================
   Auf Papier

   Der einzige Ort, an dem das Portal hell ist — und der einzige, an dem
   Hell etwas nützt. Startlisten, Ergebnislisten und offene Posten wandern
   ans schwarze Brett in der Scheune oder in einen Ordner, und Toner für
   eine dunkelgraue Fläche auszugeben wäre Unfug.

   Das war der eigentliche Auftrag hinter dem alten Hellmodus, und er war
   nie erfüllt: Wer bisher druckte, bekam zufällig das, was sein Gerät
   gerade eingestellt hatte. Jetzt ist der Druck sein eigener Zustand und
   hängt an nichts.

   Grundsatz: Was auf Papier nichts entscheidet, kommt weg. Navigation,
   Reiterleiste, Schaltflächen und Formularrahmen führen gedruckt nirgends
   hin — sie kosten nur Platz und Tinte.
   ========================================================================== */

@media print {
    /* Farbe zurück auf Papier. Die Variablen umzubiegen genügt, weil das
       ganze Stylesheet über sie läuft -- einzelne Regeln nachzujagen wäre
       eine endlose Liste. */
    :root {
        /* Auf Papier ist es hell. Ohne diese Zeile bliebe die Angabe von
           oben stehen, und der Browser zeichnete Formularfelder und
           Bildlaufleisten weiter dunkel -- in einen weissen Ausdruck. */
        color-scheme: light;

        --trr-cream:     #ffffff;
        --trr-paper:     #ffffff;
        --trr-row:       #ffffff;
        --trr-ink:       #000000;
        --trr-ink-soft:  #444444;
        --trr-ink-quiet: #333333;
        --trr-line:      #999999;

        --trr-teal-900: #003530;
        --trr-teal-800: #004a44;
        --trr-teal-700: #00615a;
        --trr-teal-600: #00615a;
        --trr-teal-500: #00615a;
        --trr-teal-100: #ffffff;
        --trr-teal-050: #ffffff;

        --trr-amber-600: #7a5200;
        --trr-amber-500: #7a5200;
        --trr-amber-100: #ffffff;

        --trr-ok:   #005c3a;
        --trr-warn: #7a5200;
        --trr-hot:  #8a1c18;

        --trr-on-primary: #000000;

        --bs-body-bg:    #ffffff;
        --bs-body-color: #000000;

        --trr-shadow:    none;
        --trr-shadow-sm: none;

        /* Schimmer und Körnung sind Atmosphäre. Auf Papier sind sie ein
           blasser Fleck am oberen Rand, den man für einen Druckfehler
           hält -- und Toner kosten sie auch noch. */
        --trr-glow-cue:  transparent;
        --trr-glow-warm: transparent;
        --trr-grain:     0;
    }

    body {
        background: #fff !important;
        color: #000 !important;
        font-size: 11pt;
    }

    /* Was gedruckt nirgends hinführt.
       Eingabefelder gehören ausdrücklich dazu: Ein Suchfeld auf Papier ist
       ein leerer Kasten, in den niemand etwas tippen kann. */
    .app-navbar,
    .handy-menu,
    .offcanvas-backdrop,
    .page-head .back-link,
    .form-actions,
    .btn,
    .flash-stack,
    .kiosk,
    .kiosk-backdrop,
    input,
    select,
    textarea,
    .form-text,
    .filter-bar,
    .blaetter-seiten {
        display: none !important;
    }

    /* Flächen werden zu Umrissen: Ein Kasten ohne Füllung trennt genauso
       gut und kostet nichts. */
    .card,
    .content-card {
        background: #fff !important;
        border: 1px solid #999 !important;
        box-shadow: none !important;
    }

    /* Die äußere Hülle bekommt ausdrücklich KEINEN Rahmen. Ein Kasten um
       die ganze Seite sähe aus wie ein Fehldruck, und die Breitenbegrenzung
       des Bildschirms verschenkt auf A4 den halben Rand. */
    .app-main .container {
        padding: 0;
        max-width: none;
        width: auto;
    }

    .page-app { padding-bottom: 0; }

    /* Tabellen sind der Hauptgrund für den ganzen Abschnitt. Sie dürfen
       weder mitten in einer Zeile umbrechen noch ihre Kopfzeile verlieren:
       Eine Ergebnisliste auf Seite zwei ohne Spaltenköpfe ist Zahlensalat. */
    table { border-collapse: collapse !important; width: 100%; }
    thead { display: table-header-group; }
    tr, img { break-inside: avoid; page-break-inside: avoid; }

    table th,
    table td {
        border: 1px solid #999 !important;
        padding: .25rem .4rem !important;
        color: #000 !important;
    }

    h1, h2, h3 { break-after: avoid; page-break-after: avoid; }

    /*
     * Verweise werden zu gewöhnlichem Text.
     *
     * Die Adresse dahinterzuschreiben lag nahe und war falsch: Das Portal
     * baut alle Adressen absolut, also traf die Regel jeden Verweis --
     * mitten in einer Familienliste stand hinter jedem Namen eine URL, und
     * die Zeile war nicht mehr zu lesen. Nützen würde sie ohnehin nichts:
     * Hinter jeder dieser Adressen liegt eine Anmeldung, niemand tippt sie
     * vom Papier ab.
     */
    a {
        color: #000 !important;
        text-decoration: none !important;
    }
}


/* ==========================================================================
   Das Programm eines Events

   Karten nebeneinander und keine Liste mit Trennstrichen. Untereinander mit
   grossen Zeichen davor stand rechts von jedem Punkt eine halbe Bildschirm-
   breite leer, und bei sechs Punkten wurde daraus eine Rutschbahn.

   Zwei Spalten, weil die linke Seite selbst nur zwei Drittel breit ist --
   drei Karten darin waeren Streichholzschachteln.

   Dasselbe Zeichen im tuerkisen Feld wie bei den Tueren: Was auf dieser
   Seite ein Punkt des Events ist, sieht ueberall gleich aus.
   ========================================================================== */

.programm {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .7rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.programm-eintrag {
    display: flex;
    align-items: flex-start;
    gap: .85rem;
    padding: .9rem 1rem;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
}

/* Ein Zeichen aus dem Katalog sitzt im Feld. Ein hochgeladenes Bild -- das
   Logo des DJs etwa -- bekommt keines: Es bringt seinen eigenen Hintergrund
   mit, und ein Feld darunter waere ein Rahmen um einen Rahmen. */
.programm-zeichen {
    flex: 0 0 auto;
    width: 2.5rem;
    height: 2.5rem;
    padding: .62rem;
    color: var(--trr-teal-700);
    background: var(--trr-teal-050);
    border-radius: 10px;
}

img.programm-zeichen {
    width: auto;
    height: auto;
    max-width: 3.5rem;
    max-height: 2.5rem;
    padding: 0;
    background: none;
    border-radius: 6px;
    object-fit: contain;
}

.programm-inhalt { min-width: 0; }

.programm-titel {
    margin: 0 0 .15rem;
    font-size: 1rem;
}

.programm-text {
    margin: 0;
    font-size: .9375rem;
    color: var(--trr-ink);
    line-height: 1.5;
}

@media (max-width: 35.9375em) {
    .programm { grid-template-columns: 1fr; }
    .programm-zeichen { width: 2.2rem; height: 2.2rem; padding: .55rem; }
}

/* ----------------------------------------- Das Programm in der Verwaltung */

.programm-liste {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* Jeder Punkt ein eigener Kasten: Bei vier Feldern je Punkt und sechs
   Punkten untereinander waere sonst nicht zu sehen, was zu wem gehoert. */
.programm-punkt {
    padding: 1rem 1.15rem 1.15rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.programm-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: .75rem 1.5rem;
    margin-bottom: .85rem;
}

/* Eigener Name und nicht .programm-titel: Den gibt es in der Gaesteansicht
   schon als Ueberschrift eines Punkts. Zwei Bedeutungen fuer einen Namen
   waeren eine Falle beim naechsten Anfassen. */
.programm-titel-feld { flex: 1 1 18rem; }

.programm-werben { flex: 0 0 auto; padding-bottom: .5rem; }

.programm-bild {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    margin-top: .85rem;
}

.programm-bild > div { flex: 1 1 auto; }

.programm-bild img {
    flex: 0 0 auto;
    width: auto;
    height: auto;
    max-width: 6rem;
    max-height: 4rem;
    object-fit: contain;
    border-radius: 6px;
}

/* Zwei Zahlenfelder nebeneinander: Sie gehoeren zusammen und lesen sich
   untereinander wie zwei Fragen. */
.deckel-felder {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.deckel-felder > div { flex: 0 1 12rem; }

/* ------------------------------------------------------- Die Freikarten

   Eine Zeile je Person, nach Familie gruppiert -- so, wie der Veranstalter
   denkt: "Familie Mueller, der Max hat gewonnen."

   Wer eine Karte hat, faellt auf: ohne diesen Rand muesste man die
   Auswahlfelder einzeln lesen, um zu sehen, wo etwas vergeben ist. */
.vip-familie + .vip-familie { margin-top: 1.75rem; }

.vip-familie-name {
    margin: 0 0 .6rem;
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-ink);
}

.vip-liste { list-style: none; margin: 0; padding: 0; display: flex;
             flex-direction: column; gap: .5rem; }

.vip-zeile {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .6rem .9rem;
    padding: .7rem .9rem;
    background: var(--trr-row);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
}

.vip-zeile.hat-karte { border-color: var(--trr-warn); }

.vip-wer { flex: 1 1 11rem; display: flex; flex-direction: column; line-height: 1.3; }
.vip-name { font-weight: 600; }
.vip-alter { font-size: .8125rem; color: var(--trr-ink-soft); }
.vip-wahl { flex: 0 1 12rem; }
.vip-notiz { flex: 1 1 14rem; }

/* Fehlende Geburtstage -- gleich im Fenster nachtragen.
   ------------------------------------------------------------------------
   Hier standen nur die Namen als Aufzaehlung; der Weg zum Eintragen fuehrte
   ueber "Meine Familie" und fuenf weitere Stationen. Jetzt steht je ein Feld
   daneben.

   Name und Feld nebeneinander, solange Platz ist: So liest man Zeile fuer
   Zeile, wer gemeint ist und was dort hingehoert. Auf dem Telefon
   untereinander -- ein Datumsfeld unter 10rem ist auf iOS nicht mehr
   vollstaendig zu sehen. */
.geb-liste {
    display: flex;
    flex-direction: column;
    gap: .625rem;
    margin: 1rem 0 0;
}

.geb-zeile {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
}

.geb-name {
    flex: 1 1 9rem;
    min-width: 0;
    margin: 0;
    font-weight: 600;
    color: var(--trr-ink);
}

.geb-feld { flex: 0 1 11rem; }

@media (max-width: 30em) {
    .geb-zeile { flex-direction: column; align-items: stretch; gap: .25rem; }
    .geb-feld  { flex: 1 1 auto; }
}

/* Die Freikarten -- in der Leiste unten und im Fenster. */
.tunleiste-karten {
    display: flex;
    align-items: center;
    gap: .5rem;
    max-width: 68rem;
    margin: 0 auto;
    padding: .5rem 1.25rem 0;
    font-size: .875rem;
    color: var(--trr-warn);
}

/* Der Kalenderverweis unter der Zeile.
   ------------------------------------------------------------------------
   Dieselbe Breite und derselbe Rand wie der Hinweis darueber, damit er in
   der Flucht steht und nicht wie angehaengt wirkt.

   Leise: Er ist ein Angebot neben der Handlung und nicht die Handlung. Wer
   bucht, bekommt die Datei mit der Bestaetigung -- hier steht sie fuer die,
   die sich das Datum vorher merken wollen. */
.tunleiste-kalender {
    max-width: 68rem;
    margin: 0 auto;
    padding: 0 1.25rem .5rem;
}

.tunleiste-kalender a {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .875rem;
    color: var(--trr-ink-soft);
    text-decoration: none;
}

.tunleiste-kalender a:hover {
    color: var(--trr-teal-700);
    text-decoration: underline;
}

.tunleiste-karten-icon { width: 1rem; height: 1rem; flex-shrink: 0; }

/* Der Abschnitt "Deine Events" -- ohne Kasten, mit derselben gesperrten
   Zeile als Ueberschrift wie auf der Event-Seite. */
/* Der Abschnitt bekommt Luft nach oben: Die Merkliste darueber ist ein
   Kasten, und ohne Abstand klebt die Reihe daran. */
.ev-abschnitt { margin-top: clamp(2.5rem, 5vw, 4rem); }

/* Die Ueberschrift ueber den Kacheln.
   ------------------------------------------------------------------------
   Sie war eine kleine gesperrte Zeile wie die anderen im Portal -- und ging
   damit genau dort unter, wo sie am meisten zu sagen hat: Ueber ihr endet
   ein Text, unter ihr faengt das an, worum es auf dieser Seite geht.

   Jetzt in der Serifenschrift und in der Groesse des Grusses darueber. Der
   Strich bleibt: Er ist die Marke, an der man die Abschnitte im Portal
   wiedererkennt -- er steht nur nicht mehr neben einer Zeile, die sich vor
   ihm klein macht.

   Dieselbe Beobachtung kam spaeter fuer die Eventseite: "Wer kommt", "Der
   Ablauf", "Die T-Shirts" -- sieben gesperrte Kleinzeilen, die beim
   Scrollen untergingen. Deshalb steht .strang-kopf jetzt mit im Selektor
   statt sich seine eigene Antwort zu bauen. Wer die eine Ueberschrift
   gelernt hat, kennt die andere. */
.ev-abschnitt-kopf,
.strang-kopf {
    display: flex;
    align-items: center;
    gap: .875rem;
    margin: 0 0 1.75rem;

    /* Mittig, wie die Jahreszahl darunter.
       -------------------------------------------------------------------
       Sie stand linksbuendig, waehrend .ev-jahr zentriert steht -- zwei
       Ueberschriften derselben Seite, jede an einer anderen Kante. Auf einer
       Startseite, deren Gruss und deren leerer Zustand ohnehin mittig
       stehen, war das die Ausreisserin.

       Der Strich davor wandert mit: Er ist Teil der Ueberschrift und nicht
       eine Marke am Seitenrand. */
    justify-content: center;
    text-align: center;

    font-family: "Bitter", Georgia, "Times New Roman", serif;
    font-size: clamp(1.25rem, 1.05rem + .8vw, 1.75rem);
    font-weight: 600;
    letter-spacing: -.015em;
    line-height: 1.2;
    text-transform: none;
    color: var(--trr-ink);
}

/* In der Verwaltung bleibt sie links.
   ------------------------------------------------------------------------
   Dort ist alles linksbuendig -- Seitentitel, Karten, Listen -- und eine
   mittige Ueberschrift dazwischen saehe verrutscht aus. Die Startseite ist
   die andere Sorte Seite: Dort steht auch der Gruss in der Mitte. */
.ev-abschnitt-kopf.ist-links {
    justify-content: flex-start;
    text-align: left;
}

/* Der Strich in der Marke, nicht in der Schriftfarbe: Er ist das Zeichen
   des Abschnitts, die Zeile daneben ist die Ueberschrift. */
.ev-abschnitt-kopf::before,
.strang-kopf::before {
    width: 2rem;
    background: var(--trr-teal-700);
}

/* ------------------------------------------------------- Die Jahreszahl

   Gross und mittig zwischen den Kacheln. Das laufende Jahr bekommt keine:
   Eine "2026" als Erstes auf der Seite beantwortet eine Frage, die niemand
   hat. Erst der Wechsel ist eine Auskunft. */
.ev-jahr {
    margin: clamp(3.5rem, 7vw, 6rem) 0 clamp(2rem, 4vw, 3rem);
    text-align: center;
    font-family: "Bitter", Georgia, "Times New Roman", serif;
    font-size: clamp(1.5rem, 3vw, 2.25rem);
    font-weight: 600;
    letter-spacing: -.01em;
    color: var(--trr-ink);
}

.ev-jahr:first-child { margin-top: 0; }

/* Hier standen die Regeln fuer "Was bisher war" -- die Liste der vergangenen
   Events auf einer eigenen Seite. Die Seite ist weg: Was war, steht unter
   "Tickets", zu jedem Event, bei dem man dabei war, mit dem Weg auf die
   Event-Seite. Zwei Wege zu derselben Sache waren einer zu viel. */

/* Der Untertitel: das Thema des Jahres.

   Klein unter dem Namen und nicht daneben. "9.
   Rasenmaehertraktorrallyemeisterschaft -- Paw Patrol" in einer Zeile ist
   ein Titel mit einem Gedankenstrich darin, den keine Ueberschrift
   ueberlebt. */
.ev-untertitel {
    margin: .1rem 0 .35rem;
    font-size: 1rem;
    letter-spacing: .02em;
    color: var(--trr-ink-soft);
}

/* Wer dabei war -- Gesichter mit Namen unter der Zeile.
   ------------------------------------------------------------------------
   Im Album standen dort zuerst die Familien, die Bilder beigesteuert haben.
   Gesichter tragen mehr: Ein Album ist eine Erinnerung, und eine Erinnerung
   hat Leute darin. Wer beigesteuert hat, steht jetzt unten und filtert. */

.hero-dabei { margin: clamp(1.25rem, 2.5vw, 2rem) 0 0; }

.hero-dabei-wort {
    margin: 0 0 .75rem;
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .62);
}

.hero-gesichter {
    list-style: none;
    margin: 0;
    padding: 0;

    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .4rem;
}

/* Bild und Name in einer Pille. Der Name allein waere eine Liste, das Bild
   allein ein Raetsel -- zusammen ist es eine Vorstellung. */
.hero-gesicht {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .2rem .7rem .2rem .2rem;

    background: rgba(0, 0, 0, .38);
    border: 1px solid rgba(255, 255, 255, .14);
    border-radius: 999px;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.hero-gesicht-name {
    font-size: .875rem;
    color: rgba(255, 255, 255, .92);
    white-space: nowrap;
}

/* Auf dem Telefon nur die Gesichter. Zwanzig Namen in Pillen sind dort
   fuenf Zeilen, und die schieben die Bilder aus dem Bild. */
@media (max-width: 40em) {
    .hero-gesicht { padding: .1rem; gap: 0; }
    .hero-gesicht-name { display: none; }
}

.hero-unterzeile {
    margin: .5rem 0 0;
    font-size: clamp(1rem, 1.6vw, 1.25rem);
    letter-spacing: .02em;
    color: rgba(255, 255, 255, .78);
    text-shadow: 0 1px 10px rgba(0, 0, 0, .6);
}

/* Wenn die Absage nicht mehr allein geht.
   ------------------------------------------------------------------------
   Steht dort, wo sonst der Button steht -- ruhig, ohne Warnfarbe. Es ist
   keine Fehlermeldung, sondern eine Auskunft: Es geht weiter, nur eben
   nicht per Klick. */
.absage-gesperrt {
    margin: 0;
    font-size: .875rem;
    color: var(--trr-ink-soft);
}

/* Die drei Wege der Erinnerung nebeneinander. Umbrechen dürfen sie -- auf
   dem Telefon passen drei Buttons nicht in eine Reihe. */
.erinnern-wege {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: 1rem;
}

.erinnern-text { font-size: .9375rem; }

/* Die Zahlen im Bearbeiten-Fenster: Bezeichnung links, Betrag rechts, damit
   man sie untereinander vergleichen kann. */
.opt-zahlen { display: grid; gap: .25rem; margin: 0 0 1.25rem; }

.opt-zahlen > div {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
}

.opt-zahlen dt { font-weight: 400; color: var(--trr-ink-soft); }
.opt-zahlen dd { margin: 0; font-variant-numeric: tabular-nums; }

.opt-block {
    padding-top: 1rem;
    margin-top: 1rem;
    border-top: 1px solid var(--trr-line);
}

/* Der Storno-Abschnitt trägt keine Warnfarbe, aber etwas Abstand nach oben:
   Er ist das Letzte im Fenster, und was zerstört, soll nicht neben dem
   stehen, was nur umbucht. */
.opt-block.ist-ernst { margin-top: 1.5rem; }

/* Der Stift neben dem Zustands-Abzeichen.
   ------------------------------------------------------------------------
   Abzeichen und Stift bilden ein Ding: Was man liest, klickt man an, um es
   zu ändern. Der Stift bleibt trotzdem sichtbar ruhig -- er steht auf
   achtzehn Seiten, und ein zweiter Button neben der Navigation soll dort
   nicht mitreden. */
.event-nav-zustand {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    margin-left: auto;
    align-self: center;
}

.event-nav-stift {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    border: 0;
    border-radius: var(--trr-radius-sm);
    background: transparent;
    color: var(--trr-ink-soft);
}

.event-nav-stift:hover,
.event-nav-stift:focus-visible {
    color: var(--trr-ink);
    background: var(--trr-row);
}

.event-nav-stift .icon { width: .9rem; height: .9rem; }

@media (max-width: 47.9375em) {
    /* In einer scrollenden Reihe waere "ganz rechts" irgendwo hinter dem
       Rand. Dann lieber gleich hinter den Gruppen. */
    .event-nav-zustand { margin-left: .5rem; }
}

/* Die vier Zustände zur Wahl.
   ------------------------------------------------------------------------
   Felder zum Antippen und keine Auswahlliste: Der erklärende Satz gehört
   neben die Wahl, und in einer Liste sieht man immer nur eine Zeile. Wer
   "Termin steht" zum ersten Mal liest, soll nicht raten müssen, was das für
   die Gäste bedeutet. */
.zustand-wahl {
    display: grid;
    gap: .5rem;
    border: 0;
    padding: 0;
    margin: 0;
}

.zustand-feld {
    display: flex;
    align-items: flex-start;
    gap: .625rem;
    padding: .625rem .75rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    cursor: pointer;
}

.zustand-feld:hover { border-color: var(--trr-ink-soft); }

/* Das Gewählte trägt den Markenton -- nicht als Fläche, sondern als Kante.
   Eine eingefärbte Fläche neben drei dunklen sähe aus wie eine Warnung.

   Nur :has(), keine Klasse vom Server -- siehe .zeichen-feld. Hier hing
   derselbe Fehler: Wer im Fahrer-Fenster von "Fährt" auf "Sozius" klickte,
   sah beide umrandet. */
.zustand-feld:has(input:checked) {
    border-color: var(--trr-teal-700);
    box-shadow: inset 0 0 0 1px var(--trr-teal-700);
}

/* Ein Feld, das gerade nicht zu haben ist -- weil eine Bedingung fehlt.
   Gedaempft und nicht versteckt: Wer es vorhat, soll sehen, dass es die
   Moeglichkeit gibt und woran es gerade liegt. Der Satz darunter sagt das
   dann in Worten.

   Die Regel fehlte, obwohl die Klasse schon im Fahrer-Fenster steht: Dort
   sperrte der Browser das Kaestchen, und der Rest der Zeile sah aus wie
   jeder andere -- man klickte hinein und nichts geschah. */
.zustand-feld.ist-gesperrt {
    opacity: .5;
    cursor: default;
}

.zustand-feld.ist-gesperrt:hover { border-color: var(--trr-line); }

.zustand-feld .form-check-input { margin-top: .2rem; flex: 0 0 auto; }
.zustand-text { display: flex; flex-direction: column; line-height: 1.35; }
.zustand-name { font-weight: 600; }
.zustand-satz { font-size: .875rem; color: var(--trr-ink); }

/* Die Einladung beim Veröffentlichen.
   ------------------------------------------------------------------------
   Abgesetzt und nicht nur ein weiteres Häkchen: Die vier Zustände darüber
   ändern eine Zahl in der Datenbank, dieses Feld verschickt Post an dreißig
   Leute. Was man nicht zurückholen kann, soll auch nicht aussehen wie der
   Countdown-Schalter daneben. */
.zustand-einladung {
    padding: .75rem;

    /* Die Kante gedämpft und nicht im vollen Markenton: Den trägt oben das
       gewählte Feld, und zwei gleich kräftige Rahmen übereinander streiten
       darum, was hier gerade angeklickt ist. */
    border: 1px solid rgba(2, 176, 167, .45);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.zustand-einladung .form-check-label { font-weight: 600; }
.zustand-einladung .form-text { margin-top: .375rem; }

/* Die Anzahl direkt neben der Zusage: "Alle einladen" ist eine andere Frage
   als "14 Nachrichten verschicken", und nur die zweite kann man ehrlich
   beantworten. */
.zustand-anzahl {
    display: inline-block;
    margin-left: .375rem;
    padding: .05rem .4rem;
    border-radius: 999px;
    background: var(--trr-teal-100);
    color: var(--trr-teal-900);
    font-size: .8125rem;
    font-weight: 600;
}

/* Der Stift in der Fahrerzeile -- dieselbe Machart wie in der
   Anmeldungsliste. Zwei Listen, die dasselbe tun, sollen auch gleich
   aussehen. */
.driver-tun { display: flex; justify-content: flex-end; }

.driver-stift {
    flex: 0 0 auto;
    width: 2.25rem;
    padding-inline: 0;
    text-align: center;
}

/* Angesprungene Zeilen bleiben unter der festen Kopfleiste nicht haengen --
   wie in den beiden Zahlungslisten. */
.driver-row[id] {
    scroll-margin-top: calc(var(--nav-hoehe) + 1rem);
}

@media (max-width: 767px) {
    /* Gestapelt braucht der Stift keine eigene Spalte mehr; er rutscht
       neben die Rolle. */
    .driver-tun { justify-content: flex-start; }
}

/* Eine Ausnahme, die neben einer Aufsicht steht, gilt gerade nicht.
   Gedaempft statt verschwiegen: Sie ist gespeichert und greift wieder,
   sobald die Aufsicht wegfaellt -- das soll man sehen koennen. */
.driver-flag.ist-ruht {
    color: var(--trr-ink-soft);
    font-weight: 600;
}

/* Der Supervisor bekommt dieselbe Pille wie alle anderen -- er stand vorher
   als kleine Versalienzeile daneben und sah dadurch aus, als gehoere er
   nicht in dieselbe Reihe. Er ist aber eine Rolle unter vieren.
   ------------------------------------------------------------------------
   Derselbe Aufbau wie die tuerkise Fahrerpille: Rand, Grund und Schrift.
   Zuerst standen hier nur Rand und Schrift, und dann sah sie neben der
   gefuellten tuerkisen blass aus -- die Farbe war da, aber sie trug nicht. */
.driver-badge.ist-aufsicht {
    border-color: var(--trr-amber-600);
    background: var(--trr-amber-100);
    color: var(--trr-warn);
}

/* Wer nicht faehrt, es aber duerfte: der Kandidat fuer den Renntag. Ruhig
   gehalten -- es ist eine Moeglichkeit und keine Aufgabe. */
.driver-flag.ist-moeglich {
    color: var(--trr-ink-soft);
    font-weight: 600;
}

/* Der Traktor-Schalter oben auf der Spielerauswahl: Schalter links, Button
   rechts. Er aendert die Woerter der ganzen Seite, deshalb steht er darueber
   und nicht irgendwo dazwischen. */
.fahrzeug-schalter {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

/* Der Kreispunkt vor jedem Navigationspunkt.
   ------------------------------------------------------------------------
   Gefuellt und tuerkis heisst zugeschaltet, hohl und grau heisst aus. Er
   ersetzt das "aus"-Abzeichen, das hinter dem Wort stand: Das sagte
   dasselbe, brauchte aber Platz und liess die Punkte unterschiedlich breit
   werden -- eine Reihe, in der jeder Eintrag anders lang ist, liest sich
   unruhig.

   Vor dem Wort und nicht dahinter: Beim Ueberfliegen einer Reihe schaut man
   zuerst auf den Anfang. */
.event-nav-punkt {
    flex: 0 0 auto;
    width: .5rem;
    height: .5rem;
    margin-right: .1rem;
    border: 1px solid var(--trr-ink-soft);
    border-radius: 50%;
    background: transparent;
}

.event-nav-punkt.ist-an {
    border-color: var(--trr-teal-700);
    background: var(--trr-teal-700);
}

/* In der Gruppenreihe stehen Punkt und Zeichen nebeneinander -- der Eintrag
   ist dort ohnehin schon eine Reihe aus mehreren Teilen. */
.event-nav-item {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
}

/* Der Schalter oben auf einer Baustein-Seite. Punkt, Text, Button -- dieselbe
   Machart wie in der Leiste, damit man den Zusammenhang sieht. */
.modul-schalter-zeile {
    display: flex;
    align-items: center;
    gap: .875rem;
}

.modul-schalter-text { flex: 1 1 auto; }

.modul-schalter-punkt {
    flex: 0 0 auto;
    width: .625rem;
    height: .625rem;
    border: 1px solid var(--trr-ink-soft);
    border-radius: 50%;
    background: transparent;
}

.modul-schalter-punkt.ist-an {
    border-color: var(--trr-teal-700);
    background: var(--trr-teal-700);
}

/* Ist der Baustein aus, steht die Karte gedaempft da -- sichtbar, aber
   erkennbar ohne Wirkung. */
.modul-schalter.ist-aus { border-style: dashed; }

/* Die beiden Faelle auf der Rallye-Seite nebeneinander: Man vergleicht sie,
   statt sich den zweiten vorzustellen. Der geltende traegt die Kante im
   Markenton -- so wie die gewaehlte Zustandskachel.

   Sie sind zugleich die Wahl. Darueber lag ein Kippschalter "Mit Traktor",
   und die Kaesten zeigten nur an, was er anrichtet: zwei Darstellungen
   desselben Zustands, von denen eine ueberfluessig war. Der Schalter ist
   weg. */
.rallye-wahl {
    border: 0;
    padding: 0;
    margin: 0;
}

.rallye-fall {
    display: block;
    height: 100%;
    padding: .875rem 1rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    cursor: pointer;
}

/* Der Button selbst ist unsichtbar -- angefasst wird der Kasten. Nicht
   display:none: Ein so verstecktes Feld ist fuer die Tastatur nicht mehr
   erreichbar und faellt aus der Reihenfolge. */
.rallye-fall input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.rallye-fall:hover { border-color: var(--trr-teal-600); }

/* Nur :has(), keine Klasse vom Server -- dieselbe Regel wie bei der
   Glaswahl. Eine zweite Quelle fuer denselben Zustand bliebe beim Umklicken
   stehen, und dann saehen beide Faelle gewaehlt aus. */
.rallye-fall:has(input:checked) {
    border-color: var(--trr-teal-700);
    box-shadow: inset 0 0 0 1px var(--trr-teal-700);
}

.rallye-fall:has(input:focus-visible) {
    outline: 2px solid var(--trr-teal-700);
    outline-offset: 2px;
}

.rallye-fall-kopf { display: block; font-weight: 600; margin-bottom: .5rem; }

/* Spannen statt einer Liste: In einem label darf keine ul stehen -- sein
   Inhalt ist Text. Die Punkte davor macht deshalb das Stylesheet. */
.rallye-fall-liste {
    display: flex;
    flex-direction: column;
    gap: .125rem;
    font-size: .875rem;
    color: var(--trr-ink);
}

.rallye-fall-punkt {
    display: block;
    position: relative;
    padding-left: 1.1rem;
}

.rallye-fall-punkt::before {
    content: "•";
    position: absolute;
    left: .3rem;
}

.rallye-teile { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }

.rallye-teil {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .625rem .75rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.rallye-teil-text { flex: 1 1 auto; }
.rallye-teil-zustand { font-size: .8125rem; color: var(--trr-ink-soft); }

/* ==========================================================================
   POSTAUSGANG
   ==========================================================================

   Was das Portal verschickt hat. Dieselbe Zeile wie bei den Cocktails und
   den Spielen -- nur ohne Schalter, denn verschickte Post laesst sich nicht
   zuruecknehmen.
   ========================================================================== */

.post-zeile {
    /* Zustand, Betreff mit Empfaenger, Zeitpunkt, Aufklapper. */
    grid-template-columns: 8.5rem 1fr auto auto;
    align-items: start;
}

/* Nicht verschickt heisst hier nicht "kaputt": Solange der Versand aus ist,
   ist es der Normalfall. Also nur leicht gedaempft -- die Zeile soll lesbar
   bleiben, sie ist ja der eigentliche Inhalt der Seite. */
.post-zeile.ist-aus { opacity: .75; border-style: solid; }

.post-zeit {
    font-size: .8125rem;
    color: var(--trr-ink-soft);
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    line-height: 1.35;
}

.post-uhrzeit { opacity: .8; }

/* Der Aufklapper mit dem Nachrichtentext.

   inline-block, damit der Button klein bleibt: Aufgeklappt spannt sich das
   details ueber die ganze Zeile, und ein Block-summary waere mitgewachsen --
   aus dem kleinen Button wurde ein Feld ueber die volle Breite, das aussah, als
   koenne man hineinschreiben. */
.post-text > summary {
    display: inline-block;
    cursor: pointer;
    font-size: .875rem;
    color: var(--trr-ink-soft);
    padding: .25rem .625rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    white-space: nowrap;
    list-style: none;
}

.post-text > summary::-webkit-details-marker { display: none; }
.post-text > summary:hover { border-color: var(--trr-teal-600); color: var(--trr-ink); }
.post-text[open] > summary { border-color: var(--trr-teal-700); color: var(--trr-ink); }

/* Aufgeklappt laeuft der Text ueber die ganze Zeile und nicht in seiner
   schmalen Spalte -- eine Mail in vier Zentimetern Breite liest niemand. */
.post-text[open] {
    grid-column: 1 / -1;
    margin-top: .75rem;
}

.post-text-inhalt {
    margin: .625rem 0 0;
    padding: .875rem 1rem;
    background: var(--trr-paper);
    border-radius: var(--trr-radius-sm);
    font-size: .875rem;
    line-height: 1.55;

    /* Umbrechen und nicht seitlich scrollen: Der Text ist auf 76 Zeichen
       gesetzt, aber eine lange Adresse sprengt auch das. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    color: var(--trr-ink);
}

/* Auf schmalen Schirmen untereinander: Vier Spalten gibt es dort nicht. */
@media (max-width: 47.9375em) {
    .post-zeile { grid-template-columns: 1fr auto; }
    .post-zeile .pflege-text { grid-column: 1 / -1; }
}

/* ==========================================================================
   Die Filterreihe des Protokolls
   ==========================================================================
   Nebeneinander, solange Platz ist, und sonst untereinander. Ein Raster mit
   fester Spaltenzahl waere hier falsch: Die Felder sind verschieden breit --
   ein Datum braucht wenig, ein Pfad viel --, und in gleichen Spalten stuende
   neben dem Datum die Haelfte der Zeile leer.

   Deshalb Flex mit Umbruch und einer Mindestbreite je Feld. Auf dem Telefon
   steht damit jedes fuer sich, ohne dass es eine eigene Regel dafuer
   braucht. */
.protokoll-filter { margin-bottom: 1.25rem; }

.filter-reihe {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .75rem 1rem;
}

.filter-feld {
    flex: 1 1 9rem;
    min-width: 0;
}

/* Die Seite bekommt mehr: Dort steht ein Pfad und kein Wort. */
.filter-feld.ist-breit { flex: 2 1 14rem; }

/* Der Schalter traegt seine Beschriftung daneben und nicht darueber. In
   einer Reihe, die an der Unterkante ausgerichtet ist, saesse er damit ein
   paar Punkte zu tief -- das Polster hebt ihn auf die Mitte der Felder
   neben ihm. Mitwachsen soll er nicht: Er ist so breit wie sein Wort. */
.filter-feld.ist-schalter {
    flex: 0 0 auto;
    padding-bottom: .5rem;
}

/* Die Knoepfe wachsen nicht mit -- sie sind so breit wie ihre Beschriftung
   und stehen am Ende der Reihe. */
.filter-feld.ist-knopf {
    flex: 0 0 auto;
    display: flex;
    gap: .5rem;
}

@media (max-width: 575.98px) {
    /* Untereinander ist jedes Feld eine Zeile, und die Knoepfe darunter
       nehmen die volle Breite: Auf dem Telefon ist das die Form, die man
       kennt. */
    .filter-feld { flex: 1 1 100%; }
    .filter-feld.ist-knopf .btn { flex: 1 1 0; }
}

/* ==========================================================================
   Die Blaetterleiste
   ==========================================================================
   Unter der Tabelle: Wer weiterblaettern will, ist unten angekommen.

   Links steht, wo man ist -- "Zeile 51-100 von 3.482" --, rechts die Zahlen.
   Das ist Absicht: Die Auskunft liest man beilaeufig, die Knoepfe sucht man
   gezielt, und beides am selben Ort waere ein Gedraenge.

   Keine Rahmen um die Leiste. Sie gehoert zur Tabelle darueber und ist kein
   eigener Kasten -- eine zweite Umrandung unter einer umrandeten Tabelle
   sieht aus wie ein Fehler im Aufbau. */
.blaetterleiste {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .75rem 1rem;
    margin-top: .75rem;
}

.blaetter-stand {
    margin: 0;
    color: var(--trr-ink-soft);
    font-size: .875rem;
}

.blaetter-seiten {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem;
}

/* Zahl und Schritt teilen sich die Form: gleiche Hoehe, gleiche Rundung.
   Unterschiedlich ist nur die Breite -- eine Zahl ist quadratisch, "Zurueck"
   ist ein Wort. */
.blaetter-zahl,
.blaetter-schritt {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.25rem;
    height: 2.25rem;
    padding: 0 .625rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-paper);
    color: var(--trr-ink);
    font-size: .9375rem;
    line-height: 1;
    text-decoration: none;
    transition: background-color .15s ease, border-color .15s ease;
}

.blaetter-zahl { font-variant-numeric: tabular-nums; }

a.blaetter-zahl:hover,
a.blaetter-schritt:hover,
a.blaetter-zahl:focus-visible,
a.blaetter-schritt:focus-visible {
    background: var(--trr-row);
    border-color: var(--trr-teal-700);
    color: var(--trr-ink);
}

/* Wo man ist, ist kein Verweis -- also sieht es auch nicht danach aus,
   sondern gefuellt und ohne Zeigefinger. */
.blaetter-zahl.ist-hier {
    background: var(--trr-teal-700);
    border-color: var(--trr-teal-700);
    color: var(--trr-on-primary);
    font-weight: 600;
    cursor: default;
}

/* Am Anfang und am Ende bleibt der Schritt stehen und wird stumpf. Er
   verschwindet nicht: Ein Knopf, der am Rand wegfaellt, laesst die Zahlen
   daneben springen. */
.blaetter-schritt.ist-stumpf {
    opacity: .4;
    cursor: default;
}

.blaetter-luecke {
    padding: 0 .25rem;
    color: var(--trr-ink-soft);
    user-select: none;
}

@media (max-width: 575.98px) {
    /* Auf dem Telefon untereinander: Nebeneinander bliebe fuer die Zahlen
       eine Handbreit, und sie braechen mitten in der Reihe um. */
    .blaetterleiste { justify-content: center; }
    .blaetter-stand { flex: 1 1 100%; text-align: center; }
}

/* Die Zahl neben einer Gruppenueberschrift.
   --------------------------------------------------------------------------
   Klein, rund und ruhig: Sie gehoert zur Ueberschrift und soll sie nicht
   ueberholen. "Event-Manager 2" beantwortet beim Ueberfliegen eine Frage, die
   man sonst durch Abzaehlen beantwortet. */
.gruppe-zahl {
    display: inline-block;
    margin-left: .5rem;
    padding: .05rem .5rem;
    border-radius: 999px;
    background: var(--trr-row);
    color: var(--trr-ink-soft);
    font-size: .875rem;
    font-weight: 600;
    vertical-align: middle;
}

/* ==========================================================================
   Die Spieleerfassung — draußen auf der Wiese

   Der einzige Teil des Portals, der im Stehen bedient wird: Sonne auf dem
   Schirm, Handschuhe an den Fingern, hinter dem Betreuer wartet der Nächste.
   Das erklärt jede Entscheidung hier unten.

   Sie steht bewusst am Ende und teilt sich fast nichts mit dem Rest: Ein
   .btn, der auf dem Schreibtisch richtig ist, ist hier zu klein, und eine
   Karte mit 1rem Innenabstand verschenkt die halbe Bildschirmbreite.
   ========================================================================== */

/* Der Reset, den sonst Bootstrap mitbringt.
   ----------------------------------------------------------------------
   Die Erfassung ist das einzige Layout ohne Bootstrap -- sie braucht weder
   Fenster noch Klapplisten, und 200 KB CSS fuer nichts waeren auf einer
   Wiese mit zwei Balken Empfang teuer. Mitgenommen hatte ich dabei aber den
   box-sizing-Reset, den app.css nirgends selbst setzt.

   Die Folge stand auf Marcels Telefon: `width: 100%` plus Innenabstand plus
   Rahmen ergibt mehr als hundert Prozent, und das Codefeld stand ueber
   seinen Kasten hinaus. Betroffen war jedes Element mit voller Breite --
   Felder wie Knoepfe.

   Bewusst nur hier und nicht global: Wo Bootstrap laedt, gilt dieselbe Regel
   ohnehin schon. */
.page-wiese,
.page-wiese *,
.page-wiese *::before,
.page-wiese *::after { box-sizing: border-box; }

.page-wiese {
    background: var(--trr-cream);
    color: var(--trr-ink);
    margin: 0;
    /* Der Daumen kommt von unten. Ein Rand nach unten hin sorgt dafür, dass
       der letzte Button nicht am Bildschirmrand klebt -- dort trifft man ihn
       auf einem Telefon in der Hand am schlechtesten. */
    padding: 0 0 3rem;
}

.wiese-shell {
    max-width: 34rem;
    margin: 0 auto;
    padding: 1.25rem 1rem 0;
}

.wiese { display: grid; gap: 1rem; }

/* ------------------------------------------------------------------ Der Kopf */

.wiese-kopf { display: grid; gap: .125rem; }

/* Wo bin ich? Die Frage stellt sich nach acht Stunden Wiese durchaus. */
.wiese-ort {
    margin: 0;
    font-size: .9375rem;
    color: var(--trr-ink-soft);
    text-transform: uppercase;
    letter-spacing: .06em;
}

.wiese-titel {
    margin: 0;
    font-size: 1.75rem;
    line-height: 1.15;
    display: flex;
    align-items: center;
    gap: .625rem;
    /* „Rasenmähertraktorrallyemeisterschaft" passt in keine Zeile. */
    overflow-wrap: break-word;
}

/* Die Startnummer, wie sie auf dem Etikett steht. Sie ist das, was der
   Betreuer zuerst sieht, wenn er den Fahrer öffnet -- und sein Abgleich mit
   der Nummer auf der Brust. */
.wiese-nummer {
    flex: 0 0 auto;
    min-width: 2.5rem;
    padding: .125rem .5rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-teal-700);
    color: var(--trr-on-primary);
    font-variant-numeric: tabular-nums;
    text-align: center;
}

/* ---------------------------------------------------------------- Die Karten */

.wiese-karte {
    background: var(--trr-paper);
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    padding: 1.125rem 1rem;
    display: grid;
    gap: .75rem;
}

.wiese-gross { margin: 0; font-size: 1.375rem; font-weight: 600; line-height: 1.2; }
.wiese-satz  { margin: 0; }
.wiese-klein { margin: 0; font-size: .875rem; color: var(--trr-ink-soft); }

.wiese-spiele { margin: 0; padding-left: 1.25rem; display: grid; gap: .25rem; }

/* ------------------------------------------------------------- Die Meldungen */

.wiese-fehler,
.wiese-hinweis {
    border-radius: var(--trr-radius-sm);
    padding: .875rem 1rem;
    border: 1px solid;
}

.wiese-fehler {
    border-color: var(--trr-hot);
    background: color-mix(in srgb, var(--trr-hot) 14%, var(--trr-paper));
}

.wiese-hinweis {
    border-color: var(--trr-warn);
    background: color-mix(in srgb, var(--trr-warn) 12%, var(--trr-paper));
}

/* ---------------------------------------------------------------- Die Felder

   Alles hier ist größer als im Portal. 3.25rem Höhe klingt üppig und ist es
   nicht: Das ist ungefähr die Fläche, die ein Daumen sicher trifft, ohne
   dass man hinsieht -- und hinsehen kann man in der Sonne schlecht. */

.wiese-label {
    display: block;
    font-weight: 600;
    margin-bottom: .375rem;
}

.wiese-code,
.wiese-zahl {
    width: 100%;
    min-height: 3.25rem;
    padding: .5rem .875rem;
    border: 2px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    color: var(--trr-ink);
    font-size: 1.5rem;
    font-variant-numeric: tabular-nums;
}

/* Der Stationscode und die Kennung werden Zeichen für Zeichen abgeglichen --
   dafür ist eine Schrift mit gleichen Breiten die richtige. */
.wiese-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    letter-spacing: .08em;
    text-align: center;
    text-transform: uppercase;
}

.wiese-code:focus,
.wiese-zahl:focus {
    outline: 0;
    border-color: var(--trr-teal-700);
}

/*
 * Die Zeitraeder auf der Wiese.
 * ---------------------------------------------------------------------------
 * Derselbe Schnitt wie das Zahlenfeld daneben: gross, ruhig, mit klammen
 * Fingern zu treffen. Ein Betreuer bedient das im Stehen, mit nassen Haenden
 * und der Sonne auf dem Display -- hier ist Groesse keine Geschmacksfrage.
 */
.wiese-rad {
    min-height: 3.25rem;
    padding: .5rem .75rem;
    border: 2px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    color: var(--trr-ink);
    font-size: 1.5rem;
    font-variant-numeric: tabular-nums;
}

.wiese-rad:focus { outline: 0; border-color: var(--trr-teal-700); }

/* Auf der Wiese teilen sich die beiden Raeder die Breite -- so bleiben sie
   auch auf einem schmalen Telefon gross genug. */
.wiese-eingabe .zeitfelder { width: 100%; align-items: flex-start; gap: .75rem; }
.wiese-eingabe .zeitfeld { flex: 1 1 0; min-width: 0; }
.wiese-eingabe .wiese-rad { width: 100%; min-width: 0; }
.wiese-eingabe .zeitfeld-name { font-size: 1rem; }

/* Ein Platzhalter ist ein Hinweis und kein Inhalt.
   ----------------------------------------------------------------------
   In einem grossen, mittig gesetzten Feld sah „12,40" aus wie eine schon
   eingetragene Zeit -- und wer das glaubt, loescht erst einmal etwas, das
   nie da war. Deutlich gedaempft und ohne die gleichen Zeichenbreiten:
   Beides zusammen macht den Unterschied zwischen „Beispiel" und „Wert". */
.wiese-code::placeholder,
.wiese-zahl::placeholder {
    color: var(--trr-ink-soft);
    opacity: .45;
    font-family: inherit;
    letter-spacing: normal;
}

/* Luft zwischen Feld und Knopf. Sie klebten aneinander, und auf einem
   Telefon trifft der Daumen dann beim Tippen ins Feld schon den Knopf. */
.wiese-code { margin-bottom: .75rem; }

/* Der Name des Betreuers ist keine Kennung: normale Schrift, linksbuendig,
   ohne Sperrung. In der Codeschrift saehe „Anna" aus wie ein Schluessel. */
.wiese-name {
    font-family: inherit;
    letter-spacing: normal;
    text-align: left;
    text-transform: none;
    font-size: 1.25rem;
}

.wiese-feld { display: grid; gap: .375rem; }
.wiese-feld + .wiese-feld { margin-top: .5rem; }
.wiese-feld-name { font-weight: 600; font-size: 1.125rem; }

/* Zahl und Einheit nebeneinander: „12,40 s" liest sich als eine Angabe, und
   die Einheit gehört deshalb an das Feld und nicht darüber. */
.wiese-eingabe { display: flex; align-items: stretch; gap: .5rem; }
.wiese-eingabe .wiese-zahl { flex: 1 1 auto; min-width: 0; }

.wiese-einheit {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    min-width: 3rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    color: var(--trr-ink-soft);
    font-size: 1.125rem;
}

/* --------------------------------------------------------------- Die Knöpfe */

.wiese-button {
    display: block;
    width: 100%;
    min-height: 3.5rem;
    padding: .75rem 1rem;
    border: 0;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-teal-700);
    color: var(--trr-on-primary);
    font-size: 1.1875rem;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
    /* Als <a> gesetzt braucht er die Zeilenhöhe, damit die Schrift mittig
       sitzt -- ein Knopf und ein Link sollen gleich aussehen. */
    line-height: 2rem;
}

.wiese-button + .wiese-button { margin-top: .5rem; }
.wiese-button:hover { background: var(--trr-teal-600); color: var(--trr-on-primary); }

/* Der Joker bekommt die Zweitfarbe. Sie sagt „Achtung, das ist die
   Ausnahme" -- und genau das ist er: ein Knopf, den man einmal am Tag
   drückt und danach nie wieder. */
.wiese-button-joker { background: var(--trr-amber-500); color: #14161a; }
.wiese-button-joker:hover { background: var(--trr-amber-600); color: #14161a; }

/* „Kein Joker" und „noch mal eingeben": Antworten, keine Abbrüche -- deshalb
   ruhig und trotzdem groß genug zum Treffen. */
.wiese-weiter,
.wiese-weg {
    display: block;
    width: 100%;
    min-height: 3rem;
    padding: .625rem 1rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: transparent;
    color: var(--trr-ink-soft);
    font-size: 1rem;
    text-align: center;
    text-decoration: none;
}

.wiese-weiter { margin-top: .75rem; }
.wiese-fuss { margin: .5rem 0 0; }

/* ------------------------------------------------------- Joker, Prüfen, Fertig */

.wiese-joker { border-color: var(--trr-amber-500); }

.wiese-pruefzeile {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: .5rem .75rem;
    padding: .625rem 0;
    border-bottom: 1px solid var(--trr-line);
}

.wiese-pruefzeile:last-of-type { border-bottom: 0; }
.wiese-pruefname { font-size: 1.0625rem; overflow-wrap: break-word; }

/* Die Zahl ist der Grund, warum diese Seite existiert: Hier fällt ein
   Zahlendreher auf, solange der Fahrer noch in Rufweite steht. */
.wiese-pruefwert {
    font-size: 1.5rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.wiese-schondrin {
    border-top: 1px solid var(--trr-line);
    padding-top: .75rem;
    display: grid;
    gap: .25rem;
}

.wiese-schondrin-zeile {
    margin: 0;
    display: flex;
    justify-content: space-between;
    gap: .75rem;
    color: var(--trr-ink-soft);
}

.wiese-fertig { text-align: center; justify-items: center; }

.wiese-haken {
    margin: 0;
    width: 3.5rem;
    height: 3.5rem;
    display: grid;
    place-items: center;
    border-radius: 999px;
    background: var(--trr-ok);
    color: #14161a;
}

.wiese-haken svg { width: 1.75rem; height: 1.75rem; }
.wiese-fertig .wiese-pruefzeile { width: 100%; text-align: left; }
.wiese-ruht { text-align: center; }

/* ------------------------------------------------------------- Der Sucher

   Er sitzt über dem Eingabefeld und ersetzt es nicht: Wer keine Kamera hat
   oder keine Erlaubnis gibt, tippt weiter. Deshalb nimmt der Sucher im
   Ruhezustand auch keinen Platz weg -- das Bild erscheint erst, wenn die
   Kamera läuft. */

.scanner { display: grid; gap: .5rem; }

.scanner-sucher {
    display: none;
    position: relative;
    /* Quadratisch, nicht im Videoformat: Ein QR-Code ist quadratisch, und
       ein breites Bild führt nur dazu, dass man ihn zu weit weg hält. */
    aspect-ratio: 1;
    border-radius: var(--trr-radius-sm);
    overflow: hidden;
    background: #000;
}

.scanner.ist-an .scanner-sucher { display: block; }

.scanner-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Nicht spiegeln: Es ist die rückwärtige Kamera, und ein gespiegeltes
       Bild lässt einen in die falsche Richtung nachjustieren. */
}

/* Der Rahmen sagt, wohin der Code gehalten werden soll. Ohne ihn hält man ihn
   zu nah -- und dann liest ihn keine Kamera, weil die Ecken fehlen. */
.scanner-rahmen {
    position: absolute;
    inset: 15%;
    border: 3px solid var(--trr-teal-700);
    border-radius: var(--trr-radius-sm);
    box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .45);
}

.scanner-meldung {
    margin: 0;
    font-size: .9375rem;
    color: var(--trr-ink-soft);
    min-height: 1.25rem;
}

.scanner-meldung.ist-fehler { color: var(--trr-warn); }
.scanner-meldung.ist-gut    { color: var(--trr-ok); }

/* Läuft die Kamera, ist der Knopf ein Abbruch -- und soll dann nicht mehr
   nach der Haupthandlung aussehen. */
.scanner.ist-an .scanner-knopf {
    background: transparent;
    color: var(--trr-ink-soft);
    box-shadow: inset 0 0 0 1px var(--trr-line);
}

/* =========================================================== Die Renntafel

   Der Monitor im Zelt. Aus drei Metern lesbar, den ganzen Tag an, und
   niemand steht davor und klickt -- dieselbe Aufgabe wie bei der
   Cocktailkarte, deshalb dieselbe Grundhaltung: groß, ruhig, ohne
   Bedienelemente. */

/* Genau eine Bildschirmhöhe, nicht mindestens eine. Vorher wuchs die Bühne
   bei vielen Fahrern nach unten heraus, und weil die Seite oben abschneidet,
   verschwanden die hinteren Plätze wortlos -- schlimmer als kleine Schrift,
   denn man sieht nicht einmal, dass etwas fehlt. */
.tafel-buehne {
    /*
     * Auf der Wand ist alles weiss.
     * ------------------------------------------------------------------
     * Die Farben des Portals sind fuer einen Bildschirm gemacht, der einen
     * halben Meter entfernt steht: #d9dee6 fuer den Text, #a8b1bd fuer das,
     * was zuruecktreten soll. Am Schreibtisch ist das eine ruhige
     * Abstufung. Drei Meter weiter, auf einem Fernseher, ueber einem
     * bewegten Film und mit dem Licht einer Scheune darauf, ist es schlicht
     * grau -- und grau liest sich nicht. Marcel: "Sie sind grau und daher
     * nicht so gut zu lesen."
     *
     * Deshalb werden hier die Farbtoken selbst umgesetzt und nicht ein
     * Dutzend Regeln einzeln umgefaerbt. Das trifft alles, was auf dieser
     * Wand steht -- Kopf, Tabelle, Namen, Zahlen, das Podest der
     * Siegerehrung -- und es trifft auch das, was morgen dazukommt.
     *
     * Die Abstufung bleibt, sie wird nur nach oben verschoben: Was
     * zuruecktreten soll, ist weiss mit weniger Deckkraft und nicht ein
     * anderes Grau. Damit haelt der Abstand auch dann, wenn hinter der
     * Schrift gerade eine helle Stelle des Films durchlaeuft.
     */
    --trr-ink: #fff;
    --trr-ink-soft: rgba(255, 255, 255, .85);

    /* Eigens gesetzt: --trr-ink-quiet zeigt zwar auf --trr-ink-soft, aber
       diese Zuweisung ist oben an der Wurzel schon aufgeloest worden. Ohne
       diese Zeile bliebe das leiseste Grau das einzige, das grau bleibt. */
    --trr-ink-quiet: rgba(255, 255, 255, .72);

    height: 100vh;
    padding: 2rem clamp(1rem, 3vw, 3rem);
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: 1.5rem;
    overflow: hidden;
    background: var(--trr-cream);
    color: var(--trr-ink);
}

/*
 * Und die Trennlinien der Tabelle mit.
 *
 * Sie sind aus demselben Grund zu dunkel: #2e343d auf einem halb
 * durchsichtigen Grund ueber einem Film ist aus drei Metern keine Linie
 * mehr. Eine Tabelle mit acht Spalten liest man aber ueber die Zeile, und
 * dafuer muss die Zeile sichtbar sein. Nicht heller als noetig -- sie soll
 * fuehren und nicht auffallen.
 */
.tafel-buehne .tafel-tabelle th,
.tafel-buehne .tafel-tabelle td {
    border-bottom-color: rgba(255, 255, 255, .18);
}

/* Das Zeichen fuer "hier war noch niemand". Es stand auf der Linienfarbe und
   war damit auf der Wand gar nicht da -- eine leere Zelle sieht aber aus wie
   ein Fehler, waehrend ein blasser Punkt sagt: hier kommt noch etwas. */
.tafel-buehne .tafel-offen { color: rgba(255, 255, 255, .3); }

/*
 * Auf der Wand tritt kein Name zurueck.
 * ----------------------------------------------------------------------
 * Wer noch nicht am Tisch war, stand mit halber Deckkraft da -- die ganze
 * Zeile, Name inbegriffen. Der Gedanke war richtig: Gesucht wird der, der
 * noch unterwegs ist. Zwei Dinge stimmen daran trotzdem nicht.
 *
 * Erstens ist eine halbe Deckkraft aus drei Metern kein Zuruecktreten mehr,
 * sondern Unlesbarkeit -- und ein Name, den man nicht lesen kann, ist der
 * einzige Inhalt dieser Zeile. Marcel: "Die Spielernamen sind immer noch
 * nicht 100% weiss."
 *
 * Zweitens ist am Morgen NIEMAND gestartet. Dann steht die gesamte Tafel
 * blass da, und eine Hervorhebung, die fuer alle gilt, hebt nichts hervor --
 * sie macht nur die ganze Wand grau.
 *
 * Die Zeile sagt ohnehin mit Worten, woran man ist: ein Strich statt der
 * Startnummer und "nicht gestartet" hinter dem Namen. Zurueck treten deshalb
 * nur noch die beiden Stellen, an denen nichts steht -- Nummer und Bild. Die
 * Deckkraft der Zeile kann nicht dasselbe leisten: Sie ist eine Gruppe, und
 * ein Kind darin wird nie heller als sie.
 */
.tafel-buehne .tafel-tabelle tr.ist-blass { opacity: 1; }

.tafel-buehne .tafel-tabelle tr.ist-blass .tafel-nr,
.tafel-buehne .tafel-tabelle tr.ist-blass .avatar { opacity: .5; }

/* Die Fortschrittsleiste am unteren Rand -- dieselbe Sprache wie an der Bar:
   duenn, rund, im Markenton. Sie zeigt, wie lange die aktuelle Seite noch
   steht, und beantwortet damit die Frage, die man vor einer blaetternden Wand
   zuerst hat: Wie lange muss ich warten? */
.tafel-fortschritt {
    height: .35rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, .12);
    overflow: hidden;
}
.tafel-fortschritt[hidden] { display: none; }

.tafel-fortschritt-balken {
    display: block;
    height: 100%;
    width: 0;
    background: var(--trr-teal-500);
}

/* Der Kopf der Renntafel: Marke links, Eventname rechts.
   Flach und nicht gestapelt -- jeder Millimeter hier fehlt den Zeilen
   darunter, und die Lesbarkeit aus drei Metern haengt an deren Hoehe. */
.tafel-kopf {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: clamp(1rem, 3vw, 3rem);

    /* Der Strich im Markenton trennt, was bleibt, von dem, was wechselt:
       oberhalb Marke und Eventname, unterhalb der Stapel. Ohne ihn schwebt
       der Kopf im selben Raum wie der Inhalt und wandert beim Blenden
       optisch mit. */
    padding-bottom: clamp(.5rem, 1.2vh, 1rem);
    border-bottom: 3px solid var(--trr-teal-500);
}
.tafel-kopf .brand { --brand-breite: clamp(11rem, 22vw, 26rem); }

/* Der Eventname tritt zurueck -- er benennt, die Marke daneben steht fuer die
   Sache. Dieselbe Rangordnung wie auf dem Monitor an der Bar. */
.tafel-eventname {
    margin: 0;
    font-size: clamp(1rem, 1.8vw, 1.875rem);
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
    text-align: right;
}

.tafel-titel p {
    margin: .25rem 0 0;
    color: var(--trr-ink-soft);
    font-size: clamp(1rem, 1.6vw, 1.375rem);
}

.tafel-kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
}

.tafel-zahlen { display: flex; flex-wrap: wrap; gap: clamp(1rem, 3vw, 2.5rem); }

.tafel-zahl { display: flex; align-items: baseline; gap: .5rem; }
.tafel-zahl strong { font-size: clamp(1.75rem, 4vw, 3rem); line-height: 1; }
.tafel-zahl span { color: var(--trr-ink-soft); font-size: clamp(.9375rem, 1.4vw, 1.25rem); }
.tafel-zahl.ist-blass strong { color: var(--trr-ink-soft); }

.tafel-stand { margin: 0; color: var(--trr-ink-soft); font-variant-numeric: tabular-nums; }

/* Nach drei Fehlschlägen in Folge: Die Tafel zeigt noch etwas, aber nicht
   mehr das Jetzt. Lieber ein sichtbar alter Stand als eine Fehlerseite an
   der Zeltwand -- aber eben sichtbar. */
[data-tafel-seite].ist-alt .tafel-stand { color: var(--trr-warn); }

[data-tafel-seite].ist-alt .tafel-stand::after {
    content: ' — keine Verbindung';
}

/* ------------------------------------------------------------ Die Renntafel

   Eine Seite im Umlauf, also ganze Wand statt halber. Aufbau wie die
   Wertungsseite: Kopf oben, Tabelle darunter, und die Tabelle fuellt, was
   uebrig bleibt. */
/* Derselbe Takt wie bei der Dreiergruppe: Jede Zeile startet, wenn die vorige
   zur Haelfte durch ist -- also Takt = Lauf / 2. Kuerzer als dort, weil hier
   bis zu zehn Zeilen hintereinander kommen: Bei .44s Lauf steht die Tafel nach
   2,4 Sekunden. */
.renn-seite {
    --renn-lauf: .44s;
    --renn-takt: .22s;


    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    gap: .75rem;
    min-height: 0;
}
.renn-kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1.5rem;
    flex-wrap: wrap;
}

/* height: 100% auf der Tabelle laesst den Browser die uebrige Hoehe auf die
   Zeilen verteilen -- dieselbe Wirkung wie 1fr-Zeilen im Raster, nur dass eine
   Tabelle das von sich aus kann. Die Schrift haengt wie ueberall an der
   Zeilenzahl: weniger Fahrer, groessere Schrift. */
.renn-blatt {
    min-height: 0;
    overflow: hidden;
    font-size: clamp(1rem, calc((100vh - 16rem) / var(--zeilen, 10) * .34), 2rem);
}
/* Feste Spaltenbreiten: Ohne sie nimmt sich die Namensspalte, was sie will,
   und die Spiele draengen sich am rechten Rand zusammen. So bekommt jedes
   Spiel gleich viel und die Haken stehen in gleichmaessigen Abstaenden. */
.renn-blatt .tafel-tabelle { height: 100%; table-layout: fixed; }
.renn-blatt .tafel-nr { width: 5%; }
.renn-blatt .tafel-wer { width: 26%; }

.tafel-tabelle {
    width: 100%;
    border-collapse: collapse;
    font-size: clamp(1rem, 1.5vw, 1.5rem);
}

.tafel-tabelle th,
.tafel-tabelle td {
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--trr-line);
    text-align: left;
}

.tafel-tabelle thead th {
    color: var(--trr-ink-soft);
    font-size: clamp(.8125rem, 1.1vw, 1rem);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
}

.tafel-nr {
    width: 3.5rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}

.tafel-person { display: flex; align-items: center; gap: .625rem; min-width: 0; }
/* Ganze Wand statt halber: Der Name passt jetzt in eine Zeile. Umbrechen liess
   ihn frueher dreizeilig werden und drueckte die Zeilenhoehe auseinander. */
.tafel-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.tafel-hinweis {
    font-size: .75em;
    color: var(--trr-ink-soft);
    white-space: nowrap;
}

/* Mit .tafel-tabelle davor, sonst gewinnt `.tafel-tabelle th` (Klasse plus
   Element) gegen `.tafel-spiel` (nur Klasse) -- und dann stand die Spaltenzahl
   links, waehrend der Spielname darunter mittig sass. */
.tafel-tabelle .tafel-spiel,
.tafel-tabelle .tafel-feld { text-align: center; }

/* Nummer gross, Name klein darunter. Bei acht Spielen ist die Spalte schmal,
   und ueber drei Meter liest man ohnehin die Zahl -- der Name steht dabei,
   damit man sie einmal zuordnen kann und danach nicht mehr muss. */
.tafel-spiel-nr {
    display: block;
    font-size: 1.25em;
    font-weight: 700;
    color: var(--trr-ink);
}

.tafel-spiel-name {
    display: block;
    max-width: 9rem;
    margin: 0 auto;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    line-height: 1.15;
    overflow-wrap: break-word;
}

.renn-blatt .avatar { width: 1.8em; height: 1.8em; flex: none; }
.renn-blatt th, .renn-blatt td { padding: .2em .6em; }

.tafel-haken { width: 1.25em; height: 1.25em; color: var(--trr-ok); }

/* Der Stern fuer die ersten fuenf eines Spiels. Groesser als der Haken und in
   Gold: Er soll ueber drei Meter auffallen, denn er ist das Einzige auf dieser
   Tafel, das sich im Lauf des Tages bewegt.

   Hier stand eine Krone fuer den Besten. Warum sie gewichen ist, steht in
   Views/partials/renntafel -- kurz: Ein genannter Erster verraet ueber sechs
   Spalten die Gesamtwertung, fuenf gleiche Zeichen tun das nicht. */
.tafel-stern { width: 1.6em; height: 1.6em; color: var(--trr-amber-500); }
.tafel-feld.ist-vorn { background: rgba(242, 169, 59, .14); }

/* Haken und Stern liegen uebereinander im selben Feld: Beim Aufbauen steht
   der Haken da, danach loest ihn der Stern ab. Ein Raster mit einer Zelle,
   in die beide gelegt werden -- so springt nichts, wenn getauscht wird. */
/*
 * Die Legende unter dem Titel.
 *
 * Klein und leise: Sie wird einmal gelesen und danach nie wieder. Zu gross
 * naehme sie den Zeilen die Hoehe, und die Lesbarkeit der Tafel haengt an
 * genau der.
 *
 * Der Stern darin ist derselbe wie in der Tabelle -- gleiche Farbe, gleiche
 * Form, nur kleiner. Ein Legendenzeichen, das anders aussieht als das, was es
 * erklaert, erklaert nichts.
 */
.renn-titel { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }

.renn-legende {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin: 0;
    font-size: clamp(.8125rem, 1.1vw, 1.0625rem);
    color: var(--trr-ink-soft);
}

.renn-legende-zeichen { width: 1.2em; height: 1.2em; flex: none; }

.tafel-offen { color: var(--trr-line); }

/* Wer durch ist, darf zurücktreten -- gesucht wird auf dieser Tafel der, der
   noch unterwegs ist. */
.tafel-tabelle tr.ist-fertig { background: var(--trr-teal-050); }
.tafel-tabelle tr.ist-blass { opacity: .5; }

.tafel-leer { color: var(--trr-ink-soft); text-align: center; padding: 2rem 0; }

/* ----------------------------------------------------------- Die Etiketten */

.druck-reihen { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; }
.druck-reihen form { margin: 0; }
.druck-station { display: flex; gap: .5rem; align-items: center; }
.druck-station .form-select { width: auto; min-width: 10rem; }

.druck-personen { gap: .375rem; }

.druck-person {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .375rem 0;
    border-bottom: 1px solid var(--trr-line);
}

.druck-person:last-child { border-bottom: 0; }
.druck-person form { margin: 0; }

.druck-nr {
    flex: 0 0 auto;
    min-width: 2rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--trr-ink-soft);
}

.druck-name { flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; }

/* --------------------------------------------------------- Die Warteschlange */

.druck-auftrag {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .5rem .625rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
}

.druck-auftrag form { margin: 0; }

/* Der Zustand trägt die Farbe und nicht die Zeile: Eine Liste, in der jede
   zweite Zeile bunt ist, liest sich als Warnung. */
.druck-zustand {
    flex: 0 0 auto;
    min-width: 7.5rem;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--trr-ink-soft);
}

.druck-auftrag.ist-gedruckt .druck-zustand { color: var(--trr-ok); }
.druck-auftrag.ist-fehler .druck-zustand { color: var(--trr-hot); }
.druck-auftrag.ist-geholt .druck-zustand { color: var(--trr-warn); }
.druck-auftrag.ist-abgebrochen { opacity: .6; }

.druck-titel { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.druck-art { font-size: .8125rem; color: var(--trr-ink-soft); }

/* Was die Brücke gemeldet hat -- „kein Papier", „Drucker nicht erreichbar".
   Ohne diesen Satz stünde dort nur „Fehler", und dann fängt das Raten an. */
.druck-meldung { font-size: .8125rem; color: var(--trr-hot); }

/* Das Kennwort wird kopiert, nicht vorgelesen: gleiche Zeichenbreiten, und
   umbrechen darf es überall -- es ist zweiunddreißig Zeichen lang. */
.druck-kennwort {
    margin: 0 0 .75rem;
    padding: .625rem .75rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 1rem;
    letter-spacing: .06em;
    overflow-wrap: anywhere;
}

@media (max-width: 35.9375em) {
    .druck-auftrag { flex-wrap: wrap; }
    .druck-zustand { min-width: 0; }
}

/* =============================================================== Der Check-in

   Der Tisch am Morgen, bedient am Telefon, im Stehen, mit einer Schlange
   davor. Hier standen einmal Blöcke mit drei Formularen darin -- ein halber
   Bildschirm je Person. Jetzt Karten wie unter „Meine Familie": Gesicht,
   Nummer, Name, Zustand, ein Knopf. Alles andere steht im Fenster. */

.checkin-raster {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: .75rem;
    margin-top: 1.25rem;
}

.checkin-karte {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
    padding: 1rem .75rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    text-align: center;
    scroll-margin-top: calc(var(--nav-hoehe) + 1rem);
}

/* Wer da ist, tritt zurück. Gesucht wird am Morgen der, der fehlt -- und
   deshalb trägt die Karte des Eingecheckten die ruhige Farbe und nicht die
   auffällige. */
.checkin-karte.ist-da {
    border-color: var(--trr-teal-700);
    background: var(--trr-teal-050);
}

.checkin-bild { position: relative; }

/* Die Startnummer auf dem Bild, nicht daneben: Sie gehört zu diesem Gesicht,
   und auf einer schmalen Karte ist neben dem Bild kein Platz. */
.checkin-nummer {
    display: inline-grid;
    place-items: center;
    min-width: 1.9rem;
    height: 1.9rem;
    padding: 0 .375rem;
    border-radius: 999px;
    background: var(--trr-teal-700);
    color: var(--trr-on-primary);
    font-weight: 700;
    font-size: .9375rem;
    font-variant-numeric: tabular-nums;
}

.checkin-bild .checkin-nummer {
    position: absolute;
    right: -.25rem;
    bottom: -.25rem;
    box-shadow: 0 0 0 3px var(--trr-row);
}

.checkin-karte.ist-da .checkin-bild .checkin-nummer {
    box-shadow: 0 0 0 3px var(--trr-teal-050);
}

.checkin-name {
    margin: .5rem 0 0;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.2;
    overflow-wrap: break-word;
}

.checkin-meta { margin: 0; font-size: .8125rem; color: var(--trr-ink-soft); }

/* Ob jemand mitspielt -- die Auskunft, die es vor dem Umbau nicht gab.
   Gedaempft, solange er zuschaut, im Markenton, wenn er dabei ist: Beim
   Ueberfliegen der Karten sucht man die Spieler, nicht die Zuschauer. */
.checkin-rolle {
    margin: .25rem 0 0;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--trr-ink-quiet);
}

.checkin-rolle.ist-dabei { color: var(--trr-teal-700); }

/* Der Schalter im Fenster steht fuer sich und nicht in einer Reihe -- er ist
   der erste Schritt und traegt die Startnummer mit sich. */
.checkin-spielt { margin-bottom: .5rem; }

.checkin-zustand {
    margin: .375rem 0 .625rem;
    font-size: .8125rem;
    display: flex;
    align-items: center;
    gap: .3125rem;
}

.checkin-haken { width: 1rem; height: 1rem; color: var(--trr-ok); }
.checkin-offen { color: var(--trr-ink-soft); }

.checkin-buttons {
    margin-top: auto;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .375rem;
}

.checkin-buttons form { margin: 0; }

/* ------------------------------------------------------ Das Schrittfenster */

/* Die Punktreihe: wie weit bin ich. Drei Punkte sagen das schneller als
   „Schritt 2 von 3" -- man zählt sie nicht, man sieht sie. */
.schritt-punkte {
    list-style: none;
    margin: 0 0 1.25rem;
    padding: 0;
    display: flex;
    justify-content: center;
    gap: .5rem;
}

.schritt-punkte li {
    width: .5rem;
    height: .5rem;
    border-radius: 999px;
    background: var(--trr-line);
}

.schritt-punkte li.ist-durch { background: var(--trr-ink-soft); }

.schritt-punkte li.ist-hier {
    background: var(--trr-teal-700);
    transform: scale(1.4);
}

.schritt-titel { margin: 0 0 .75rem; }

.schritt-foto {
    display: grid;
    place-items: center;
    min-height: 8rem;
}

/* Das gewählte Bild sofort sehen. Rund wie der Avatar daneben, damit der
   Wechsel kein Formatsprung ist. */
.schritt-vorschau {
    width: 8rem;
    height: 8rem;
    border-radius: 999px;
    object-fit: cover;
    background: var(--trr-row);
}

/* Zurück links, Weiter und Speichern rechts -- die übliche Leserichtung. */
.schritt-fuss { justify-content: space-between; }
.schritt-fuss [data-schritt-weiter],
.schritt-fuss [data-schritt-fertig] { margin-left: auto; }

/* Gesicht und Name nebeneinander -- der Betreuer prüft damit, ob der
   Richtige vor ihm steht, bevor er eine Zahl einträgt. */
.wiese-wer { display: flex; align-items: center; gap: .875rem; min-width: 0; }
.wiese-wer .wiese-titel { min-width: 0; }

/* ================================================================ Der Fund

   Der Witz für alle, die den Aufkleber aus Neugier scannen.

   Die einzige Seite der Erfassung, die etwas darstellen darf. Die anderen
   sind Werkzeug: Man steht davor, tippt eine Zahl und geht weiter -- dort
   wäre Zierat im Weg. Diese hier ist eine Entdeckung, und dann darf sie auch
   danach aussehen. */

/* Mittig auf dem Schirm statt oben: Ein Fund braucht keinen Arbeitsplatz,
   sondern einen Auftritt. */
.wiese-fund {
    min-height: calc(100vh - 4rem);
    align-content: center;
    justify-items: center;
    gap: 1.5rem;
}

.witz-karte {
    position: relative;
    overflow: hidden;
    width: 100%;
    padding: 2rem 1.5rem;
    border: 1px solid var(--trr-teal-700);
    border-radius: var(--trr-radius-sm);

    /* Ein Hauch Markenton statt des üblichen Panelgrundes -- die Karte soll
       sich vom Werkzeug daneben unterscheiden, ohne bunt zu werden. */
    background:
        radial-gradient(120% 90% at 50% 0%, var(--trr-teal-100), transparent 70%),
        var(--trr-paper);
    text-align: center;
}

/* Der Traktor groß und als Umriss -- „groß oder gar nicht". Klein laufen die
   Linien zu und aus der Zeichnung wird ein Fleck. Er liegt hinter dem Text,
   angeschnitten wie in den Fenstern des Portals, und nimmt keine Berührung
   an. */
.witz-traktor {
    position: absolute;
    right: -3rem;
    bottom: -2rem;
    width: 21rem;
    color: var(--trr-teal-700);

    /* Kräftiger als in den Fenstern des Portals (dort .2 bei 13rem). Dort
       ist er Zierat neben einem Formular; hier ist er der halbe Grund, warum
       die Seite überhaupt gestaltet wurde -- und bei .16 las er sich als
       Rauschen statt als Zeichnung. */
    opacity: .28;
    pointer-events: none;
}

.witz-traktor svg { display: block; width: 100%; height: auto; }

/* Über den Traktor, sonst liest man den Witz durch die Radspeichen. */
.witz-inhalt { position: relative; }

/* Das Gesicht vom Morgen -- rund, mit einem Ring im Markenton.
   ----------------------------------------------------------------------
   Rund und nicht eckig: Ein Passbild ist ein Dokument, ein Kreis ist ein
   Mensch. Der Ring hebt es vom Traktor ab, der als Umriss dahinterliegt --
   ohne ihn liefe der helle Rand des Fotos in die Zeichnung.

   Feste Kantenlaenge in em und nicht in Prozent: Die Karte ist auf einem
   Telefon so breit wie der Bildschirm und auf einem Laptop dreimal so
   breit, und ein Gesicht, das mitwaechst, waere dort ein Plakat. */
.witz-gesicht {
    display: block;
    width: 7.5rem;
    height: 7.5rem;
    margin: 0 auto 1rem;
    border: 3px solid var(--trr-teal-600);
    border-radius: 50%;
    object-fit: cover;

    /* Der Grund darunter: Bis das Bild da ist, steht sonst ein Loch in der
       Karte -- auf einer Wiese mit wackligem Netz durchaus eine Weile. */
    background: var(--trr-panel);
}

.witz-hallo {
    margin: 0;
    font-size: 1.5rem;
    line-height: 1.25;
    overflow-wrap: break-word;
}

.witz-hallo strong { color: var(--trr-teal-800); }

.witz-ansage {
    margin: .375rem 0 1.25rem;
    color: var(--trr-ink-soft);
}

/* Die Pointe ist der Grund für die Seite -- also groß, und in der
   Zweitfarbe, damit sie sich vom Rest abhebt wie ein Zuruf. */
.witz-text {
    margin: 0;
    font-size: 1.375rem;
    line-height: 1.4;
    font-weight: 600;
    color: var(--trr-amber-500);
}

.witz-fuss {
    margin: 1.5rem 0 0;
    padding-top: 1rem;
    border-top: 1px solid var(--trr-line);
    font-size: .8125rem;
    color: var(--trr-ink-soft);
}

/* Die Wortmarke beantwortet „wo bin ich hier gelandet", ohne sich
   vorzudrängen. Ohne Verweis: Der Gast hat hier nichts zu erledigen. */
/* Kein Verweis und trotzdem lesbar: Bei .55 auf gedämpftem Grau war der
   Schriftzug ein grauer Streifen, und die Frage „wo bin ich gelandet" blieb
   offen -- also der volle Textton und nur wenig zurückgenommen. */
.witz-marke {
    margin: 0;
    width: 11rem;
    color: var(--trr-ink);
    opacity: .75;
}

.witz-marke svg { display: block; width: 100%; height: auto; }

@media (min-width: 30em) {
    .witz-karte { padding: 2.5rem 2rem; }
    .witz-hallo { font-size: 1.75rem; }
    .witz-text { font-size: 1.625rem; }
}

/* Die Witzesammlung: eine Zeile je Witz, ohne Nummer und ohne Abzeichen --
   es gibt nur den Text, und der darf die ganze Breite haben. */
.pflegezeile.witz-zeile { grid-template-columns: 2.5rem 1fr auto; }

.witz-satz { font-weight: 400; overflow-wrap: break-word; }

@media (max-width: 47.9375em) {
    .pflegezeile.witz-zeile { grid-template-columns: 2.5rem 1fr; }
    .pflegezeile.witz-zeile .pflege-buttons { grid-column: 2; justify-self: start; }
}

/* ------------------------------------------------------- Die beiden Tafeln

   Nebeneinander, sobald der Bildschirm es hergibt -- an einer Zeltwand hängt
   ein Fernseher im Querformat, und dort ist Platz für beides. Untereinander
   wäre die zweite Tafel unterhalb der Kante und damit nicht vorhanden.

   Blättern wäre die Alternative gewesen und ist die schlechtere: Wer sein
   eigenes Ergebnis sucht, müsste warten, bis das Bild wiederkommt. */

/* minmax(0, 1fr) oben und min-height: 0 hier: Ohne beides wächst ein Kind im
   Grundriss auf seine Inhaltshöhe und ignoriert die Vorgabe von oben. */
.tafel-paar { display: grid; gap: 1.5rem; min-height: 0; }
.tafel-paar > * { min-height: 0; }

@media (min-width: 62em) {
    /* Die Live-Tabelle schmaler: Sie hat drei Spalten, die Renntafel bei acht
       Spielen zehn. */
    .tafel-paar { grid-template-columns: minmax(20rem, 2fr) 3fr; align-items: stretch; }

    /* Steht die Wertung zweispaltig, braucht sie die halbe Wand. Sonst bliebe
       für den Namen so wenig übrig, dass jeder zweite gekürzt wird -- und die
       zweite Spalte hätte nichts gewonnen. */
    .tafel-paar:has(.liga[data-spalten="2"]) { grid-template-columns: 1fr 1fr; }
}

/* -------------------------------------------------------- Die Live-Tabelle */

/* ---------------------------------------------------------------- Der Stapel

   Alle Seiten liegen im selben Rasterfeld uebereinander; sichtbar ist immer
   genau eine. Uebereinander statt nebeneinander, damit die Hoehe nicht von der
   Seitenzahl abhaengt -- und ohne position: absolute, weil der Stapel dann
   seine eigene Hoehe verloere. */
.tafel-deck { display: grid; min-height: 0; }

.tafel-seite {
    grid-area: 1 / 1;
    min-height: 0;
    display: grid;
    grid-template-rows: minmax(0, 1fr) auto;
    gap: .75rem;
    opacity: 0;
    visibility: hidden;
    /* visibility springt erst nach der Blende -- sonst waere die abgehende
       Seite sofort weg und es blitzte durch. */
    transition: opacity .25s ease, visibility 0s linear .25s;
}
.tafel-seite.ist-sichtbar {
    opacity: 1;
    visibility: visible;
    transition: opacity .25s ease, visibility 0s;
}

/* ------------------------------------------------------- Der Auftritt

   Karten fallen von oben ein, Tabellenzeilen blenden von unten nach --
   nacheinander, aber zuegig. Eine Wand, auf der alle acht Sekunden ein
   fertiges Bild erscheint, wirkt starr; ein kurzer Auftritt macht daraus
   eine Anzeige, die lebt.

   Die Regeln haengen an .ist-sichtbar und nicht am Laden des Dokuments.
   Das ist der Kniff: Beim Blattwechsel geht die Klasse ab und wieder an,
   und damit laeuft die Animation jedes Mal neu -- sonst saehe man den
   Auftritt genau einmal, beim allerersten Aufruf am Morgen.

   --i ist die Nummer innerhalb der Seite und kommt aus dem PHP. Ueber
   nth-child liesse sich das auch machen, aber dann muesste fuer jede
   moegliche Zeilenzahl eine eigene Regel dastehen. */
@keyframes tafel-fallen {
    from { opacity: 0; transform: translateY(-2.5rem); }
    to   { opacity: 1; transform: none; }
}

@keyframes tafel-auftauchen {
    from { opacity: 0; transform: translateY(.5rem); }
    to   { opacity: 1; transform: none; }
}

@keyframes tafel-aufgehen {
    from { opacity: 0; transform: scale(.86); }
    to   { opacity: 1; transform: none; }
}

/* Die Zaehlung steht hier und nicht im Markup.
   ---------------------------------------------------------------------------
   Das Portal liefert `style-src 'self'` ohne 'unsafe-inline' aus -- der
   Browser verwirft jedes style-Attribut, und zwar stillschweigend. Hier stand
   einmal `style="--i: 0"` an jeder Karte. Im Stylesheet war die Staffelung
   korrekt, gemessen wurde sie auch, und auf dem Monitor kamen trotzdem alle
   drei Karten gleichzeitig: --i erreichte die Elemente nie, also griff
   ueberall der Ersatzwert 0.

   Der Fehler ist besonders heimtueckisch, weil die feste Haelfte der
   Verzoegerung (950ms) weiter wirkte -- es sah also nach "Pause, dann alles
   auf einmal" aus und nicht nach "kaputt".

   nth-child kennt die Position ohnehin. Sechs Karten, weil die Spitze bei
   Gleichstand hoechstens sechs zeigt; zwoelf Zeilen, weil zehn je Seite
   stehen. */
.spitze-wer:nth-child(1) { --i: 0; }
.spitze-wer:nth-child(2) { --i: 1; }
.spitze-wer:nth-child(3) { --i: 2; }
.spitze-wer:nth-child(4) { --i: 3; }
.spitze-wer:nth-child(5) { --i: 4; }
.spitze-wer:nth-child(6) { --i: 5; }

.tafel-tabelle tbody tr:nth-child(1) { --i: 0; }
.tafel-tabelle tbody tr:nth-child(2) { --i: 1; }
.tafel-tabelle tbody tr:nth-child(3) { --i: 2; }
.tafel-tabelle tbody tr:nth-child(4) { --i: 3; }
.tafel-tabelle tbody tr:nth-child(5) { --i: 4; }
.tafel-tabelle tbody tr:nth-child(6) { --i: 5; }
.tafel-tabelle tbody tr:nth-child(7) { --i: 6; }
.tafel-tabelle tbody tr:nth-child(8) { --i: 7; }
.tafel-tabelle tbody tr:nth-child(9) { --i: 8; }
.tafel-tabelle tbody tr:nth-child(10) { --i: 9; }
.tafel-tabelle tbody tr:nth-child(11) { --i: 10; }
.tafel-tabelle tbody tr:nth-child(12) { --i: 11; }

/* Die Zeilenzahl als Klasse -- daran haengt die Schriftgroesse. */
.zeilen-1 { --zeilen: 1; } .zeilen-2 { --zeilen: 2; } .zeilen-3 { --zeilen: 3; } .zeilen-4 { --zeilen: 4; } .zeilen-5 { --zeilen: 5; } .zeilen-6 { --zeilen: 6; }
.zeilen-7 { --zeilen: 7; } .zeilen-8 { --zeilen: 8; } .zeilen-9 { --zeilen: 9; } .zeilen-10 { --zeilen: 10; } .zeilen-11 { --zeilen: 11; } .zeilen-12 { --zeilen: 12; }
.zeilen-13 { --zeilen: 13; } .zeilen-14 { --zeilen: 14; } .zeilen-15 { --zeilen: 15; } .zeilen-16 { --zeilen: 16; } .zeilen-17 { --zeilen: 17; } .zeilen-18 { --zeilen: 18; }
.zeilen-19 { --zeilen: 19; } .zeilen-20 { --zeilen: 20; } .zeilen-21 { --zeilen: 21; } .zeilen-22 { --zeilen: 22; }

/* Die Tafel baut sich von oben nach unten auf.
   ---------------------------------------------------------------------------
   Animiert wird der INHALT der Zellen, nicht die Zeile. Der Unterschied ist
   sichtbar: Die Trennlinien sitzen auf den Zellen, und eine mitblendende Zeile
   naehme sie mit. So steht das Raster sofort da -- Kopfzeile und Linien -- und
   fuellt sich dann Zeile fuer Zeile mit Namen, Haken und Kronen.

   --i steht auf dem <tr>; Eigenschaften vererben sich, also kennen die Zellen
   und deren Kinder sie ebenfalls.

   Die Kurve ist dieselbe symmetrische wie bei der Dreiergruppe. Mit ease-out
   war der Aufbau ruppig: Jede Zeile war bei halber Laufzeit schon zu zwei
   Dritteln da und sass dann, waehrend die naechste erst anfing -- ein Stapeln
   statt eines Flusses. */
.tafel-seite.ist-sichtbar .tafel-tabelle tbody td > * {
    animation: tafel-auftauchen var(--renn-lauf) cubic-bezier(.45, .05, .55, .95) backwards;
    animation-delay: calc(var(--i, 0) * var(--renn-takt));
}

/* Die farbigen Flaechen gehoeren zur Zeile und muessen mit ihr kommen.
   ---------------------------------------------------------------------------
   Der goldene Grund der Kronenzelle und der gruene der fertigen Zeile sitzen
   auf <td> und <tr> -- also auf dem, was NICHT mitblendet, damit die
   Trennlinien stehen bleiben. Ohne diese Regeln standen sie sofort da: leere
   goldene Kaestchen im unteren Drittel der Tafel, Sekundenbruchteile bevor
   die Krone darin erschien. Animiert wird deshalb nur die Farbe, nicht die
   Deckkraft -- sonst waere die Linie wieder weg. */
@keyframes tafel-grund-gold {
    from { background-color: transparent; }
    to   { background-color: rgba(242, 169, 59, .14); }
}

@keyframes tafel-grund-fertig {
    from { background-color: transparent; }
    to   { background-color: var(--trr-teal-050); }
}

/* Die farbige Flaeche des Sternfelds kommt mit ihrer Zeile.
   ---------------------------------------------------------------------------
   Sie blendete eine Zeit lang erst hinterher auf, zusammen mit einem Stern,
   der einen Haken abloeste -- einer nach dem anderen, in gewuerfelter Folge.
   Es sah gut aus und war eine Bewegung zu viel; die Begruendung steht in
   Views/partials/renntafel. Jetzt wieder derselbe Takt wie alles andere in
   der Zeile. */
.tafel-seite.ist-sichtbar .tafel-tabelle tbody td.ist-vorn {
    animation: tafel-grund-gold var(--renn-lauf) cubic-bezier(.45, .05, .55, .95) backwards;
    animation-delay: calc(var(--i, 0) * var(--renn-takt));
}

.tafel-seite.ist-sichtbar .tafel-tabelle tbody tr.ist-fertig {
    animation: tafel-grund-fertig var(--renn-lauf) cubic-bezier(.45, .05, .55, .95) backwards;
    animation-delay: calc(var(--i, 0) * var(--renn-takt));
}

/* Die Dreiergruppe: eine Kette, kein Aufblitzen.
   ---------------------------------------------------------------------------
   Neun Elemente in EINER Kette, in dieser Reihenfolge:

       Kasten 1, Kasten 2, Kasten 3, Bild 1, Name 1, Bild 2, Name 2, Bild 3, Name 3

   Jedes startet, wenn das vorige zur Haelfte durch ist. Genau deshalb ist der
   Takt die halbe Laufzeit und keine eigene Zahl -- wer die Laufzeit aendert,
   aendert den Abstand automatisch mit, und das Verhaeltnis bleibt.

   Zwei Stellschrauben, sonst nichts:

       --spitze-lauf   wie lange ein einzelnes Element braucht
       --spitze-takt   der Abstand, immer die Haelfte davon

   Bei .68s Lauf steht die Tafel nach 3,4 Sekunden -- bei acht Sekunden
   Standzeit bleiben mehr als vier Sekunden Ruhe danach.

   Die Kurve ist symmetrisch, und das ist keine Geschmacksfrage.
   ---------------------------------------------------------------------------
   Hier stand cubic-bezier(.22, .9, .3, 1), eine stark ausklingende Kurve. Die
   ist bei halber Laufzeit schon zu 95 Prozent durch -- nachgerechnet, nicht
   geschaetzt. Das Element SAH also fertig aus, wenn der Nachfolger startete,
   und von der Ueberschneidung war nichts zu sehen, obwohl die Verzoegerungen
   auf die Millisekunde stimmten.

   cubic-bezier(.45, .05, .55, .95) ist punktsymmetrisch zu (.5, .5): bei
   halber Zeit genau halber Fortschritt. Damit heisst "startet bei 50 Prozent"
   auch sichtbar 50 Prozent. Linear taete dasselbe, wirkt bei .68s aber
   mechanisch. */
.spitze-seite {
    --spitze-lauf: .68s;
    --spitze-takt: .34s;
}

.tafel-seite.ist-sichtbar .spitze-wer {
    animation: tafel-fallen var(--spitze-lauf) cubic-bezier(.45, .05, .55, .95) backwards;
    animation-delay: calc(var(--i, 0) * var(--spitze-takt));
}

/* Platz 4, 6 und 8 in der Kette -- also drei Takte fuer die Kaesten, dann je
   zwei je Karte. */
.tafel-seite.ist-sichtbar .spitze-wer .avatar {
    animation: tafel-aufgehen var(--spitze-lauf) cubic-bezier(.45, .05, .55, .95) backwards;
    animation-delay: calc(var(--spitze-takt) * 3 + var(--i, 0) * var(--spitze-takt) * 2);
}

/* Platz 5, 7 und 9. */
.tafel-seite.ist-sichtbar .spitze-name {
    animation: tafel-auftauchen var(--spitze-lauf) cubic-bezier(.45, .05, .55, .95) backwards;
    animation-delay: calc(var(--spitze-takt) * 4 + var(--i, 0) * var(--spitze-takt) * 2);
}

/* Die Fussnote zuletzt -- sie erklaert die Tafel, und erklaert wird, was schon
   dasteht. */
.tafel-seite.ist-sichtbar .spitze-fussnote {
    animation: tafel-auftauchen var(--spitze-lauf) ease-out backwards;
    animation-delay: calc(var(--spitze-takt) * 9);
}

/* Wer Bewegung abgeschaltet hat, bekommt harte Schnitte statt Blenden. Das
   Blaettern selbst bleibt -- ohne es saehe man nur ein Zehntel der Fahrer. */
@media (prefers-reduced-motion: reduce) {
    .tafel-seite { transition: none; }
    .tafel-seite.ist-sichtbar .spitze-wer,
    .tafel-seite.ist-sichtbar .spitze-wer .avatar,
    .tafel-seite.ist-sichtbar .spitze-name,
    .tafel-seite.ist-sichtbar .spitze-fussnote,
    .tafel-seite.ist-sichtbar .tafel-tabelle tbody td > *,
    .tafel-seite.ist-sichtbar .tafel-tabelle tbody td.ist-vorn,
    .tafel-seite.ist-sichtbar .tafel-tabelle tbody tr.ist-fertig { animation: none; }
}

.tafel-kapitel {
    margin: 0;
    font-size: clamp(1rem, 1.6vw, 1.5rem);
    color: var(--trr-ink-soft);
    text-transform: uppercase;
    letter-spacing: .06em;
}

.tafel-fuss {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    font-size: clamp(.8125rem, 1vw, 1rem);
    color: var(--trr-ink-soft);
}
/* „Seite 2 von 4": Wer seinen Namen sucht und nicht findet, muss unterscheiden
   koennen zwischen „ich stehe nicht drauf" und „ich komme gleich". */
.tafel-blatt { margin: 0; font-variant-numeric: tabular-nums; }

.wertung-seite {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    gap: .75rem;
    min-height: 0;
}

/* Die Höhe wird auf --zeilen gleich hohe Zeilen aufgeteilt, und die Schrift
   folgt dieser Höhe: sechs Fahrer stehen gross da, dreissig klein. Begrenzt
   nach unten auf 17px -- mehr gibt eine 55-Zoll-Wand aus drei Metern nicht her
   -- und nach oben auf 28px, damit sechs Zeilen nicht zum Plakat werden.

   grid-auto-flow: column füllt spaltenweise. Bei zwei Spalten stehen also 1
   bis 15 links und 16 bis 30 rechts, nicht 1 und 2 nebeneinander -- eine
   Rangliste liest man senkrecht. */
.liga-liste {
    list-style: none; margin: 0; padding: 0;
    min-height: 0;
    display: grid;
    grid-template-rows: repeat(var(--zeilen, 10), minmax(0, 1fr));
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: .4vh .75rem;
    font-size: clamp(1.0625rem, calc((100vh - 14rem) / var(--zeilen, 10) * .39), 2.5rem);
}

.liga-zeile {
    display: grid;
    grid-template-columns: 2.2em auto minmax(0, 1fr) auto;
    align-items: center;
    gap: .5em;
    padding: .25em .6em;
    border-radius: var(--trr-radius-sm);
    background: rgba(28, 31, 37, .55);
    min-height: 0;
    overflow: hidden;
}

/* Das Bild wächst und schrumpft mit der Zeile. .avatar-sm bleibt unangetastet
   -- daran hängen vierzig andere Stellen im Portal. */
.liga-zeile .avatar { width: 1.9em; height: 1.9em; flex: none; }

/* Die ersten drei heben sich ab -- aus drei Metern sieht man sonst nur eine
   Liste, und die Frage am Monitor lautet „wer führt". */
.liga-zeile.ist-podest { background: rgba(2, 176, 167, .16); }
.liga-zeile.ist-platz-1 { background: rgba(242, 169, 59, .2); }

.liga-platz {
    text-align: center;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--trr-ink-soft);
}

.liga-zeile.ist-platz-1 .liga-platz { color: var(--trr-amber-500); }

.liga-wer { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
/* Kein Umbruch: In einer Zeile fester Höhe fiele die zweite Zeile unsichtbar
   heraus. Lieber kürzen -- vollständig steht der Name im title. */
.liga-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* „nach 4 Spielen" -- ohne diese Zeile misst die Tabelle mitten am Tag vor
   allem, wer schneller herumgekommen ist. */
.liga-meta { font-size: .7em; color: var(--trr-ink-soft); }

/* ---------------------------------------------------------------- Die Spitze

   „Diese drei sind vorne" -- gleich gross, gleich hoch, nebeneinander. Keine
   Treppe, keine Farbabstufung, kein Erster in der Mitte: Jede Andeutung einer
   Rangfolge waere hier eine Luege, denn genau die soll offenbleiben. */
.spitze-seite {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: 1rem;
    min-height: 0;
}

.spitze {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: clamp(1rem, 3vw, 3rem);
    /* Die Karten fuellen die Hoehe, statt als Streifen in der Mitte zu
       schweben -- auf einer Wand von drei Metern Abstand wirkt sonst die
       halbe Flaeche ungenutzt. */
    align-items: stretch;
    min-height: 0;
}

.spitze-wer {
    display: grid;
    justify-items: center;
    align-content: center;
    gap: clamp(.75rem, 2vh, 2rem);
    padding: clamp(1rem, 3vh, 3rem) 1rem;
    border-radius: var(--trr-radius-sm);
    background: rgba(2, 176, 167, .14);
    width: 100%;
    min-height: 0;
    overflow: hidden;
}

.spitze-wer .avatar {
    width: clamp(5rem, 28vh, 16rem);
    height: clamp(5rem, 28vh, 16rem);
}

.spitze-name {
    font-weight: 600;
    text-align: center;
    font-size: clamp(1.25rem, 2.8vw, 3rem);
    line-height: 1.15;
    max-width: 100%;
}

/* Der Hinweis ist kein Kleingedrucktes, sondern der Grund, warum die Tafel
   ueberhaupt so aussieht -- deshalb lesbar und nicht weggedimmt. */
.spitze-fussnote {
    margin: 0;
    text-align: center;
    color: var(--trr-ink-soft);
    font-size: clamp(.875rem, 1.3vw, 1.25rem);
    line-height: 1.4;
}

/* ------------------------------------------------------- Die Siegerehrung

   Dieselbe Buehne wie die Renntafel, aber ohne Stapel: Es gibt nur ein Bild,
   das sich in vier Stufen fuellt. Die Buehne ist deshalb ein Raster aus Kopf
   und einem Feld, das den Rest bekommt. */
.tafel-buehne.ist-ehrung { grid-template-rows: auto minmax(0, 1fr); }

.ehrung {
    display: grid;
    grid-template-rows: minmax(0, 1.5fr) minmax(0, 1fr) auto;
    gap: 1.2rem;
    min-height: 0;
    position: relative;
}

/* Alles, was eine Stufe traegt, wartet -- bis das Skript (oder ohne Skript
   der Server) ihm `ist-da` gibt. visibility zusaetzlich zu opacity, damit ein
   noch nicht genannter Sieger auch nicht als blasser Schatten dasteht. */
.ehrung [data-stufe] {
    opacity: 0;
    visibility: hidden;
}

.ehrung [data-stufe].ist-da {
    opacity: 1;
    visibility: visible;
}

/* Der Auftritt: Das Podest faellt ein, die Liste taucht auf. Dieselben
   Bewegungen wie auf der Renntafel -- wer die eine gesehen hat, kennt die
   andere. */
.ehrung .podest-platz.ist-da {
    animation: tafel-fallen .6s cubic-bezier(.45, .05, .55, .95) backwards;
}

/* Der Sieger kommt anders herein als die anderen: Er waechst auf, statt zu
   fallen. Das ist der einzige Moment des Abends, der eine eigene Geste
   verdient. */
.ehrung .podest-platz.ist-rang-1.ist-da {
    animation: tafel-aufgehen .7s cubic-bezier(.34, 1.3, .5, 1) backwards;
}

.ehrung .podest-rest.ist-da {
    animation: tafel-auftauchen .5s cubic-bezier(.45, .05, .55, .95) backwards;
}

@media (prefers-reduced-motion: reduce) {
    .ehrung [data-stufe].ist-da { animation: none; }
}

/* Der Hinweis fuer Marcel, solange die Buehne leer ist. Danach waere er eine
   Bedienungsanleitung vor Publikum -- das Skript blendet ihn ab der ersten
   Stufe aus. */
/* Die Bilder gross -- sie sind das Persoenliche am Abend.
   ---------------------------------------------------------------------------
   Auf der Renntafel sind sie Beiwerk neben Zahlen und muessen klein bleiben;
   hier stehen drei Menschen auf einem Podest, und dann darf man sie auch
   sehen. Deshalb hier ueberschrieben und nicht an .podest-platz selbst --
   das gilt auch fuer die geparkte Podestseite der Renntafel.

   Die Karten wachsen mit: Ein Bild, das aus seinem Sockel herausragt, wuerde
   von overflow: hidden abgeschnitten, und zwar unauffaellig schief. */
.ehrung .podest-platz .avatar {
    width: clamp(4.5rem, 13vh, 10rem);
    height: clamp(4.5rem, 13vh, 10rem);
}
.ehrung .podest-platz.ist-rang-1 .avatar {
    width: clamp(6rem, 18vh, 14rem);
    height: clamp(6rem, 18vh, 14rem);
}

.ehrung .podest-platz.ist-rang-2 { height: 88%; }
.ehrung .podest-platz.ist-rang-3 { height: 80%; }

/* ------------------------------------------------------------- Das Losrad

   Ein Band aus allen Fahrern laeuft von rechts nach links durchs Bild und
   bleibt unter der Nadel stehen. Es liegt ueber allem, damit das halb
   gefuellte Podest dahinter nicht ablenkt, und verdunkelt den Grund -- sonst
   flimmerte der Film darunter mit. */
.losrad {
    position: fixed;
    inset: 0;
    z-index: 10;
    display: grid;
    grid-auto-flow: row;
    align-content: center;
    justify-items: center;
    gap: clamp(1rem, 3vh, 2.5rem);
    background: rgba(6, 26, 32, .86);
    opacity: 0;
    transition: opacity .3s ease;
}
.losrad[hidden] { display: none; }
.losrad.ist-da { opacity: 1; }

/* Die Ansage: „Platz 3 geht an:". Sie steht ueber dem Rad und sagt, worum
   es gerade laeuft -- ohne sie dreht sich etwas, und niemand weiss, wofuer. */
.losrad-titel {
    margin: 0;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--trr-ink-soft);
    font-size: clamp(1.125rem, 2.2vw, 2.25rem);
}

/* Das Fenster begrenzt, was man sieht. An den Raendern laeuft es aus: Ohne
   das Ausblenden schnitte eine harte Kante die Gesichter ab, und das Band
   saehe aus wie eine Liste hinter einem Schlitz statt wie ein Rad. */
.losrad-fenster {
    position: relative;
    width: min(94vw, 110rem);
    height: clamp(21rem, 60vh, 45rem);
    overflow: hidden;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
}

/* Das Band selbst. Die Verschiebung setzt das Skript ueber die CSSOM --
   ein style-Attribut im Markup verwuerfe die Sicherheitsregel des Portals. */
.losrad-band {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    display: flex;
    align-items: center;
    gap: clamp(1.5rem, 4.5vh, 3.75rem);
    will-change: transform;
}

.losrad-wer {
    flex: 0 0 auto;
    width: clamp(13.5rem, 36vh, 27rem);
    display: grid;
    justify-items: center;
    align-content: center;
    gap: 1.1rem;
}

.losrad-wer .avatar {
    width: clamp(9rem, 27vh, 19.5rem);
    height: clamp(9rem, 27vh, 19.5rem);
}

/* Groesser als auf dem Podest: In Bewegung erfasst man einen grossen Namen,
   einen kleinen liest man erst, wenn er steht -- und dann ist er vorbei.

   Und mit FESTER Hoehe fuer drei Zeilen.
   ---------------------------------------------------------------------------
   "Kim Welz" braucht eine Zeile, "Mia Mustermann-Musterfrau" drei. Ohne feste
   Hoehe waeren die Felder verschieden hoch, und weil das Band sie mittig
   ausrichtet, huepften die Bilder beim Vorbeiziehen auf und ab -- als liefe
   das Rad unrund. Drei Zeilen sind reserviert, ob sie gebraucht werden oder
   nicht; was darueber hinausginge, wird abgeschnitten. */
.losrad-name {
    font-weight: 600;
    text-align: center;
    line-height: 1.15;
    /* In vh und nicht in vw: Alles andere im Rad haengt an der Fensterhoehe.
       Ein Mass, das der Breite folgt, laeuft bei flachen Fenstern aus dem
       Kasten -- genau das ist einmal passiert. */
    font-size: clamp(1.125rem, 4.7vh, 3.1875rem);
    height: calc(3 * 1.15em);
    max-width: 100%;
    overflow: hidden;
}

/* Wer gerade unter der Nadel steht, tritt hervor. Die Klasse setzt das
   Skript erst, wenn das Rad steht -- waehrend der Fahrt waere sie ein
   Flackern. */
.losrad-wer.ist-treffer .avatar { box-shadow: 0 0 0 4px var(--trr-amber-500); }
.losrad-wer.ist-treffer .losrad-name { color: var(--trr-amber-500); }

/* Das Kaestchen mit der Nadel. Es steht fest in der Mitte, das Band laeuft
   darunter durch -- wie die Anzeige eines Glueckrads. Die Spitze sitzt oben
   auf der Kante und zeigt nach innen: dorthin, wo abgelesen wird. */
.losrad-nadel {
    position: absolute;
    top: 50%;
    left: 50%;
    /* Nur der Rueckfall, falls kein Skript laeuft. Im Betrieb setzt das
       Skript beide Masse aus dem gemessenen Feld -- siehe ehrung.js. */
    width: clamp(13.5rem, 36vh, 27rem);
    height: clamp(16.5rem, 48vh, 36rem);
    transform: translate(-50%, -50%);
    border: 3px solid var(--trr-teal-500);
    border-radius: var(--trr-radius-sm);
    pointer-events: none;
}

.losrad-nadel::before {
    content: '';
    position: absolute;
    top: -.2rem;
    left: 50%;
    transform: translateX(-50%);
    border-left: 1.3rem solid transparent;
    border-right: 1.3rem solid transparent;
    border-top: 1.7rem solid var(--trr-amber-500);
}

/* Steht das Rad, springt die Nadel auf Gold -- sonst weiss niemand, ob es
   fertig ist oder nur sehr langsam. */
.losrad.ist-gefallen .losrad-nadel { border-color: var(--trr-amber-500); }

@media (prefers-reduced-motion: reduce) {
    .losrad { transition: none; }
    .losrad-band { transition: none !important; }
}

.ehrung-hinweis {
    margin: 0;
    text-align: center;
    color: var(--trr-ink-soft);
    font-size: clamp(.8125rem, 1.1vw, 1rem);
}
.ehrung-hinweis[hidden] { display: none; }

/* ---------------------------------------------------------------- Das Podest

   Die letzte Seite jedes Umlaufs. Oben „wer fuehrt" so gross, dass man es von
   der Bierbank aus sieht, unten „und wo stehe ich" klein, aber vollstaendig.

   Zweite links, Erste in der Mitte und hoeher, Dritter rechts -- die
   Anordnung, die jeder von jedem Siegerpodest kennt. Sie spart die Erklaerung:
   Man sieht, wer gewonnen hat, bevor man die Zahl gelesen hat. */
.podest-seite {
    display: grid;
    grid-template-rows: auto minmax(0, 1.4fr) minmax(0, 1fr);
    gap: 1rem;
    min-height: 0;
}

/* auto-flow statt fester Dreiteilung: Am fruehen Morgen steht vielleicht einer
   allein da, und dann soll das Podest eine Stufe haben statt zwei Luecken. */
.podest {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 1.5rem;
    align-items: end;
    min-height: 0;
}

.podest-platz {
    display: grid;
    justify-items: center;
    /* Oben im Block, nicht unten drin: Auf einem Siegerpodest steht man auf dem
       Sockel. So liegt der Erste auch wirklich am hoechsten im Bild. */
    align-content: start;
    gap: .2rem;
    padding: 1rem .75rem;
    border-radius: var(--trr-radius-sm);
    background: rgba(255, 255, 255, .08);
    min-height: 0;
    overflow: hidden;
}
/* Die Treppe entsteht ueber die Hoehe, nicht ueber Polster: Sonst bleibt ueber
   dem Podest ein totes Feld stehen, weil die Karten ihre Zeile nicht
   ausfuellen. Eins steht ganz, zwei und drei stufen sich darunter ab. */
.podest-platz.ist-rang-1 { background: rgba(242, 169, 59, .22); height: 100%; }
.podest-platz.ist-rang-2 { height: 82%; }
.podest-platz.ist-rang-3 { background: rgba(2, 176, 167, .16); height: 72%; }

.podest-platz .avatar { width: clamp(3rem, 7vh, 6rem); height: clamp(3rem, 7vh, 6rem); }
.podest-platz.ist-rang-1 .avatar { width: clamp(4rem, 10vh, 8.5rem); height: clamp(4rem, 10vh, 8.5rem); }

.podest-rang {
    font-size: clamp(1rem, 1.6vw, 1.5rem);
    font-weight: 700;
    color: var(--trr-ink-soft);
}
.podest-platz.ist-rang-1 .podest-rang { color: var(--trr-amber-500); }

.podest-name {
    font-weight: 600;
    text-align: center;
    font-size: clamp(1rem, 1.8vw, 1.75rem);
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.podest-platz.ist-rang-1 .podest-name { font-size: clamp(1.125rem, 2.4vw, 2.25rem); }

.podest-punkte {
    font-size: clamp(1.75rem, 4vw, 3.25rem);
    font-weight: 700;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
}
.podest-platz.ist-rang-1 .podest-punkte { font-size: clamp(2.25rem, 5.5vw, 4.5rem); }

.podest-meta { font-size: clamp(.75rem, 1vw, 1rem); color: var(--trr-ink-soft); }

/* Die Uebrigen: enger als eine Wertungsseite, und das ist Absicht. Diese
   Haelfte ist der Ueberblick, nicht das Kleingedruckte -- wer sich genau
   ansehen will, wartet auf seine Wertungsseite im Umlauf. */
.podest-rest {
    list-style: none; margin: 0; padding: 0;
    min-height: 0;
    display: grid;
    /* Zeilen so hoch wie ihr Inhalt, der Block dann mittig im Feld. Mit
       gestreckten Zeilen sassen bei fuenf Uebrigen fuenf fette Leerbalken da,
       weil sich jede Zeile auf eine Hoehe zog, die sie nicht fuellt. */
    grid-template-rows: repeat(var(--zeilen, 1), auto);
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    align-content: center;
    gap: .4vh .75rem;
    font-size: clamp(.9375rem, calc(26vh / var(--zeilen, 1) * .5), 1.75rem);
    overflow: hidden;
}

.podest-rest-zeile {
    display: grid;
    grid-template-columns: 2.2em minmax(0, 1fr) auto;
    align-items: center;
    gap: .5em;
    padding: .15em .5em;
    border-radius: var(--trr-radius-sm);
    background: rgba(28, 31, 37, .45);
    min-height: 0;
    overflow: hidden;
}
.podest-rest-platz { text-align: center; color: var(--trr-ink-soft); font-variant-numeric: tabular-nums; }
.podest-rest-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.podest-rest-punkte { font-weight: 700; font-variant-numeric: tabular-nums; }

.liga-punkte {
    font-size: 1.4em;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}


/* Der Film gehört hinter die Tafel -- ohne diese Zeile läge sie darunter.
   Und der Grund muss durchscheinen können, sonst wäre der Film umsonst. */
.tafel-buehne { position: relative; z-index: 1; background: transparent; }
.page-kiosk { background: var(--trr-cream); }

/* Die Tafeln bekommen einen eigenen, halbdurchsichtigen Grund: Weiße Schrift
   direkt auf bewegtem Bild ist je nach Bildinhalt lesbar oder nicht, und
   „je nach" reicht auf einem Monitor an einer Scheunenwand nicht. */
.tafel {
    padding: 1rem 1.25rem;
    border-radius: var(--trr-radius-sm);
    background: rgba(20, 22, 26, .72);
    /* Wie die Wertung: nur so hoch wie die Wand. Was nicht hineinpasst, bleibt
       im eigenen Rollbereich statt hinter dem Bildrand. */
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    min-height: 0;
}
.tafel .table-scroll { min-height: 0; overflow: auto; }


/* ==========================================================================
   Der Monitor

   Zwei Orte, ein Thema: die Wand selbst und die Fernbedienung im Manager.
   Sie stehen hier beieinander, weil man sie zusammen ändert -- wer ein
   fünftes Bild baut, braucht beides.
   ========================================================================== */

/* ------------------------------------------------------------- Die Wand */

/*
 * Der Kasten um das Bild. Er hat bewusst keine eigene Größe und keinen
 * Stapelkontext: Jede Szene bringt ihre eigene Höhe mit, und der
 * Hintergrundfilm liegt fest im Fenster. Ein z-index hier zöge ihn in einen
 * eigenen Kontext, und die Reihenfolge Film-unten-Inhalt-oben ginge verloren.
 */
.monitor {
    display: block;
}

/*
 * Das Netz ist weg -- sichtbar, aber leise.
 *
 * Eine Fehlermeldung an der Zeltwand hilft niemandem: Sie erklärt vierzig
 * Gästen ein Problem, das sie nicht lösen können. Ein sanftes Abdunkeln sagt
 * dem, der es wissen muss, genug -- und alle anderen sehen weiterhin ein
 * Bild, das nur alt ist und nicht falsch.
 */
.monitor.ist-abgehaengt {
    opacity: .78;
    transition: opacity 1.2s ease;
}

/* Der ausgeschaltete Monitor: nichts. Der Kasten muss trotzdem die Wand
   füllen -- sonst schiene die Grundfarbe des Layouts durch und die Seite
   sähe aus wie eine, die noch lädt. */
.monitor-aus {
    height: 100vh;
    background: #000;
}

/* ---------------------------------------------------------- Das Standbild */

.standbild {
    position: relative;
    z-index: 1;
    height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.4vh;
    padding: 4vh 6vw;
    text-align: center;
    color: #fff;
}

/* Die Marke bekommt hier die Fläche, für die sie entworfen wurde -- anders
   als auf der Renntafel, wo der Kopf flach bleiben muss. */
.standbild .brand { --brand-breite: 34vw; }

.standbild-logo {
    max-width: 34vw;
    max-height: 26vh;
    height: auto;
    width: auto;
}

.standbild-event {
    margin: 0;
    font-size: 2.2vw;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--trr-teal-800);
}

.standbild-titel {
    margin: 0;
    font-size: 6vw;
    line-height: 1.1;
    font-weight: 700;
    /* Wie bei den Cocktailnamen: lieber eine schmalere Zeile als ein Wort,
       das mittendrin aufbricht. Aus zehn Metern liest das niemand. */
    overflow-wrap: normal;
    word-break: keep-all;
    hyphens: none;
}

.standbild-zeile {
    margin: 0;
    font-size: 2.6vw;
    color: rgba(255, 255, 255, .82);
    max-width: 40ch;
}

/*
 * Drei Punkte, die nacheinander aufleuchten -- das einzige, was sich auf
 * diesem Bild bewegt. Ohne sie ist ein Standbild von einem eingefrorenen
 * Browser nicht zu unterscheiden, und genau das fragt am Eventtag jeder
 * Zweite.
 */
.standbild-puls {
    display: flex;
    gap: .9vw;
    margin-top: 2vh;
}

.standbild-puls span {
    width: .9vw;
    height: .9vw;
    min-width: 8px;
    min-height: 8px;
    border-radius: 50%;
    background: var(--trr-teal-500);
    opacity: .25;
    animation: standbild-puls 1.8s ease-in-out infinite;
}

.standbild-puls span:nth-child(2) { animation-delay: .3s; }
.standbild-puls span:nth-child(3) { animation-delay: .6s; }

@keyframes standbild-puls {
    0%, 70%, 100% { opacity: .25; }
    35%           { opacity: 1; }
}

/* Wer Bewegung abgestellt hat, bekommt drei ruhige Punkte. Sie sagen dann
   nichts mehr über das Leben der Seite -- aber ein Flimmern, das jemandem
   wehtut, wiegt schwerer als diese Auskunft. */
@media (prefers-reduced-motion: reduce) {
    .standbild-puls span { animation: none; opacity: .55; }
}

/* ---------------------------------------------- Die Fernbedienung im Manager */

/*
 * Die Adresse. Hier stand einmal ein QR-Code daneben, und dafuer war dies
 * ein Flex-Verbund -- der ist mit ihm entfallen: Die Adresse wandert per
 * Zwischenablage nach OBS, und dafuer hilft kein Quadrat aus Punkten.
 */
.monitor-adresse-text { min-width: 0; }

/*
 * Groesser als der uebliche Kleinkram und mit Luft darum: Sie ist das
 * Einzige auf dieser Seite, das man mit der Maus greift und kopiert. Bei
 * einer Zeile in Fussnotengroesse trifft man beim Markieren die Zeile
 * darueber.
 */
.monitor-adresse-link {
    margin: 0 0 .75rem;
    padding: .6rem .8rem;
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .9375rem;

    /* Sie ist lang und hat keine Leerzeichen. Ohne das bricht sie nicht und
       schiebt die Karte auf dem Telefon auseinander. */
    overflow-wrap: anywhere;
}

/*
 * Vier Kacheln, und jede ist als Ganzes der Knopf.
 *
 * Bedient wird im Stehen, mit dem Telefon in einer Hand -- ein Ziel von der
 * Größe eines Wortes trifft man dann nicht. Deshalb keine Auswahlliste mit
 * einem Speichern-Knopf darunter: Das wären zwei Handlungen für einen
 * Gedanken, und die zweite vergisst man vor Publikum.
 */
/*
 * Die Sprungmarken der beiden Knopfgruppen.
 *
 * Jeder Knopf hier schickt ab und laedt neu; ohne Anker setzte der Browser
 * die Seite oben an, und man rollte nach jedem Klick wieder herunter. Der
 * Abstand nach oben ist derselbe wie bei den Buchungszeilen: Die
 * Navigationsleiste steht fest ueber der Seite, und ohne ihn schoebe der
 * Browser das Ziel genau dorthin, wo es verdeckt ist.
 */
.monitor-szenen[id],
.monitor-verlesen[id] {
    scroll-margin-top: calc(var(--nav-hoehe) + 1rem);
}

/*
 * Waehrend ein Klick unterwegs ist.
 *
 * Nur ein Hauch: Der Weg zum Server und zurueck dauert auf einem Telefon im
 * Zelt einen Wimpernschlag, und ein Ladebalken dafuer waere mehr Unruhe als
 * Auskunft. Es geht allein darum, dass der Knopf den Druck quittiert --
 * sonst tippt man im Zweifel ein zweites Mal.
 */
[data-steuerung] { transition: opacity .12s ease; }
[data-steuerung].ist-unterwegs { opacity: .6; }

.monitor-szenen {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: .75rem;
    margin-top: 1rem;
}

.monitor-szene { margin: 0; display: flex; }

.monitor-szene-knopf {
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto auto;
    column-gap: .7rem;
    row-gap: .2rem;
    align-items: center;
    text-align: left;
    padding: .9rem 1rem;
    border: 1px solid var(--trr-line);
    border-radius: var(--trr-radius-sm);
    background: var(--trr-row);
    color: var(--trr-ink);
    cursor: pointer;
}

.monitor-szene-knopf:hover:not(:disabled) { border-color: var(--trr-teal-600); }
.monitor-szene-knopf:disabled { opacity: .45; cursor: not-allowed; }

.monitor-szene-icon {
    grid-row: 1 / span 2;
    width: 1.9rem;
    height: 1.9rem;
    color: var(--trr-teal-500);
}

.monitor-szene-name { font-weight: 600; }

.monitor-szene-satz {
    grid-column: 2;
    font-size: .85rem;
    color: var(--trr-ink-soft);
}

/* Was läuft, trägt den Markenton als Rahmen und ein Wort dazu. Nur die Farbe
   wäre zu wenig -- sie ist bei einem Blick aufs Telefon in der Sonne kaum zu
   sehen, und wer das falsche Bild schaltet, merkt es erst an der Wand. */
.monitor-szene.ist-da .monitor-szene-knopf {
    border-color: var(--trr-teal-500);
    box-shadow: inset 0 0 0 1px var(--trr-teal-500);
}

.monitor-szene-marke {
    grid-column: 2;
    justify-self: start;
    margin-top: .35rem;
    padding: .1rem .5rem;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    background: var(--trr-teal-500);
    color: var(--trr-on-primary);
}

/* ------------------------------------------------------- Die Siegerehrung */

/*
 * Das Ergebnis steht hier im Klartext -- also zugeklappt.
 *
 * An dieser Seite kommt man nicht vorbei: Sie ist auch der Weg von der
 * Cocktailkarte zum Standbild. Ein Blick ueber die Schulter reicht sonst,
 * und der Abend ist verdorben. Aufgeklappt ist sie nur, waehrend die Ehrung
 * ohnehin auf der Wand steht -- dann schaut niemand mehr auf dieses Telefon.
 */
.monitor-verlesen { margin: 1rem 0; }

.monitor-verlesen-kopf {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    border: 1px dashed var(--trr-line);
    border-radius: var(--trr-radius-sm);
    color: var(--trr-ink-soft);
    font-size: .9375rem;
    cursor: pointer;
    list-style: none;
}

/* Das eigene Dreieck weg -- Safari zeichnet es ueber ein anderes Pseudo-
   Element als der Rest, deshalb beide. */
.monitor-verlesen-kopf::-webkit-details-marker { display: none; }
.monitor-verlesen-kopf::marker { content: ''; }

/* Das Zeichen davor: zu heisst zugedeckt, offen heisst offen. Es dreht sich
   nicht, es wechselt -- ein Dreieck sagt "mehr davon", hier geht es aber um
   verdeckt oder nicht. */
.monitor-verlesen-kopf::before {
    content: '\2022\2022\2022';
    letter-spacing: .1em;
    color: var(--trr-ink-quiet);
}

.monitor-verlesen[open] > .monitor-verlesen-kopf {
    border-style: solid;
    color: var(--trr-ink);
}

.monitor-verlesen[open] > .monitor-verlesen-kopf::before { content: ''; }

.monitor-stufen {
    list-style: none;
    margin: 1rem 0;
    padding: 0;
    display: grid;
    gap: .35rem;
}

.monitor-stufe {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem .75rem;
    align-items: baseline;
    padding: .5rem .75rem;
    border-left: 3px solid var(--trr-line);
    border-radius: 0 var(--trr-radius-sm) var(--trr-radius-sm) 0;
    background: var(--trr-row);
}

.monitor-stufe-kopf { font-weight: 600; min-width: 8rem; }
.monitor-stufe-wer { color: var(--trr-ink-soft); }

/* Was verlesen ist, tritt zurück; was als Nächstes kommt, steht hervor. Das
   ist die einzige Frage, die man vor diesem Knopf hat. */
.monitor-stufe.ist-durch { opacity: .55; border-left-color: var(--trr-teal-500); }

.monitor-stufe.ist-naechste {
    border-left-color: var(--trr-amber-500);
    background: var(--trr-paper);
}

.monitor-stufe.ist-naechste .monitor-stufe-wer { color: var(--trr-ink); }

.monitor-takt {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: stretch;
}

.monitor-takt form { margin: 0; }

/* Der breiteste Knopf des Portals. Fünfmal am Abend, vor vierzig Leuten --
   er muss jedes Mal sitzen, auch mit dem Daumen und ohne hinzusehen. */
.monitor-takt form:first-child { flex: 1 1 16rem; }
.monitor-weiter { width: 100%; min-height: 3.5rem; }


/* ==========================================================================
   Die Erklaerung hinter dem „i"
   ==========================================================================
   Ein kleines Zeichen neben der Beschriftung, kein Knopf im Wortsinn: Es soll
   erreichbar sein und sonst nichts von der Aufmerksamkeit nehmen, die dem
   Feld gehoert.

   Deshalb in der gedaempften Schriftfarbe und erst beim Darueberfahren im
   Markenton -- wer es sucht, findet es; wer es nicht braucht, sieht es kaum.
   ========================================================================== */
.feld-hilfe {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.125rem;
    height: 1.125rem;
    margin-left: .375rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--trr-ink-soft);
    vertical-align: baseline;
    cursor: help;
}

.feld-hilfe:hover,
.feld-hilfe:focus-visible { color: var(--trr-teal-700); }

.feld-hilfe-zeichen {
    width: 1.125rem;
    height: 1.125rem;
}


/* ==========================================================================
   Die Grunddaten: ein Raster, das nicht raten muss
   ==========================================================================
   Die drei Karten sind voneinander unabhaengig und verschieden lang. Vorher
   standen sie in einer Rasterreihe mit gleicher Hoehe -- alle bekamen die
   Hoehe der laengsten, und die kuerzeste stand zu zwei Dritteln leer.

   Dann kam column-count, und das war der zweite Fehlgriff: Mehrspalten
   verteilen den Inhalt selbst, und wenn der Browser sich gegen ein Umbrechen
   entscheidet, steht alles in der ersten Spalte und die zweite bleibt leer.
   Genau das ist Marcel am 30.08.2026 passiert -- bei mir sah dieselbe Seite
   anders aus als bei ihm, was fuer sich schon das Urteil ueber das Verfahren
   ist.

   Jetzt ein Raster mit fester Spaltenzahl: Karte eins nach links, zwei in die
   Mitte, drei nach rechts. Da ist nichts zu balancieren und nichts zu raten.

   align-items: start ist der ganze Trick gegen den alten Leerraum: Ohne die
   Zeile zieht das Raster jede Karte auf die Hoehe der hoechsten, und wir
   waeren wieder bei h-100.
   ========================================================================== */
.grunddaten-spalten {
    display: grid;
    gap: 1.5rem;
    align-items: start;
}

/* Unter 62em untereinander: Nebeneinander waeren die Felder schmaler als ihre
   Beschriftung. */
@media (min-width: 62em) {
    .grunddaten-spalten { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Drei Spalten waren einmal drin. Sie fuellten die Breite, aber jede Karte
   wurde so schmal, dass die Beschriftungen umbrachen -- und "Wann" und
   "Anmeldeschluss" standen als zwei duenne Streifen nebeneinander, obwohl
   sie dasselbe Thema sind. Jetzt zwei Karten: links die Termine, rechts die
   Teilnahme. */

/* Eine Zwischenueberschrift in einer Karte -- fuer zwei Themen unter einem
   Dach ("Anmeldeschluss" in den Terminen, "Mindestanzahl" bei der
   Teilnahme). Mit Luft darueber, damit sie als Schnitt zu lesen ist und
   nicht als Beschriftung des naechsten Feldes. */
.grunddaten-untertitel {
    margin: 1.75rem 0 .75rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--trr-line);
}

/* Die erste Zwischenueberschrift braucht keinen Strich nach oben: Darueber
   steht der Kartentitel, und zwei Trenner uebereinander sind einer zu viel. */
.grunddaten-untertitel-erster {
    margin-top: .25rem;
    padding-top: 0;
    border-top: 0;
}

/* Zahlenfelder nebeneinander.
   ----------------------------------------------------------------------
   Drei zweistellige Zahlen brauchen keine drei vollen Zeilen. Gleich breit
   und nicht nach Inhalt: Es sind dieselben Angaben zu drei Zeitpunkten, und
   ungleiche Breiten liessen eine wichtiger aussehen als die andere. */
/* ==========================================================================
   Die Titelbilder: drei gleichwertige Spalten
   ==========================================================================
   Dieselbe Machart wie bei den Grunddaten, und aus demselben Grund: feste
   Spaltenzahl statt Balancieren, und align-items: start, damit keine Karte auf
   die Hoehe der hoechsten gezogen wird.

   Die Sammlung links bekommt mehr Platz -- sie zeigt Bilder und waechst mit
   jedem Event, die beiden Schalter daneben sind je eine Frage mit einer
   Antwort.
   ========================================================================== */
.bilder-spalten {
    display: grid;
    gap: 1.5rem;
    align-items: start;
}

@media (min-width: 62em) {
    .bilder-spalten { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
}

@media (min-width: 87.5em) {
    .bilder-spalten { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); }
}

/* Name und Untertitel nebeneinander. Der Name bekommt mehr: Er ist die
   laengere Angabe ("9. Rasenmaehertraktorrallyemeisterschaft") und die
   wichtigere. */
.namensreihe { display: grid; gap: 1rem; }

@media (min-width: 48em) {
    .namensreihe { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
}

.zahlenreihe {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .75rem;
}



/* ==========================================================================
   Ein Textfeld, das gross werden darf
   ==========================================================================
   Im Ruhezustand ein Ausschnitt von vier Zeilen mit einem Knopf darunter.
   Aufgeklappt legt sich die Huelle als Flaeche ueber die Seite, und das Feld
   fuellt sie -- geschrieben wird dann im Ganzen.

   Das Feld wandert dabei nicht: Es bleibt im Formular stehen, nur seine Huelle
   wechselt die Position. Siehe app.js, dort steht, warum das hier wichtiger
   ist als anderswo.
   ========================================================================== */
.feld-gross { position: relative; }

.feld-gross .feld-gross-zu { display: none; }

.feld-gross .feld-gross-auf { margin-top: .5rem; }

.feld-gross.ist-gross {
    position: fixed;
    inset: 0;
    z-index: 1080;

    display: flex;
    flex-direction: column;
    gap: .75rem;
    padding: clamp(1rem, 4vw, 3rem);

    background: var(--trr-cream);
}

/* Aufgeklappt fuellt das Feld die Flaeche -- rows zaehlt dann nicht mehr. */
.feld-gross.ist-gross textarea {
    flex: 1 1 auto;
    min-height: 0;
    resize: none;
}

.feld-gross.ist-gross .feld-gross-auf { display: none; }

.feld-gross.ist-gross .feld-gross-zu {
    display: inline-block;
    align-self: flex-end;
    margin: 0;
}

/* Die Seite darunter soll nicht mitscrollen, solange oben geschrieben wird. */
body.hat-grosses-feld { overflow: hidden; }
