/*
 * tableroom — das Stilblatt des Foyers.
 *
 * EIGENER NAMENSRAUM, UND DAS IST KEINE FOERMLICHKEIT. Alle Farben und Masse
 * stehen als `--hub-*`, alle Klassen beginnen mit `hub-`. Das Spiel unter
 * /games/hardcover/ fuehrt `--bm-*` und rund vierhundertsiebzig eigene
 * Klassennamen; der Tresen bekommt spaeter `--tr-*`. Ein doppelt vergebener
 * Name faerbt lautlos eine Flaeche mit, die niemand angefasst hat – und kein
 * Lauf meldet es.
 *
 * DAS FOYER IST NICHT DER COMIC-NOIR VON FALL 01. Es spricht nicht IN einer
 * Welt, sondern UEBER Welten: Naturpapier, Tinte, ein Akzent je Kachel, und
 * dann hoert es auf zu gestalten.
 *
 * ES WAR BIS ZUM UMBAU BLECH, und das war eine Entscheidung, die sich beim
 * Messen als falsch herausgestellt hat: Auf 2560 Pixeln stand ein dunkler
 * Streifen von 1536 Pixeln in einem dunklen Fenster. Die Begruendung und die
 * Grenze stehen in CLAUDE.md, Abschnitt 7 ("Das Haus ist hell, die Zimmer
 * sind Nacht"); kurz: Hinter jeder Tuer dieses Foyers ist es weiterhin Nacht.
 *
 * WAS ES MIT DEN SPIELEN TEILT, IST DIE HANDSCHRIFT UND NICHT DIE PALETTE —
 * und seit dem Umbau auch die Handschrift nur noch zur Haelfte: kein Glow,
 * keine Verlaufsflaechen, Uebergaenge linear und hoechstens 120 ms, das gilt
 * weiter. Rundung und Schatten gibt es hier, im Zimmer nicht; der Grund steht
 * beim Token --hub-radius-m.
 *
 * Verlaeufe gibt es an genau drei Stellen: als Vignette ueber einem Bild, als
 * Halbtonraster und seit dem Breitbild-Feinschliff als Flanke neben der Buehne
 * (--hub-flanke). Alle drei sind Textur, keine Flaeche — und die dritte traegt
 * ausdruecklich nie eine Zeile Text.
 */

:root {
    /*
     * EIN MODUS, UND DER IST JETZT TAG — IM FOYER, NIRGENDWO SONST.
     *
     * Hier stand "color-scheme: dark" mit der Begruendung, ein Foyer bei Tag,
     * hinter dessen Tueren jedes Zimmer Nacht ist, sei ein Bruch im Uebergang.
     * Der Satz hat acht Monate gehalten und einen Fall nicht bedacht: Das
     * Foyer ist gar kein Vorzimmer der Zimmer, es ist der Katalog UEBER sie.
     * Dieselbe Grenze, die in CLAUDE.md Abschnitt 6 die Stimme trennt — der
     * Bestand spricht Noir, weil er IN einer Welt spielt; das Foyer spricht
     * UEBER Welten.
     *
     * Gemessen war der Bruch ausserdem umgekehrt: Auf 2560 Pixeln stand ein
     * dunkler Streifen von 1536 Pixeln in einem dunklen Fenster, und niemand
     * sah, wo die Seite anfing.
     *
     * DIE NACHT BLEIBT, WO SIE ETWAS BEDEUTET. Das Kino (--hub-kino*) kippt
     * nicht mit: Ein Filmbild ist dunkel, bei Tag wie bei Nacht. Und hinter
     * jeder Tuer dieses Foyers ist es weiterhin Nacht, woertlich wie in
     * CLAUDE.md Abschnitt 7.
     *
     * DIE PALETTE IST DIESELBE WIE IM RAHMEN (shared/haus/haus.css) — nicht
     * dieselben Tokens, aber dieselben Werte. Zwei Namensraeume, weil der
     * Rahmen in drei Haeusern liegt und das Foyer in einem; gleiche Zahlen,
     * damit die Naht zwischen Leiste und Seite keine ist. Wer eine Farbe hier
     * aendert, aendert sie dort mit.
     */
    color-scheme: light;

    /* --- Grund: Naturpapier ------------------------------------------ */
    --hub-grund: #fbf9f5;
    --hub-grund-karte: #ffffff;
    --hub-grund-subtil: #f4efe4;

    /*
     * DREI KANTEN, UND NUR EINE DAVON DARF EIN BEDIENELEMENT BEGRENZEN — die
     * ausfuehrliche Begruendung steht im Rahmen (shared/haus/haus.css, beim
     * Kantenblock). Kurz: WCAG 1.4.11 verlangt 3,0:1 fuer Nichttext, das gilt
     * fuer die Kante eines Knopfes und nicht fuer einen Spaltentrenner.
     *
     *   --hub-kante        1,31:1  Haarlinie. Karten, Trennungen, Zierrat.
     *   --hub-kante-stark  1,76:1  sichtbare Zaesur.
     *   --hub-kante-griff  3,06:1  Felder, Knoepfe, alles zum Anfassen.
     */
    --hub-kante: #e2dbce;
    --hub-kante-stark: #c5beaf;
    --hub-kante-griff: #8f887c;

    /* --- Tinte -------------------------------------------------------- */
    --hub-tinte: #141416; /* 17,50:1 auf --hub-grund */
    --hub-tinte-sekundaer: #4a4740; /* 8,81:1 auf --hub-grund */
    --hub-tinte-gedaempft: #6f6b62; /* 5,05:1 auf --hub-grund, 4,63:1 auf --hub-grund-subtil */

    /* --- Signal ------------------------------------------------------- */
    --hub-signal: #c43826;
    /*
     * DAS MESSING DES BRETTSPIELS — der Akzent der dritten Säule auf der Weiche.
     *
     * Er ist der einzige Akzent dieses Foyers, der weder aus der Kartei kommt
     * (`spiele.akzent`) noch das Signal des Hauses ist, und er steht da, weil
     * beide Nachbarn auf der Weiche dasselbe Zinnober führen: Fall 01 aus der
     * Kartei, die Arena aus `--hub-signal`. Drei gleich rote Oberkanten lesen
     * sich als ein Block und nicht als drei Wege.
     *
     * Die Zahl ist das Holz seines eigenen Bretts (`--ak-holz-hell` in
     * `public/games/archiv/css/archiv.css`) — kein neuer Ton, sondern derselbe,
     * den man einen Klick weiter wiedersieht. Auf --hub-grund-karte hält er
     * 5,41:1 als Kante; die daraus gemischte Schrift (`--hub-akzent-schrift`)
     * hält 7,76:1.
     */
    --hub-messing: #8a6238;
    /*
     * DAS WARME MESSING DES SOLO-KNOPFES („Allein zocken“) — eine FLAECHE unter dunkler Tinte, und deshalb heller als
     * das Messing oben, das als Kante und Schrift auf Papier steht. Tinte darauf haelt 8,8:1. Gegen das Papier ist die
     * Flaeche allein nur 2,0:1, und darum traegt der Knopf ausserdem die dunkle Kante (`--hub-messing`, 5,4:1): WCAG
     * 1.4.11 verlangt fuer ein Bedienelement 3,0 gegen seinen Grund, und die Kante ist es, die ihn als Knopf ausweist.
     */
    --hub-messing-hell: #e0a96d;
    /* Wird je Kachel per style-Attribut aus "spiele.akzent" gesetzt. */
    --hub-akzent: #c43826;

    /*
     * DER STERN EINER WERTUNG - und er haengt ausdruecklich NICHT an
     * --hub-akzent.
     *
     * Der wird je Kachel aus `spiele.akzent` ueberschrieben: Sterne daran
     * gehaengt waeren auf der einen Kachel rot, auf der naechsten gruen und
     * auf der dritten grau. Eine Wertung ist in jedem Regal dieselbe Sache.
     *
     * ER IST DUNKLER ALS DAS GELB DER ZIMMER, UND DAS IST EINE RECHNUNG.
     * --bm-mustard/--wr-bernstein (#d9a521) halten auf Weiss 2,24:1 - unter
     * den 3,0, die WCAG 1.4.11 fuer Nichttext verlangt. Auf Blech ist das
     * richtig, auf Papier nicht. Dieser Ton haelt 3,91:1 auf
     * --hub-grund-karte und 3,72:1 auf --hub-grund.
     *
     * DER LEERE STERN NIMMT --hub-kante-griff (3,51:1) - denselben Ton wie
     * jede andere Kontur, die etwas aussagt.
     */
    --hub-stern: #a8781a;

    /*
     * DER AKZENT HAT ZWEI AUFGABEN, UND DIE ZWEITE KIPPT MIT DEM GRUND.
     *
     * Als FLAECHE steht er unter heller Schrift (der Tuerknopf) und braucht
     * seine Tiefe. Als SCHRIFT stand er bis hierher auf Blech und musste
     * AUFGEHELLT werden; auf Papier ist es genau umgekehrt — er muss
     * ABGEDUNKELT werden. Die Mischung ist deshalb von "62 % Akzent auf
     * Papier" auf "78 % Akzent auf Schwarz" gedreht.
     *
     * Gerechnet fuer alle drei heutigen Faelle gegen --hub-grund:
     *   #b03a2e (Fall 01) -> #892d24   8,08:1
     *   #2e8b6b (Fall 02) -> #246c53   5,94:1
     *   #78838d (Fall 03) -> #5e666e   5,54:1
     *
     * DIE ZEILE DARUEBER IST DER RUECKFALL fuer Browser ohne color-mix. Sie
     * faellt auf eine Farbe zurueck, nicht auf Unlesbarkeit — und sie ist
     * jetzt die SEKUNDAERE TINTE und nicht mehr ein gedaempftes Papier: Auf
     * hellem Grund waere ein helles Grau der Rueckfall in die Unsichtbarkeit.
     */
    --hub-akzent-schrift: var(--hub-tinte-sekundaer);
    --hub-akzent-schrift: color-mix(in srgb, var(--hub-akzent) 78%, #000);
    /*
     * EIN HAUCH AKZENT ALS GRUND, fuer einen Kasten, der hervortreten soll, ohne laut zu werden (der Fakt eines
     * Magazinartikels). Tinte haelt darauf 16,6:1, die Akzentschrift 6,9:1. Der Rueckfall ist der subtile Grund.
     */
    --hub-akzent-hauch: var(--hub-grund-subtil);
    --hub-akzent-hauch: color-mix(in srgb, var(--hub-akzent) 7%, var(--hub-grund-karte));

    /*
     * DAS GRUEN VON WHATSAPP, nur am Knopf „Auf WhatsApp teilen“: eine FLAECHE unter Tinte (9,3:1) und eine tiefe Kante,
     * die den Knopf gegen das Papier ausweist und im Hover zur Flaeche unter Weiss wird. Es ist die Farbe des Dienstes,
     * den der Knopf aufruft, und keine Farbe dieses Hauses — sie steht an keiner anderen Stelle.
     */
    --hub-whatsapp: #25d366;
    --hub-whatsapp-tief: #0a6b3d;

    /*
     * --- Das Kino, und es KIPPT NICHT MIT DEM MODUS ------------------
     *
     * Der Aufmacher ist ein Filmbild, und ein Filmbild ist dunkel — bei Tag
     * wie bei Nacht. Diese Toene stehen deshalb nur hier und werden vom hellen
     * Grund NICHT beruehrt. Sie sind zugleich der Monolith des Aufmachers: der
     * dunkle Kasten rechts, in dem der Film und die vier Daten stehen.
     *
     * Es sind dieselben Werte wie im Sockel des Hauses (--haus-kontrast-*),
     * und das ist Absicht: Der Fuss und der Monolith sind dieselbe Flaeche,
     * einmal unten und einmal rechts.
     */
    --hub-kino: #121214;
    --hub-kino-karte: #1a1a1e;
    --hub-kino-text: #f5f4f0; /* 17,00:1 auf --hub-kino */
    --hub-kino-still: #9b988f; /* 6,49:1 auf --hub-kino */
    --hub-kino-kante: rgba(255, 255, 255, 0.12);

    /*
     * --- Die Bildunterschrift unter einem Panel ----------------------
     *
     * Derselbe Kasten wie in beiden Zimmern und in der Arena: Papier,
     * Goldkante oben, Serife (CLAUDE.md, Abschnitt 7). Im Foyer steht er auf
     * der Seite eines Tisches, unter den drei Panels seiner Geschichte.
     * --hub-tinte haelt darauf 14,29:1. Die Goldkante ist Praegung und keine
     * Auskunft; gemessen wird sie gegen den Grund, auf dem sie liegt —
     * 5,86:1 auf --hub-kino —, und nicht gegen ihr Papier.
     */
    --hub-comic-papier: #ede2c8;
    --hub-gold: #b4893a; /* NUR als Linie von 2 px, nie als Flaeche */

    /* --- Textur ------------------------------------------------------ */
    --hub-halbton-size: 6px;
    --hub-halbton: #00000026;
    --hub-vignette: rgba(0, 0, 0, 0.55);
    /*
     * DIE FLANKE AUF DEM BREITBILD.
     *
     * Die Buehne ist bei --hub-shell gedeckelt, und auf einem Schirm von 2560
     * Pixeln bleiben daneben 380 Pixel Naturpapier je Seite stehen: dieselbe
     * Flaeche, dieselbe Koernung, keine Kante. Das Blatt schwimmt darin, statt
     * darauf zu liegen.
     *
     * SIE IST EINE VIGNETTE UND KEINE FLAECHE, und genau deshalb ist sie
     * erlaubt: Die eisernen Verbote schliessen Verlaeufe ALS FLAECHE aus und
     * lassen sie ausdruecklich fuer Vignette, Halbtonraster und Korn zu. Sie
     * faengt dort an, wo die Buehne aufhoert, und traegt deshalb nie eine Zeile
     * Text — ein Weichzeichner oder ein Schatten waeren der andere, verbotene
     * Weg (der Weichzeichner gehoert allein der klebenden Kopfleiste).
     *
     * 0,06 SIND KNAPP VIER PROZENT WEG VOM PAPIER. Gemessen an der aeussersten
     * Kante: #fbf9f5 wird zu #f0eeea. Mehr waere ein Rahmen, weniger waere
     * nichts.
     */
    --hub-flanke: rgba(20, 20, 22, 0.06);
    /*
     * DAS FELD IST JETZT EINE FLAECHE UND KEIN LOCH. Es stand auf
     * "rgba(0,0,0,0.3)" — eine Vertiefung, richtig auf Blech. Auf Papier ist
     * ein Eingabefeld eine leichte Tuchung, mit einer Kante, die man sieht
     * (--hub-kante-griff: 3,06:1 darauf, 3,51:1 gegen Weiss).
     *
     * ES IST DER SUBTILE GRUND UND NICHT WEISS, weil ein Feld fast immer auf
     * einer weissen KARTE liegt: Weiss auf Weiss haelt 1,00:1, und dann traegt
     * die Kante das Feld ganz allein. Tinte darauf steht bei 16,04:1.
     *
     * Und es ist ein Verweis und keine zweite getippte Farbe — ein Token, das
     * nur ein anderes wiederholt, laeuft beim naechsten Umbau still
     * auseinander.
     */
    --hub-feld-grund: var(--hub-grund-subtil);
    /* Der Schleier unter dem Spielknopf auf dem Filmbild. Er bleibt dunkel:
       Er liegt auf dem Bild und nicht auf der Seite. */
    --hub-kino-schleier: rgba(18, 18, 20, 0.78);
    /* Die Aufschrift auf dem Tuerknopf — sie liegt auf einer Farbflaeche und
       nicht auf Papier. */
    --hub-knopf-schrift: #ffffff;
    /*
     * DAS KORN BLEIBT, UND ES IST AUF PAPIER MEHR WERT ALS AUF BLECH: Eine
     * grosse helle Flaeche ohne Struktur sieht nach Bildschirm aus, eine mit
     * Struktur nach Papier. Die Deckung faellt von 0,12 auf 0,05 — dasselbe
     * Rauschen liest sich auf hellem Grund deutlich lauter.
     */
    --hub-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)' opacity='0.05'/%3E%3C/svg%3E");

    /* --- Masse ------------------------------------------------------- */
    /*
     * DREI BREITEN, UND SIE WIDERSPRECHEN EINANDER — so wie im Spiel nebenan.
     *
     * "--hub-shell" ist die Buehnenbreite: Regal, Kopf, Fuss nutzen sie ganz.
     * Sie stand auf 96rem (1536 px) mit der Begruendung, ab etwa 1700 Pixeln
     * wandere der Blick beim Zeilenwechsel zu weit. Das stimmt fuer eine
     * TEXTSPALTE und war nie das Mass dieser Zahl — auf der Buehne stehen
     * Kacheln und Karten, nicht Zeilen. Was Saetze traegt, hat sein eigenes
     * Mass, und das ist genau der Unterschied.
     *
     * SIE IST DIESELBE ZAHL WIE --haus-shell, --bm-akte UND --wr-akte. Wer
     * eine davon anfasst, fasst alle an: Sonst springt die Wortmarke beim
     * Betreten eines Zimmers wieder zur Seite.
     *
     * "--hub-mass" ist das Zeilenmass und gilt fuer alles, was SAETZE traegt.
     * "--hub-hero-mass" ist die dritte Breite und keine Laune: Grosse Schrift
     * braucht mehr Spalte fuer dieselbe Zeilenlaenge.
     */
    --hub-shell: 1800px;
    --hub-mass: 68ch;
    /*
     * DIE SCHLAGZEILE ZERRISS "Online-Escape-Games" AM BINDESTRICH.
     *
     * Auf 46rem stand sie in drei Zeilen, und die zweite endete auf
     * "Kooperative Online-": Fuer CSS ist ein Bindestrich eine
     * Umbruchgelegenheit, und die Gattungsangabe, wegen der diese Zeile
     * ueberhaupt so heisst (Abschnitt 9: "Wer ein Escape Game sucht, sucht
     * keine Buchmafia"), zerfiel dabei in zwei Haelften. Gemessen faellt sie
     * ab 52rem auf zwei Zeilen, und die Gattungsangabe steht ganz in der
     * zweiten.
     */
    --hub-hero-mass: 52rem;
    /*
     * Die Breite des Code-Terminals auf /tisch. Es ist kein Text, sondern ein
     * Geraet mit einem Feld darin – und ein Feld fuer fuenf Zeichen ueber
     * achtzig Rem sieht aus, als fehle etwas daneben.
     */
    --hub-terminal-mass: 36rem;
    /*
     * DER AUSSENABSTAND WAECHST MIT, und zwar hier und nicht in jeder Regel.
     * Er war bei 2,25rem gedeckelt — auf 2560 Pixeln derselbe Daumenbreit wie
     * auf einem Laptop. Dieselbe Zahl wie --haus-luft im Rahmen.
     */
    --hub-luft: clamp(1.15rem, 2.6vw, 3.5rem);
    --hub-spalt: clamp(1.5rem, 3vw, 3.5rem);
    --hub-griff: 44px;
    /*
     * DAS GRUNDZEICHEN IN DER ECKE EINER KARTE, und es ist ein Schwund und
     * kein Weichzeichner. Ein Piktogramm darf hier stehen, weil es KEINE
     * Auskunft traegt – darueber steht das Wort, das es meint.
     *
     * AUF PAPIER MUSS ES LEISER SEIN. 0,1 Deckung schwarzer Tinte auf einem
     * hellen Blatt ist deutlich lauter als dieselbe Zahl heller Tinte auf
     * Blech; 0,05 ist der Wert, bei dem es wieder ein Wasserzeichen ist.
     */
    --hub-zeichen-schwund: 0.05;
    --hub-zeichen-gross: 7.5rem;
    /*
     * DIE KANTENSTAERKE FIEL VON DREI AUF EINS.
     *
     * Drei Pixel sind eine Comic-Kante — richtig in einem Zimmer, wo jede
     * Flaeche eine Zeichnung ist. Auf Naturpapier ist eine Karte mit drei
     * Pixeln Rand ein Kasten; was sie traegt, ist ein Haar und ein Schatten.
     * Der FOKUSRING behaelt seine drei Pixel: Er ist kein Rand, sondern ein
     * Signal, und WCAG 2.4.11 verlangt dort Sichtbarkeit.
     */
    --hub-border: 1px;
    --hub-ring: 3px;
    --hub-radius-m: 8px;
    --hub-radius-l: 12px;
    --hub-schatten-karte: 0 4px 20px rgba(20, 20, 22, 0.05), 0 1px 3px rgba(20, 20, 22, 0.03);
    --hub-schatten-schwebend: 0 16px 36px rgba(20, 20, 22, 0.08);
    --hub-gap-1: 0.35rem;
    --hub-gap-2: 0.7rem;
    --hub-gap-3: 1.15rem;
    --hub-gap-4: 1.9rem;
    --hub-gap-5: 3rem;
    --hub-tracking: 0.08em;

    /*
     * EINE EBENE, UND DAS IST DER REST VON DREIEN.
     *
     * Hier standen "--hub-glas", "--hub-glas-kante", "--hub-glas-blur" und
     * "--hub-ebene-kopf" — Rueckstaende der Glasleiste, die nach
     * shared/haus/haus.css umgezogen ist. Kein var() im ganzen Haus hat sie
     * noch gelesen. Der Sprunglink liegt UEBER dem Kopf (dessen Ebene 900
     * ist): Ein klebender Kopf haette ihn sonst verdeckt, und der erste
     * Tastendruck auf einer Seite haette ins Nichts fokussiert.
     */
    --hub-ebene-sprung: 910;

    /* --- Schrift ----------------------------------------------------- */
    /* KEINE WEBSCHRIFT. Das Foyer laedt keine Datei fuer Buchstaben – weder
       von einem fremden Server noch vom eigenen. Was hier steht, steht in
       dem, was auf dem Geraet ohnehin liegt; die Handschrift macht der Satz
       und nicht die Familie. */
    --hub-font-text: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --hub-font-doc: ui-monospace, 'Cascadia Mono', 'Segoe UI Mono', 'Courier New', monospace;
    --hub-font-zahl: var(--hub-font-doc);
    /* Ohne Anfuehrungszeichen: Georgia ist eine Systemschrift und keine Datei, die jemand ausliefern muesste. */
    --hub-font-comic: Georgia, Times, serif;

    /* --- Bewegung ---------------------------------------------------- */
    --hub-schnell: 90ms linear;
}

/* ------------------------------------------------------------ Grundlage */

/*
 * DIE NULL IST JETZT EIN NORMALISIERER UND KEIN BEKENNTNIS.
 *
 * Hier stand "Ausnahmslos: Das Haus hat harte Kanten", und das gilt woertlich
 * weiter fuer jedes ZIMMER (CLAUDE.md, Abschnitt 7). Das Foyer ist kein
 * Zimmer: Es zeigt kein Bild, es ist Moebel — die Begruendung steht im Rahmen
 * bei --haus-radius-m. Was diese Regel noch tut, ist die Vorgaberundung der
 * Browser an Knoepfen und Feldern wegzuraeumen; wo eine Rundung hingehoert,
 * steht sie an ihrer Klasse und gewinnt gegen den Universalselektor ohnehin.
 */
*,
*::before,
*::after {
    box-sizing: border-box;
    border-radius: 0;
}

/*
 * `hidden` SCHLAEGT JEDE ANZEIGEART, und diese Zeile ist teuer erkauft.
 *
 * Das Attribut wirkt nur ueber `display: none` aus dem Vorgabestilblatt des
 * Browsers — und JEDE eigene Regel mit einem `display` gewinnt dagegen, weil
 * sie spezifischer ist. Das erste Blatt der Buehne traegt `display: grid`, und
 * damit standen beide Blaetter gleichzeitig da: das Werteversprechen des Hauses
 * und der Werbefilm zu Fall 02 untereinander, also genau der Zustand, gegen den
 * die Reiter gebaut wurden. Kein Lauf haette das gemeldet — gesehen hat es ein
 * Blick auf den fertigen Schirm.
 *
 * Das `!important` ist hier kein Notnagel, sondern die Aussage selbst: Was
 * versteckt ist, ist versteckt. Denselben Riegel fuehren die base.css beider
 * Spiele.
 */
[hidden] {
    display: none !important;
}

html {
    background: var(--hub-grund);
    /*
     * WER ZU EINEM ANKER SPRINGT, LANDET UNTER DEM KLEBENDEN KOPF - es sei
     * denn, das Dokument weiss, wie hoch der ist. Der Wert ist absichtlich
     * grosszuegiger als die Leiste selbst: Auf einem Telefon steht sie
     * zweizeilig.
     */
    scroll-padding-top: 7.5rem;
}

body.hub-body {
    margin: 0;
    background: var(--hub-grund);
    background-image: var(--hub-grain);
    color: var(--hub-tinte);
    font-family: var(--hub-font-text);
    font-size: 16px;
    line-height: 1.6;
    /* Ein Wort, das laenger ist als seine Spalte, schiebt sonst die ganze
       Seite seitwaerts – und der Handytest meldet den Ueberlauf, nicht das
       Wort. */
    overflow-wrap: anywhere;
}

/*
 * DIE FLANKEN AUF DEM BREITBILD.
 *
 * Ab 1920 Pixeln wird der Rand neben der Buehne breiter als ein Daumen, und
 * dort faengt diese Vignette an. Sie haengt an DERSELBEN Zahl wie die Buehne
 * (`calc(50% ± var(--hub-shell) / 2)`) und wandert damit von selbst mit: auf
 * 1920 sind es 60 Pixel je Seite, auf 2560 rund 380. Feste Prozentstopps
 * waeren auf dem einen Schirm nichts und auf dem anderen eine Verdunklung
 * mitten im Blatt.
 *
 * SIE LIEGT AM HINTERGRUND UND NICHT AN EINEM KASTEN. Ein Element mit
 * `width: 100vw` waere auf einer Seite mit Scrollbalken genau der Befund, den
 * `dev/portal.mjs` als Seitwaertsscrollen meldet; ein Hintergrundbild
 * verschiebt keine einzige gemessene Kante.
 *
 * `background-repeat` MUSS HIER STEHEN. Ohne die Zeile kachelte der Verlauf
 * zusammen mit dem Korn darunter — das Korn ist 140 × 140 Pixel gross, der
 * Verlauf waere es dann auch.
 */
@media (min-width: 120rem) {
    body.hub-body {
        background-image:
            linear-gradient(
                to right,
                var(--hub-flanke) 0,
                transparent calc(50% - var(--hub-shell) / 2),
                transparent calc(50% + var(--hub-shell) / 2),
                var(--hub-flanke) 100%
            ),
            var(--hub-grain);
        background-repeat: no-repeat, repeat;
    }
}

img,
video {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    color: var(--hub-tinte);
}

:focus-visible {
    outline: var(--hub-ring) solid var(--hub-signal);
    outline-offset: 2px;
}

/* Der Sprung ins Dokument. Er steht links ausserhalb des Schirms und nicht in
   einem `hidden`-Kasten: So misst ihn jeder Griffmesser mit, statt ihn als
   null mal null zu ueberspringen. */
.hub-sprung {
    position: fixed;
    left: -9999px;
    top: 0;
    z-index: var(--hub-ebene-sprung);
    display: inline-flex;
    align-items: center;
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    padding: var(--hub-gap-2) var(--hub-gap-3);
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
    text-decoration: none;
}

.hub-sprung:focus {
    left: 0;
}

/*
 * OBEN STAND NULL, UND DAS SAH AUS WIE EIN FEHLER.
 *
 * Der erste Kasten jeder Seite — der Aufmacher im Regal, die Schrittliste auf
 * /konzept, das Bekenntnis auf /ueber-uns, die Registratur auf /fall/<slug> —
 * begann unmittelbar an der Unterkante der klebenden Leiste. Beim Scrollen
 * schob sich der Inhalt ohne einen Pixel Luft unter das Glas.
 *
 * DIE ZAHL GEHOERT DEM RAHMEN, NICHT DIESER DATEI. `--haus-kopfluft` steht in
 * `shared/haus/haus.css`, weil sie an der Hoehe der LEISTE haengt und nicht an
 * der Breite dieses Foyers — und weil dieselbe Zahl in beiden Zimmern an
 * `.shell` steht. Drei Fassungen davon liefen beim naechsten Umbau
 * auseinander, genau wie es die drei Kopfleisten vor ihrer Zusammenlegung
 * taten.
 */
.hub-schale {
    max-width: var(--hub-shell);
    margin: 0 auto;
    padding: var(--haus-kopfluft) var(--hub-luft) var(--hub-gap-5);
}

/*
 * DIE SCHMALE SCHALE IST GEFALLEN, und mit ihr die dritte Seitenbreite.
 *
 * Konzept und Ueber uns liefen auf 82rem, weil sie „Saetze und keine Kacheln"
 * tragen. Das war einmal richtig und ist es nicht mehr: Beide Seiten sind
 * heute Schrittlisten und Kartenraster, und der Fliesstext darin traegt sein
 * Zeilenmass ohnehin selbst (--hub-mass, 68ch). Die Schale entschied also
 * nicht ueber die Lesbarkeit einer Zeile, sondern nur darueber, wie breit die
 * Kacheln stehen — und dort war sie die einzige Seite des Hauses, die beim
 * Wechsel aus dem Regal um 224 Pixel einsprang.
 *
 * ES GIBT JETZT EINE BUEHNENBREITE: --hub-shell im Foyer, --haus-shell im
 * Rahmen, --bm-akte und --wr-akte in den Zimmern. Dieselbe Zahl, 96rem.
 * Das Zeilenmass bleibt davon unberuehrt — es ist die Zusage, die Lesbarkeit
 * traegt, und es steht an den Absaetzen und nicht an der Seite.
 */

/*
 * DIE SCHMALE SCHALE DER AKTE IST WIEDER GEFALLEN, und der Weg dorthin ist
 * lehrreich genug, um ihn aufzuschreiben.
 *
 * Erst war der Aktendeckel 1400 Pixel breit und alles darauf 587: Der Satz
 * brach nach „Grossrechner kann man" um, und rechts lagen sechzig Prozent
 * leere Karte. Die Reparatur zog die KARTE auf das Zeilenmass zusammen
 * (`.hub-schale--akte`) — der Umbruch war weg, und dafuer stand Fall 03 als
 * Streifen von 650 Pixeln neben der Zeitung von Fall 01 und dem Ausdruck von
 * Fall 02, die beide die volle Buehnenbreite nehmen. Eine Reparatur, die einen
 * Stilbruch baut, ist keine.
 *
 * DIE ANTWORT STAND NEBENAN. Die Zeitung macht es seit jeher richtig: Kopf
 * ueber alles, darunter die Schlagzeile links und das Bild rechts. Beides
 * zusammen nimmt die Breite, und trotzdem liest niemand eine Zeile ueber 1300
 * Pixel — das Zeilenmass steht an den ABSAETZEN und nicht an der Seite.
 * `.hub-akte__koerper` tut dasselbe; die Schale der Akte ist wieder die des
 * Hauses, und die Registratur darueber passt wieder zum Deckel darunter.
 */

.hub-titel {
    margin: 0 0 var(--hub-gap-3);
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    border-bottom: var(--hub-border) solid var(--hub-kante);
    padding-bottom: var(--hub-gap-2);
}

/* ------------------------------------------------------------ Knopfform */

.hub-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--hub-gap-1);
    min-height: var(--hub-griff);
    /* IN BEIDE RICHTUNGEN. Ein Knopf von vierundvierzig Pixeln Hoehe und
       zwanzig Breite ist auf einem Telefon genauso wenig zu treffen wie
       einer von zwanzig Hoehe – der Daumen ist rund. */
    min-width: var(--hub-griff);
    padding: 0 var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-tinte);
    background: transparent;
    color: var(--hub-tinte);
    font: inherit;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-decoration: none;
    text-align: center;
    cursor: pointer;
    transition: background var(--hub-schnell), color var(--hub-schnell), transform var(--hub-schnell);
    border-radius: var(--hub-radius-m);
}

.hub-btn:hover {
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

/*
 * DER TASTENHUB: Beim Druck sinkt der Knopf um zwei Pixel, so wie eine Taste. Auf dem Telefon ist das die einzige
 * Rueckmeldung, die vor dem Seitenwechsel ankommt (und die Vibration, wo es sie gibt, siehe `data-haptik`). Es ist
 * eine Verschiebung und keine Bewegung: ohne `prefers-reduced-motion`-Frage, aber auch ohne Uebergang, wenn jemand
 * weniger Bewegung bestellt hat.
 */
.hub-btn:active:not([disabled]) {
    transform: translateY(2px);
}

@media (prefers-reduced-motion: reduce) {
    .hub-btn {
        transition: background var(--hub-schnell), color var(--hub-schnell);
    }
}

/*
 * DER TÜRKNOPF TRÄGT DEN AKZENT GEDUNKELT, und das ist keine Geschmacksfrage.
 *
 * Die Aufschrift steht in Papier. Auf dem Rot von Fall 01 hielt das 4,42:1,
 * auf dem Grün von Fall 02 nur 3,65:1 — und heller geht nicht: Selbst reines
 * Weiß kommt auf jenem Grün nur auf 4,18:1. Es gibt keine helle Schrift, die
 * dort 4,5 erreicht.
 *
 * Dunkle Schrift löst es auch nicht: Auf demselben Grün trägt Druckerschwärze
 * 4,62:1, auf dem Rot daneben aber nur 3,21:1. Eine Farbe für beide gibt es
 * nicht — also muss die FLÄCHE nachgeben, nicht die Schrift.
 *
 * 78 Prozent Akzent auf Schwarz tragen alle drei heutigen Fälle: Rot 8,52:1,
 * Grün 6,28:1, Grau 5,83:1 (gegen das reine Weiß, das die Aufschrift auf
 * hellem Grund jetzt ist — vorher stand dort ein gebrochenes Papier). Der
 * Akzent kommt je Kachel aus `spiele.akzent`; gerechnet wird deshalb und
 * nicht getippt. Die Kante behält den vollen Ton — sie ist der Ort, an dem
 * die Farbe des Falls unverfälscht steht.
 *
 * DER HOVER WIRD DUNKLER UND NICHT DURCHSICHTIG. Er stand auf
 * `background: transparent`, und das war auf Blech eine Umkehrung; auf Papier
 * sieht ein Knopf, der beim Darüberfahren seine Fläche verliert, aus wie
 * einer, der gerade abgeschaltet wurde. 62 Prozent halten Weiß bei 10,94:1,
 * 8,54:1 und 8,05:1.
 */
.hub-btn--tuer {
    border-color: var(--hub-akzent);
    background: var(--hub-akzent);
    background: color-mix(in srgb, var(--hub-akzent) 78%, #000);
    color: var(--hub-knopf-schrift);
}

.hub-btn--tuer:hover {
    background: color-mix(in srgb, var(--hub-akzent) 62%, #000);
    color: var(--hub-knopf-schrift);
}

/*
 * DER GEISTKNOPF IST AUF PAPIER KEIN GEIST MEHR, SONDERN EINE KARTE.
 *
 * Auf Blech reichte eine leise Kante: Der Knopf hob sich schon dadurch ab,
 * dass überhaupt eine Linie da war. Auf Naturpapier stand er mit
 * `--hub-kante` bei 1,31:1 gegen seinen Grund — unter den 3,0, die WCAG
 * 1.4.11 für ein Bedienelement verlangt, und in der Sache: kein Knopf,
 * sondern ein Satz mit viel Luft drumherum.
 *
 * `--hub-kante-griff` hält 3,34:1 gegen den Grund und 3,51:1 gegen die eigene
 * Fläche. Die Fläche ist weiß und nicht durchsichtig — sonst hinge er auf
 * einer Karte in deren Ton und auf der Seite in einem anderen.
 */
.hub-btn--geist {
    border-color: var(--hub-kante-griff);
    background: var(--hub-grund-karte);
    color: var(--hub-tinte-sekundaer);
}

.hub-btn--geist:hover {
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

.hub-btn[disabled] {
    border-color: var(--hub-kante);
    background: transparent;
    color: var(--hub-tinte-gedaempft);
    cursor: not-allowed;
}

/* --------------------------------------------------------------- Kopf */

/*
 * ER STEHT NICHT MEHR HIER, und das ist der Sinn des Umbaus.
 *
 * Kopfleiste und Fusszeile lagen dreimal im Haus: einmal in dieser Datei und
 * zweimal als zeichengleiche Kopie in den Zimmern - mit anderen Maszen, einem
 * anderen Umbruchpunkt und einer anderen Unterkante. Wer vom Foyer in einen
 * Fall ging, sah die Marke um 76 Pixel nach rechts springen.
 *
 * Beide stehen jetzt in `shared/haus/haus.css` (`.haus-kopf`, `.haus-fuss`),
 * werden von `shared/haus/haus.php` gesetzt und hier ueber
 * `index.php?seite=stil&d=haus` geladen. Wer an ihnen etwas aendert, aendert
 * es fuer JEDES Zimmer - und genau das war gewollt.
 */

/* ---------------------------------------------------------- Aufmacher */

/*
 * DIE BUEHNE HAT ZWEI BLAETTER, UND DAS IST EINE REPARATUR.
 *
 * Sie hatte eines, und darauf lag beides uebereinander: das Werteversprechen
 * des Hauses ("Ein Tisch, ein Code, kein Konto") UND als Hintergrund der
 * Werbefilm zu Fall 02. Wer die Seite zum ersten Mal sah, las einen Satz ueber
 * eine Plattform vor Bildern aus einem einzelnen Spiel und konnte nicht sagen,
 * wovon der Satz handelt. Zwei Aussagen in einem Kasten sind keine.
 *
 * GESCHALTET WIRD UEBER DIE ADRESSE (`/?buehne=film`) und nicht ueber ein
 * Skript. Damit hat jedes Blatt eine eigene Adresse, laesst sich verlinken und
 * steht auch ohne JavaScript da; das Skript im Fuss macht daraus nur den
 * Wechsel ohne Seitenwechsel. Dieselbe Bauform wie die Filterleiste darunter.
 *
 * Der Block heisst weiter `hub-aufmacher` und nicht `hub-buehne`: Ein zweiter
 * Name fuer dieselbe Flaeche waere ein zweiter Name - und `buehne` ist im
 * Nachbarhaus (`js/spiel/`) laengst die Comic-Buehne.
 */
.hub-aufmacher {
    margin-bottom: var(--hub-gap-5);
}

/*
 * DAS ERSTE BLATT WAR EINE TAPETE UND IST JETZT EINE SEITE.
 *
 * Es stand als dunkler Kasten von 28 rem Hoehe da, mit einem Panel als
 * Hintergrund, einem flachen Schleier darueber, einer Vignette darauf und dem
 * Text ganz oben — vier Ebenen, damit eine Zeile lesbar bleibt. Auf 2560
 * Pixeln war das Ergebnis eine Postkarte in der Mitte eines dunklen Fensters.
 *
 * JETZT SIND ES ZWEI SPALTEN: links die Ansage auf dem Papier der Seite,
 * rechts der Monolith mit dem Film und den vier Daten. Der Text braucht keinen
 * Schleier mehr, weil er auf nichts mehr liegt — und das Panel, das vorher
 * Tapete war, ist jetzt das Standbild DES FILMS und damit zum ersten Mal ein
 * Bild, das man ansieht.
 *
 * 60/40 UND ERST AB 62REM. Darunter stehen die beiden untereinander: Ein
 * Monolith von 40 Prozent Breite ist auf einem Tablet ein Streifen, in dem
 * weder der Film noch die Datenzeilen Platz haben.
 */
.hub-aufmacher__blatt {
    position: relative;
    display: grid;
    gap: var(--hub-spalt);
    align-items: center;
}

@media (min-width: 62rem) {
    .hub-aufmacher__blatt {
        grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
    }
}

/*
 * EIN FILMBLATT IST EIN KINO, und deshalb behaelt es seine eigenen
 * Knopffarben. Die Regel haengt am Blatt und nicht am ganzen Aufmacher:
 * Auf dem Willkommen-Blatt steht die Knopfreihe auf Papier und nimmt die
 * Hausfarben.
 *
 * SIE HAENGT AN DER KLASSE UND NICHT AM BLATTNAMEN, und genau deshalb hat der
 * Wechsler diese Regel nicht angefasst: Seit jeder Filmfall sein eigenes
 * Blatt hat (`data-buehne="film-<slug>"`), waere ein Selektor auf
 * `[data-buehne="film"]` der Ton eines einzigen Falls gewesen und jeder
 * weitere ein Kasten auf Papier.
 */
.hub-aufmacher__blatt--film {
    min-height: clamp(19rem, 44vh, 28rem);
    border: var(--hub-border) solid var(--hub-kino-kante);
    border-radius: var(--hub-radius-l);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    overflow: hidden;
}

.hub-aufmacher__blatt--film .hub-btn {
    border-color: var(--hub-kino-text);
    color: var(--hub-kino-text);
}

/*
 * UND DER GEISTKNOPF NIMMT SEINE FLAECHE WIEDER MIT.
 *
 * Er hatte bis zum Hellumbau gar keine: Auf Blech reichte die Kante, und im
 * Kino erbte er brav das durchsichtige Grund von ".hub-btn". Seit er auf
 * Papier eine weisse Karte ist (die Begruendung steht bei ".hub-btn--geist"),
 * brachte er sie auch hierher mit — und die Regel darueber faerbt nur Schrift
 * und Kante um. Ergebnis: zwei Knoepfe im dunklen Filmblatt, deren Aufschrift
 * (#f5f4f0) auf ihrer eigenen weissen Flaeche bei 1,10:1 stand. Lesbar war
 * daran nichts; sichtbar war nur der Umriss.
 *
 * DIE REGEL HAENGT AN ".hub-btn--geist" UND NICHT AN ".hub-btn", und das ist
 * der ganze Fix: Ein pauschales "background: transparent" fuer jeden Knopf
 * dieses Blattes haette die Flaeche des TUERKNOPFS gleich mit abgeraeumt —
 * ".hub-aufmacher__blatt--film .hub-btn" (0,2,0) schlaegt ".hub-btn--tuer"
 * (0,1,0), und aus "Fall 02 starten" waere ein Geist geworden.
 */
.hub-aufmacher__blatt--film .hub-btn--geist {
    background: transparent;
}

.hub-aufmacher__blatt--film .hub-btn:hover {
    background: var(--hub-kino-text);
    color: var(--hub-kino);
}

/*
 * DER MONOLITH. Ein dunkler Kasten auf hellem Papier — dieselbe Flaeche wie
 * der Sockel des Hauses, einmal unten und einmal rechts (die Toene stehen
 * deshalb auch auf denselben Werten, siehe --hub-kino im Tokenblock).
 *
 * Er ist der EINE dunkle Gegenstand dieser Seite, und das ist seine Aufgabe:
 * Ein Filmbild ist dunkel, und was darunter steht, sind die vier Zahlen, nach
 * denen jemand sucht, bevor er einen Abend zusagt.
 */
.hub-monolith {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--hub-kino-kante);
    border-radius: var(--hub-radius-l);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    box-shadow: var(--hub-schatten-schwebend);
    overflow: hidden;
}

.hub-monolith__daten {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: var(--hub-gap-3) var(--hub-gap-4) var(--hub-gap-4);
}

/*
 * EINE ZEILE IST EIN PAAR UND KEINE TABELLE. dt links, dd rechts, dazwischen
 * die Luft — und darunter ein Haar. Die letzte Zeile bekommt keines: Eine
 * Linie unter der letzten Zeile ist keine Trennung mehr, sondern ein Rest.
 */
.hub-monolith__zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--hub-gap-2);
    padding: var(--hub-gap-2) 0;
    border-bottom: 1px solid var(--hub-kino-kante);
}

.hub-monolith__zeile:last-child {
    border-bottom: 0;
    padding-bottom: 0;
}

.hub-monolith__zeile dt {
    margin: 0;
    color: var(--hub-kino-still);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-monolith__zeile dd {
    margin: 0;
    color: var(--hub-kino-text);
    font-size: 0.95rem;
    font-weight: 500;
    text-align: right;
}

/*
 * ZWEI BILDFLAECHEN, UND SIE HEISSEN VERSCHIEDEN, WEIL SIE ES SIND.
 *
 *   __video     – die Filmschleife. Sie steht auf BEIDEN Blaettern: im
 *                 Monolithen des ersten und im Kinokasten des zweiten.
 *   __standbild – der Ersatz FUER die Schleife, wenn jemand weniger Bewegung
 *                 bestellt hat. Nur dann steht es da.
 *
 * ES WAREN DREI, UND DIE DRITTE HIESS "__bild". Sie war die Tapete des ersten
 * Blattes, und der Kommentar hier begruendete ihren eigenen Namen damit, es
 * gebe "auf diesem Blatt keinen Film, zu dem sie der Ersatz waere". Genau das
 * ist mit dem zweispaltigen Aufmacher weggefallen: Auf dem ersten Blatt steht
 * jetzt der Film, und dasselbe Panel ist darin sein Standbild. Ein Name
 * weniger, eine Flaeche weniger, dieselbe Unterscheidung.
 */
.hub-aufmacher__video,
.hub-aufmacher__standbild {
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.45;
}

/*
 * IM MONOLITHEN IST DER FILM DIE HAUPTSACHE UND NICHT DIE TAPETE: volle
 * Deckung, 16:9, und der Kasten gibt ihm sein Mass. Dieselbe Regel wie im
 * Kinokasten des zweiten Blattes, nur eine Ebene frueher — sie steht hier und
 * nicht dort, weil der Monolith kein Kino ist: Unter dem Film stehen vier
 * Zeilen, und die duerfen nicht mitschneiden.
 */
.hub-monolith__film {
    position: relative;
    display: block;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--hub-kino-karte);
    border-bottom: 1px solid var(--hub-kino-kante);
}

.hub-monolith__film .hub-aufmacher__video,
.hub-monolith__film .hub-aufmacher__standbild {
    position: absolute;
    inset: 0;
    opacity: 1;
}

.hub-aufmacher__standbild {
    display: none;
}

/*
 * KEIN POLSTER MEHR AUF DEM ERSTEN BLATT. Es war der Innenabstand eines
 * Kastens; jetzt ist der Text die Seite selbst und richtet sich an derselben
 * Kante aus wie alles darunter. Auf dem Filmblatt bleibt der Kasten, und dort
 * bleibt auch das Polster (siehe die Regel weiter unten).
 */
.hub-aufmacher__text {
    position: relative;
    z-index: 1;
    max-width: var(--hub-hero-mass);
}

.hub-aufmacher__blatt--film .hub-aufmacher__text {
    padding: var(--hub-gap-5) var(--hub-gap-4);
}

/*
 * DIE SCHLAGZEILE DARF JETZT GROSS SEIN. Sie war auf 3,6rem gedeckelt, weil
 * sie in einem Kasten von 28 rem Hoehe ueber einem Bild stand; auf dem Papier
 * der Seite ist die Hoehe frei. 4,8rem ist der Wert, bei dem sie auf 2560 px
 * traegt, ohne auf 1440 px in vier Zeilen zu zerfallen.
 *
 * DIE SPERRUNG IST NEGATIV UND DAS IST DER GRUND: Grosse Grotesk laeuft ohne
 * Nachziehen auseinander. -0,035em ist gemessen an "Online-Escape-Games" — bei
 * -0,05 klebte das "rr" in "tableroom".
 */
.hub-aufmacher__zeile {
    margin: 0 0 var(--hub-gap-3);
    font-size: clamp(2.1rem, 4.4vw, 4.8rem);
    line-height: 1.03;
    letter-spacing: -0.035em;
}

/*
 * AUF DER WEICHE LAEUFT DIE SCHLAGZEILE IN EINER ZEILE DURCH, und die Zahl ist gemessen: „Kein Login. Kein Download.
 * Reines Browser-Gaming." ist mit -0,035em Sperrung 22,93 Schriftgroessen breit (die englische Zeile 20,38). Bei
 * 3,85vw sind das 88 Prozent der Fensterbreite, und die Buehne bietet 94,8 Prozent: Von rund 810 Pixeln aufwaerts
 * bleibt hinter der Zeile Platz, und ab 1200 Pixeln (75rem) ist es genug fuer den Filmstreifen (78 Pixel bei 1200,
 * 123 bei 1920). Unter 810 Pixeln bricht sie in zwei Zeilen um, und `text-wrap: balance` haelt beide gleich lang.
 *
 * 4,3rem ist der Deckel: Bei 1920 Pixeln rechnete 3,85vw sonst 74 Pixel, und die Zeile fuellte die Buehne bis an
 * den Rand — der Streifen haette keinen Platz mehr.
 *
 * DIE SCHRIFT IST DIE DER SYSTEMSCHRIFT (Segoe UI, San Francisco, Roboto): Eine breitere Ersatzschrift bricht die Zeile
 * auch ab 1200 Pixeln in zwei, und das ist ein Rueckfall und kein Fehler — Streifen und Zeile stehen dann als Zeile.
 */
.hub-weiche__kopf .hub-aufmacher__zeile {
    font-size: clamp(2.1rem, 3.85vw, 4.3rem);
}

/*
 * ER STAND AUF 46ch, UND DAS WAR EIN SCHMALER BLOCK NEBEN EINER RIESIGEN
 * SCHLAGZEILE. Gemessen auf 2560 px: Die Textspalte ist 832 px breit
 * (--hub-hero-mass), die Schlagzeile darueber nimmt sie mit 76,8 px ganz — der
 * Satz darunter stand mit 476,1 px auf 57,2 % davon und zerfiel in fuenf
 * Zeilen zu 51/53/51/45/51 Zeichen. Mit 62ch sind es 615,0 px, also 73,9 % der
 * Spalte, und vier Zeilen zu 70/64/67/51.
 *
 * JEDE DER DREI ZAHLEN IM clamp HAT IHREN EIGENEN GRUND. Wer eine davon fuer
 * ein Ueberbleibsel haelt, dreht sie heraus:
 *
 * 62ch ist das Magazinmass und die Obergrenze. AUF DEM ERSTEN BLATT gilt sie
 * ab etwa 1310 px Fensterbreite, IM FILMKASTEN ERST AB ETWA 1740 px: Dort
 * teilen sich zwei Spalten dieselbe Breite, und zwei Polster von 30,4 px
 * liegen davor. Auf 1600 px misst die Textspalte des Kinos deshalb 662,1 px,
 * und 85 % davon sind 562,8 px — dort gewinnt die Prozentzahl und nicht 62ch.
 *
 * 62ch liegt 217 px unter --hub-hero-mass (832 px). Die Hintertuer geht aber
 * frueher auf, als diese Differenz vermuten laesst: Wer den Token unter 724 px
 * senkt, deckelt den Satz ueber die Prozentzahl — 85 % von 723,5 px sind genau
 * 615,0 px.
 *
 * 85 % ist die Reserve fuer das mittlere Fensterband, gemessen ~1015–1310 px
 * auf dem ersten Blatt und ~1370–1740 px im Filmkasten. Dort ist die Spalte
 * schmaler als 62ch, und ohne den Prozentwert liefe der Satz bis an ihre
 * Kante. Der Prozentwert misst dabei gegen die CONTENT-Breite von
 * .hub-aufmacher__text: Im Filmkasten liegt unter 60rem ein Polster von
 * 30,4 px je Seite darin, bei 768 px sind also 85 % von 665,3 px gemeint und
 * nicht von 726,1 px.
 *
 * UND SIE HAT EINEN PREIS, gemessen im Notebookband: Bei 1180 px kostet sie
 * die vierte Zeile und laesst "Sofa)." als Schlusszeile stehen, bei 1100 px
 * zehn Zeichen. Mit 62ch allein stuenden dort bis 1024 px hinunter vier volle
 * Zeilen. Wer das Band hoeher gewichtet als die Reserve, setzt 95 % — dann
 * kippt es erst bei 1024 px. Kein Lauf faehrt diese Breiten (portal misst
 * 2560/1920/1440/768/390); wer es sieht, sieht es mit dem Auge.
 *
 * 48ch ist der Riegel gegen die Prozentzahl auf schmalen Spalten. Auf 375 px
 * waeren 85 % von 338,2 px gleich 287,5 px — ein Streifen mit 51 px totem Rand
 * auf einem Telefon. Mit dem Boden steht die max-width dort ueber der
 * Containerbreite und ist damit wirkungslos: Der Satz nimmt die Spalte ganz.
 *
 * ES BLEIBT EINE max-width. Ein `width` oder `min-width` an derselben Stelle
 * risse die Ueberlaufprobe in portal und hub sofort auf; max-width kappt nur,
 * und ein <p> fuellt ohnehin seinen Elternteil.
 *
 * DER SCHRIFTGRAD IST FEST UND WAR EIN clamp(1.05rem, 1.25vw, 1.2rem). Fest
 * ist eine gemessene Entscheidung: Auf 375 px (Spalte 338,2 px) stehen mit
 * 18,4 px sieben Zeilen zu 36 Zeichen — dieselbe Zeilenzahl wie vorher mit
 * 16,8 px, nur 18 px hoeher (188 -> 206 px); auf 390 px kostet er eine Zeile
 * (6 -> 7). 36 Zeichen je Zeile liegt im mobilen Komfortband, eine
 * Untergrenze waere eine Zahl mehr fuer keinen gemessenen Gewinn. Erst bei
 * 320 px Fensterbreite faellt es auf 26–34 Zeichen und neun Zeilen — diese
 * Breite misst kein Lauf, und der Erste, der es sieht, sitzt an einem Telefon.
 *
 * DER SICHTWECHSEL BEI 992 px IST AELTER ALS DIESE REGEL. Dort greift das
 * 60/40-Raster, und die Textspalte faellt von 832 px auf 546 px. Die 832 sind
 * der Deckel --hub-hero-mass: Unter 992 px steht der Text einspaltig, und
 * breiter als ihr Deckel wird die Spalte nirgends. Der Satz waechst gemessen
 * von vier auf fuenf Zeilen, waehrend das Fenster BREITER wird. Das faellt
 * erst auf, seit der Satz seine Spalte nutzt — es ist keine Regression dieses
 * Umbaus.
 */
.hub-aufmacher__satz {
    margin: 0 0 var(--hub-gap-3);
    max-width: clamp(48ch, 85%, 62ch);
    color: var(--hub-tinte-sekundaer);
    font-size: 1.15rem;
    line-height: 1.6;
}

/* Im Kino spricht der Satz die Kinofarbe. */
.hub-aufmacher__blatt--film .hub-aufmacher__satz {
    color: var(--hub-kino-text);
}

.hub-aufmacher__knopf {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2);
    margin: 0;
}

/*
 * DAS DACH UEBER DER SCHLAGZEILE — und es steht wieder auf BEIDEN Blaettern.
 *
 * Hier stand, es trage nur noch das zweite: Ueber dem ersten habe einmal
 * "Kooperative Spiele fuer den Browser" gestanden, dieselbe Aussage, die die
 * Schlagzeile einen Zentimeter tiefer schon macht — zweimal derselbe Satz
 * uebereinander liest sich wie ein Versehen.
 *
 * DER SATZ WAR RICHTIG, UND DER NEUE IST EIN ANDERER. Auf dem ersten Blatt
 * steht jetzt "Kooperative Online-Escape-Games · Direkt im Browser": die
 * Gattung und die eine BEDINGUNG, nach der jemand als Erstes fragt. Die
 * Schlagzeile darunter nennt die Gattung ein zweites Mal, weil sie das h1 ist
 * und der Suchbegriff dort stehen muss; die Bedingung nennt sie nicht.
 *
 * Auf dem Filmblatt bleibt es die rote Zeile ("Frisch erschienen"), auf dem
 * ersten ist es ein Chip: Dort liegt Papier, und eine rote Zeile allein ist
 * auf Papier zu leise fuer das, was sie sagt.
 */
/*
 * DAS DACH IST JETZT EINE MARKE UND KEINE ZEILE.
 *
 * Es stand als roter Satz ueber der Schlagzeile — auf dem Filmblatt richtig,
 * auf dem hellen ersten Blatt zu leise. Als Chip mit Kante und Grund sagt es
 * in drei Worten, was diese Seite ist, bevor die Schlagzeile es ausspricht.
 *
 * SEINE SCHRIFT IST --hub-akzent-schrift UND NICHT --hub-akzent: Auf
 * --hub-grund-subtil haelt das reine Akzentrot 4,65:1, die abgedunkelte
 * Fassung 6,70:1. (Hier stand 8,08 — das ist der Wert desselben Tons gegen
 * --hub-grund, nicht gegen die Flaeche des Chips.) Der Chip ist klein und
 * gesperrt; dort ist der Unterschied keine Kosmetik.
 */
.hub-aufmacher__dach {
    display: inline-flex;
    align-items: center;
    margin: 0 0 var(--hub-gap-3);
    padding: 0.35em 0.8em;
    border: 1px solid var(--hub-kante-stark);
    border-radius: 999px;
    background: var(--hub-grund-subtil);
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.75rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

/* Auf dem Filmblatt liegt kein Papier — dort bleibt es die rote Zeile. */
.hub-aufmacher__blatt--film .hub-aufmacher__dach {
    padding: 0;
    border: 0;
    background: none;
    color: var(--hub-kino-text);
}

/*
 * DER FILM LIEGT AUF SLIDE ZWEI IM 16:9-KASTEN und nicht mehr als Tapete
 * hinter dem Text. Ein Werbefilm, den man nur als abgedunkelten Hintergrund
 * sieht, ist ein Film, den niemand gesehen hat.
 */
@media (min-width: 60rem) {
    .hub-aufmacher__blatt--film {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
        gap: var(--hub-gap-4);
        align-items: center;
        padding: var(--hub-gap-4);
    }

    .hub-aufmacher__blatt--film .hub-aufmacher__text {
        padding: 0;
    }
}

/*
 * UND ES UEBERSCHREIBT DAS 60/40 DES ERSTEN BLATTES. Beide sind
 * ".hub-aufmacher__blatt"; ohne diese Zeile bekaeme das Filmblatt ab 62rem das
 * Raster des Aufmachers und ab 60rem sein eigenes — zwei Raster auf einem
 * Kasten, und welches gewinnt, entschiede die Reihenfolge im Stilblatt.
 */
@media (min-width: 62rem) {
    .hub-aufmacher__blatt--film {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    }
}

/*
 * SEINE KANTE GEHOERT DER KINOZONE UND NICHT DEM PAPIER.
 *
 * Die Umstellung auf den hellen Grund bildete --hub-blech-3 pauschal auf
 * --hub-kante ab — richtig fuer jede Kante, die auf Papier liegt, und falsch
 * fuer diese: Sie liegt auf #121214. Das cremeweisse #e2dbce stand dort mit
 * 13,59:1 als heller Rahmen um ein Filmbild, wo eine Haarlinie gemeint war.
 * Alle Nachbarn derselben dunklen Insel nehmen --hub-kino-kante.
 */
.hub-aufmacher__kino {
    position: relative;
    z-index: 1;
    aspect-ratio: 16 / 9;
    border: 1px solid var(--hub-kino-kante);
    background: var(--hub-kino);
}

/* Im Kinokasten ist der Film die Hauptsache und nicht die Tapete: volle
   Deckung, und der Kasten gibt ihm sein Mass. */
.hub-aufmacher__kino .hub-aufmacher__video,
.hub-aufmacher__kino .hub-aufmacher__standbild {
    position: absolute;
    inset: 0;
    opacity: 1;
}

@media (max-width: 59.99rem) {
    .hub-aufmacher__kino {
        margin: 0 var(--hub-gap-3) var(--hub-gap-4);
    }
}

/*
 * DER SPIELKNOPF LIEGT AUF DEM BILD und nicht in der Knopfreihe daneben: Er
 * bedient das, worauf er liegt. Er traegt seinen Stand in `aria-pressed` UND
 * in der Aufschrift - auf einem Telefon zeigt kein Tooltip nach, ob gerade
 * laeuft oder steht.
 */
.hub-aufmacher__spielen {
    position: absolute;
    right: var(--hub-gap-2);
    bottom: var(--hub-gap-2);
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    padding: 0 var(--hub-gap-3);
    border: 1px solid var(--hub-kino-text);
    background: var(--hub-kino-schleier);
    color: var(--hub-kino-text);
    font-family: var(--hub-font-doc);
    font-size: 0.75rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    cursor: pointer;
}

.hub-aufmacher__spielen:hover {
    background: var(--hub-kino-text);
    color: var(--hub-kino);
}

/* ------------------------------------------------- Die Reiterleiste */

/*
 * PFEILE UND PUNKTE IN EINER ZEILE, und alle vier sind ECHTE LINKS.
 *
 * Ein Punkt ohne Wort ist auf einer Startseite eine Zumutung: Er sagt, dass es
 * ein zweites Blatt gibt, und verschweigt, was darauf steht. Der Punkt traegt
 * deshalb seine Aufschrift daneben - er ist zugleich der Reiter. Ein dritter
 * Bedienweg (anonyme Punkte NEBEN beschrifteten Reitern) waere derselbe Knopf
 * dreimal.
 */
.hub-aufmacher__leiste {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-1);
    margin: var(--hub-gap-2) 0 0;
}

.hub-aufmacher__pfeil,
.hub-aufmacher__punkt {
    display: inline-flex;
    align-items: center;
    gap: var(--hub-gap-2);
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    justify-content: center;
    padding: 0 var(--hub-gap-2);
    border: 1px solid transparent;
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.76rem;
    letter-spacing: var(--hub-tracking);
    text-decoration: none;
    text-transform: uppercase;
    transition: color var(--hub-schnell), border-color var(--hub-schnell);
}

.hub-aufmacher__pfeil:hover,
.hub-aufmacher__punkt:hover {
    color: var(--hub-tinte);
}

/*
 * DIE AUFSCHRIFT DARF UMBRECHEN, UND ZWAR AUCH IM WORT.
 *
 * Sie hiess „Buchmafia #2" und passte in jede Zeile. Seit sie den Fall beim
 * Namen nennt („Fall 02 · Das Welt-Register") und seit es einen Reiter je
 * Filmfall gibt, stehen auf 375 px drei davon in einer Leiste. Ein Flex-Kind
 * schrumpft von sich aus nur bis zu seinem laengsten Wort; `anywhere` nimmt
 * auch diesen Riegel heraus. `hyphens: auto` taete es nicht — es setzt den
 * Trennstrich, senkt aber die min-content-Breite nicht zuverlaessig.
 */
.hub-aufmacher__punkt {
    overflow-wrap: anywhere;
    text-align: center;
}

/*
 * DER PUNKT IST EINE FLAECHE UND KEINE FARBE. "Keine Farbe als einziger
 * Informationstraeger" gilt auch fuer einen Slider: Gefuellt heisst offen,
 * hohl heisst zu - das sieht auch, wer die Akzentfarbe nicht unterscheidet.
 */
.hub-aufmacher__marke {
    display: block;
    flex: 0 0 auto;
    width: 0.6rem;
    height: 0.6rem;
    border: 2px solid currentcolor;
}

.hub-aufmacher__punkt[aria-current='true'] {
    border-color: var(--hub-kante);
    color: var(--hub-tinte);
}

/*
 * Der gefüllte Punkt ist SECHS MAL SECHS PIXEL, und er nimmt die
 * Schriftfassung des Akzents und nicht den Akzent selbst.
 *
 * Auf Blech war die Begründung, das volle Rot halte dort nur 2,88:1 — als
 * Fläche unter den 3,0 aus WCAG 1.4.11. Auf Papier hält es 5,07:1 und wäre
 * damit zu halten; die abgedunkelte Fassung hält 8,08:1. Bei sechs mal sechs
 * Pixeln ist das kein Feinschliff: Das ist die kleinste Fläche dieser Seite,
 * und sie sagt als einzige Farbe, welches Blatt oben liegt (daneben steht
 * „aria-current" und die Kante).
 */
.hub-aufmacher__punkt[aria-current='true'] .hub-aufmacher__marke {
    background: var(--hub-akzent-schrift);
    border-color: var(--hub-akzent-schrift);
}

/* ========================================================= Die Weiche ===

   DIE STARTSEITE: eine Kopfzeile und darunter zwei gleichrangige Wege.

   ZWEI SPALTEN AB 62rem UND KEINE DREI. Es sind genau zwei Sorten Abend, und
   die Entscheidung dazwischen ist die ganze Seite; eine dritte Spalte waere
   eine dritte Frage, die niemand gestellt hat. Die Schwelle ist dieselbe wie
   beim Aufmacher des Regals und bei `.hub-wissen` auf `/spiele` — eine eigene
   Zahl waere eine dritte Kante im selben Haus.

   BEIDE WEGE SIND GLEICH BREIT. `1fr 1fr` und nicht 60/40: Welcher der
   richtige ist, weiss der Besucher; eine breitere Spalte waere eine Antwort,
   bevor die Frage gestellt ist. Genau darum ging es bei diesem Umbau. */

.hub-weiche {
    margin-bottom: var(--hub-gap-5);
}

/*
 * DER SATZ UNTER DER SCHLAGZEILE NIMMT DIE BREITE DES KOPFES.
 *
 * Er trug die Regel der BUEHNE (`.hub-aufmacher__satz`, `clamp(48ch, 85%,
 * 62ch)`), und die ist fuer eine zweispaltige Flaeche gebaut: Dort steht der
 * Satz in einer Textspalte von rund 830 Pixeln, und die 85 Prozent sind die
 * Reserve fuer das mittlere Fensterband. Auf der Weiche steht er ueber die
 * VOLLE Breite, und dieselbe Regel kappte ihn bei 615 Pixeln — drei kurze
 * Zeilen unter einer Schlagzeile, die daneben 790 nimmt. Das sah nach einem
 * Umbruch aus, den jemand von Hand gesetzt hat.
 *
 * Was bleibt, ist das Zeilenmass des Hauses (`--hub-mass`, 68ch) und sonst
 * nichts: keine Prozentzahl, kein Boden, kein `clamp`. Der Satz bricht damit
 * dort, wo die Breite ihn bricht.
 *
 * UND DER KOPF TEILT DIESE KANTE. Ohne die Deckelung an `.hub-weiche__kopf`
 * liefe die Schlagzeile auf 2560 Pixeln ueber 1800 und der Satz bei 680 aus —
 * zwei rechte Kanten, die nichts miteinander zu tun haben. Mit ihr haben beide
 * dieselbe, und der Platz rechts ist Absicht statt Rest.
 */
.hub-weiche__kopf {
    position: relative;
    margin-bottom: var(--hub-gap-4);
}

/*
 * ------------------------------------------------ Der Filmstreifen
 *
 * EIN ZIERRAT, DER NICHTS TRAEGT. Kein Wort, kein Weg, keine Auskunft: `aria-hidden` im Markup, `pointer-events: none`
 * hier, und unter 48rem steht er gar nicht erst da. Auf einem Telefon ist der Kopf zweieinhalb Zeilen hoch — ein
 * Streifen darueber waere kein Zelluloid, sondern ein Schatten ueber der Schlagzeile.
 *
 * ER HAT ZWEI GESTALTEN, UND DIE FENSTERBREITE ENTSCHEIDET:
 *
 *   ab 75rem  — die Schlagzeile steht in EINER Zeile, und hinter ihrem letzten Wort bleibt Platz. Dort schliesst ein
 *               kurzes Stueck Film sie ab, wie ein Buchdrucker seine Zeile mit einer Vignette beendet: derselbe
 *               Streifen im Kleinen (`__stempel`), IN der Zeile und nicht hinter ihr, leicht geneigt, ein Stempel.
 *   48–75rem  — die Zeile fuellt die Buehne fast bis an den Rand, oder sie bricht um. Dort liegt der grosse Streifen
 *               (`__band`) als Wasserzeichen HINTER der Schlagzeile, mit 0,18 Deckkraft: Sie bleibt lesbar, wo sie
 *               ihn ueberlaeuft (Tinte darauf haelt 11,9:1).
 *
 * BEIDE SIND SVG-PFADE, UND DIE NEIGUNG STEHT IM viewBox UND NICHT IN EINER CSS-TRANSFORM. Ein gedrehtes Element traegt
 * eine Bounding-Box, die groesser ist als es selbst — ein Streifen von 120 x 560 misst bei 27 Grad rund 360 x 560 —,
 * und `overflow: hidden` schneidet das BILD, nicht den Kasten. `dev/dev.ps1 portal` meldete daraufhin „[Notebook
 * Foyer] Kein seitliches Scrollen → svg +68px": Er haelt JEDES Element des Dokuments gegen die Fensterbreite. Was im
 * viewBox liegt, liegt im Kasten des SVG; damit kann kein Kind mehr hinausragen.
 *
 * ER LIEGT UNTER DEM TEXT. `z-index: 0` an ihm, `1` an Schlagzeile und Satz — und bei 0,18 Deckkraft auf Naturpapier
 * bleibt die Schlagzeile auch dort lesbar, wo sie ihn ueberlaeuft.
 *
 * ER SCHWEBT: zwei bis drei Pixel in sechs Sekunden, `linear` wie jede Bewegung dieses Hauses — die neun Stufen
 * beschreiben eine Sinuskurve, ohne dass ein Federn oder Nachwippen im Spiel waere. Es ist die zweite Bewegung des Foyers,
 * die von selbst laeuft (die erste ist die Banderole), und sie steht unter denselben Riegeln: gar nichts bei
 * `prefers-reduced-motion`, und unter 48rem gibt es ihn gar nicht.
 */
.hub-zelluloid {
    display: none;
}

.hub-weiche__kopf > .hub-aufmacher__satz,
.hub-weiche__zeile > .hub-aufmacher__zeile {
    position: relative;
    z-index: 1;
}

/* Die Zeile: Schlagzeile und Streifen. Der Abstand nach unten gehoert ihr und nicht mehr der Schlagzeile allein. */
.hub-weiche__zeile {
    margin: 0 0 var(--hub-gap-3);
}

.hub-weiche__zeile > .hub-aufmacher__zeile {
    margin: 0;
}

@media (min-width: 48rem) {
    .hub-zelluloid {
        display: block;
        position: absolute;
        z-index: 0;
        inset: 0 0 auto auto;
        width: min(36%, 25rem);
        height: min(100%, 10.5rem);
        pointer-events: none;
        color: var(--hub-tinte);
    }

    /*
     * DAS BAND FUELLT DEN KASTEN. `xMaxYMid meet` haelt es an der rechten Kante: Der Kasten ist je nach Fensterbreite
     * verschieden breit, und ein Streifen, der dabei von der Ecke wegwandert, sieht nach Zufall aus. Die Deckkraft
     * ist die eines Wasserzeichens: 0,18, damit die Schlagzeile darueber (17,50:1 auf Naturpapier) auch dort ruhig
     * bleibt, wo die Zeile bis an den Rand laeuft.
     */
    .hub-zelluloid__band {
        display: block;
        width: 100%;
        height: 100%;
        opacity: 0.18;
    }

    .hub-zelluloid__stempel {
        display: none;
    }

    /* Sepia statt Schwarz: ein Zelluloid ist braun geworden, kein Blech. */
    .hub-zelluloid__grund {
        fill: var(--hub-tinte);
    }

    /* Die Perforation ist der Grund der Seite selbst: ein Loch zeigt das Papier darunter. */
    .hub-zelluloid__loch rect {
        fill: var(--hub-grund);
    }

    /*
     * DREI KADER, DREI TÖNE, JEDER FLACH. Ein belichteter Film traegt drei verschiedene Bilder und keinen
     * Streifen Tapete; drei gleiche Rechtecke saehen aus wie ein unbelichteter Rest. Es sind deshalb drei Toene
     * aus der Palette dieses Foyers und keine drei neuen — Messing, gedaempfte Tinte, Sand.
     *
     * FLACH HEISST FLACH. Hier stand ein Halbtonraster aus Punkten von fuenf Pixeln, und auf einer um 27 Grad
     * gedrehten Kante ist das ein Moire und kein Raster. Ein Verlauf waere die andere Versuchung und nach
     * Abschnitt 7 als Flaeche ohnehin verboten.
     */
    .hub-zelluloid__kader {
        fill: var(--hub-messing);
    }

    .hub-zelluloid__kader--b {
        fill: var(--hub-tinte-sekundaer);
    }

    .hub-zelluloid__kader--c {
        fill: var(--hub-kante-stark);
    }
}

/*
 * AB 75rem STEHT DIE ZEILE ALLEIN, UND DER STREIFEN SCHLIESST SIE AB. Er steht im Fluss neben der Schlagzeile (kein
 * absolutes Kind mehr), vertikal zur Zeile zentriert, und seine Breite ist der Platz, der hinter ihr bleibt — gemessen
 * 78 Pixel bei 1200 und 123 bei 1920 (`min(5vw, 5.5rem)` plus der Abstand bleibt darunter). Wird die Schlagzeile durch
 * eine breitere Ersatzschrift doch zweizeilig, steht er rechts neben dem Block: derselbe Kasten, ein Rueckfall.
 *
 * SEIN VERHAELTNIS STEHT ALS `aspect-ratio` DA (112 : 64, wie der viewBox): Die Hoehe rechnet sich aus der Breite, und
 * der Streifen ist so hoch wie eine Zeile Versalien.
 */
@media (min-width: 75rem) {
    .hub-weiche__zeile {
        display: flex;
        align-items: center;
        gap: var(--hub-gap-2);
    }

    .hub-weiche__zeile > .hub-aufmacher__zeile {
        flex: 0 1 auto;
    }

    .hub-zelluloid {
        position: static;
        flex: 0 0 auto;
        width: min(5vw, 5.5rem);
        height: auto;
        aspect-ratio: 112 / 64;
    }

    .hub-zelluloid__band {
        display: none;
    }

    .hub-zelluloid__stempel {
        display: block;
        width: 100%;
        height: 100%;
        opacity: 0.85;
    }
}

@keyframes hub-zelluloid-schweben {
    0%, 100% { transform: translateY(0); }
    12.5%, 87.5% { transform: translateY(-0.44px); }
    25%, 75% { transform: translateY(-1.5px); }
    37.5%, 62.5% { transform: translateY(-2.56px); }
    50% { transform: translateY(-3px); }
}

@media (min-width: 48rem) and (prefers-reduced-motion: no-preference) {
    .hub-zelluloid {
        animation: hub-zelluloid-schweben 6s linear infinite;
    }
}

/*
 * DIE SCHLAGZEILE NIMMT DIE FLAECHE, DIE SIE HAT.
 *
 * Der Kopf stand auf `min(100%, 62rem)` — 992 Pixel —, und darin brach die
 * Zeile auf einem Schirm von 1440 in DREI: „Kein Login. Kein Download. /
 * Reines Browser-Gaming / im 1920er-Noir-Stil." Der Deckel war als gemeinsame
 * rechte Kante fuer Zeile und Satz gedacht und hat dabei genau das gemacht,
 * wogegen er gebaut war: einen Umbruch, den niemand gesetzt hat und den jeder
 * sieht.
 *
 * Ohne ihn laeuft die Zeile ueber die Buehnenbreite und steht auf jedem
 * Schreibtisch in ZWEI Zeilen — gemessen auf 1440, 1920 und 2560.
 */

/*
 * UND DER SATZ DARUNTER HAT SEIN EIGENES MASS, das breiter ist als ein
 * Lesemass und schmaler als die Buehne.
 *
 * `--hub-mass` (68ch) sind hier 626 Pixel und damit drei kurze Zeilen unter
 * einer Schlagzeile, die daneben 1376 nimmt — derselbe Fehler wie oben, eine
 * Etage tiefer. 105ch sind rund 970 Pixel: Der Satz steht damit in ZWEI vollen
 * Zeilen, auf 1440 wie auf 2560.
 *
 * DASS DAS BREITER IST ALS DAS ZEILENMASS DIESES HAUSES, IST BEABSICHTIGT UND
 * GILT NUR HIER. Es sind drei Saetze ueber einer Weiche, keine Textspalte; wer
 * sie liest, liest sie einmal. Das Zeilenmass gilt weiter fuer alles, was man
 * entlangliest — auf `/faelle`, auf `/konzept`, in jedem Dossier.
 */
.hub-weiche__kopf .hub-aufmacher__satz {
    max-width: min(100%, 105ch);
    text-wrap: pretty;
}

/* ============================================================ Der Kompass ===
 *
 * DIE DREI SAEULEN AUF EINEN BLICK, direkt unter dem Schaufenster und ueber der Frage nach dem ganzen Abend. Wer
 * hier steht, hat sechs Tische gesehen — und weiss noch nicht, dass es zwei weitere Sorten Abend gibt. Der Kompass sagt
 * es in drei Karten, jede mit denselben drei Angaben: wie lange, wie viele, wie gespielt. Die Reihenfolge ist die der
 * Dauer, die kuerzeste links.
 *
 * ES IST KEIN ZWEITES REGAL. Keine Bilder, keine Knoepfe, keine Links: Die Wege stehen darunter (`.hub-abend`) und
 * darueber (`.hub-top`), und ein dritter waere derselbe Griff ein drittes Mal. Die Angaben sind Plaketten wie auf den
 * Wegen darunter (`.hub-weg__eck`), damit man die Zahlen zwischen beiden Stellen vergleichen kann.
 *
 * DIE OBERKANTE TRAEGT DEN AKZENT DER SAEULE: das Signal fuer Arena und Faelle, das Messing fuer das Brett — dieselben
 * Toene wie auf den Wegen, aus demselben Grund (drei gleich rote Kanten lesen sich als ein Block).
 *
 * EINE SPALTE UNTER 40rem, DREI DARUEBER. Auf 375 Pixeln stuenden drei Karten als je 110 Pixel breite Streifen, in
 * denen „Asymmetrisch" umbricht.
 */
.hub-kompass {
    margin-bottom: var(--hub-gap-5);
}

.hub-kompass__saeulen {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--hub-gap-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 40rem) {
    .hub-kompass__saeulen {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.hub-kompass__saeule {
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-2);
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    border-radius: var(--hub-radius-l);
    background: var(--hub-grund-karte);
    box-shadow: var(--hub-schatten-karte);
}

.hub-kompass__saeule {
    --hub-kompass-farbe: var(--hub-akzent-schrift);
}

/*
 * DAS BRETT NIMMT SEIN MESSING AUCH FUER DAS ZEICHEN: `--hub-akzent-schrift` wird am Wurzelelement gemischt und
 * folgt einem `--hub-akzent` an der Karte nicht — die Kante wuerde messingfarben, das Zeichen rot. Messing haelt
 * als Kante 5,41:1 auf Weiss.
 */
.hub-kompass__saeule--brett {
    --hub-akzent: var(--hub-messing);
    --hub-kompass-farbe: var(--hub-messing);
}

.hub-kompass__name {
    display: flex;
    align-items: center;
    gap: var(--hub-gap-2);
    margin: 0;
    font-size: 1.2rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.hub-kompass__zeichen {
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    fill: none;
    stroke: var(--hub-kompass-farbe);
    stroke-width: 1.7;
    stroke-linecap: square;
    stroke-linejoin: miter;
}

.hub-kompass__satz {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    text-wrap: pretty;
}

/* ====================================================== Die Asymmetrie ===
 *
 * DREI SCHRITTE, DIE ERKLAEREN, WARUM DIE FAELLE ANDERS SIND: vier Rollen an vier Schirmen, ein Sprechfunk, ueber den
 * alles laeuft, und niemand, der allein weiterkommt. Der Satz „Niemand sieht denselben Bildschirm" steht seit jeher im
 * Text der Karte; er ist eine Behauptung, und wer ihn liest, glaubt ihn nicht, bevor er ihn gespielt hat. Drei
 * kurze Zeilen in einem dunklen Streifen sagen es so, dass man es im Vorbeigehen mitnimmt.
 *
 * SIE STEHT IN DER KARTE DER FAELLE (Startseite) UND AM ANFANG DES REGALS (/escapes) — dieselbe Funktion
 * (`tr_asymmetrie()`), derselbe Wortlaut. Der Streifen ist Kino-Grund, dunkel bei Tag wie bei Nacht wie der Monolith
 * des Aufmachers und der Fuss; die Nummer steht als Messingplakette darauf (8,5:1 gegen den Streifen).
 *
 * DIE ZAHL IST EIN ZAEHLER UND KEIN TEXT: Sie steht im Pseudoelement, damit ein Schirmleser „eins, vier Rollen, vier
 * Schirme" aus der Liste selbst liest und nicht „1. 1 Vier Rollen". `role="list"` haelt die Semantik, die `list-style: none`
 * in Safari sonst abwirft.
 */
.hub-asym {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2) var(--hub-gap-3);
    margin: var(--hub-gap-2) 0;
    padding: var(--hub-gap-2) var(--hub-gap-3);
    border-radius: var(--hub-radius-m);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    list-style: none;
    counter-reset: hub-asym;
}

.hub-asym__schritt {
    display: inline-flex;
    align-items: center;
    gap: var(--hub-gap-2);
    min-height: 2rem;
    font-family: var(--hub-font-doc);
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    counter-increment: hub-asym;
}

.hub-asym__schritt::before {
    content: counter(hub-asym);
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--hub-messing-hell);
    color: var(--hub-kino);
    font-size: 0.8rem;
    font-weight: 700;
}

/*
 * KEIN PFEIL ZWISCHEN DEN SCHRITTEN: Die Nummern sagen die Reihenfolge, und ein Pfeil, der hinter dem letzten Wort einer Zeile
 * stuende, weil die naechste Nummer umgebrochen ist, waere ein Zeichen ohne Ziel — die Karte der Faelle ist eine halbe
 * Buehne breit, und dort stehen die drei Schritte untereinander.
 */
@media (max-width: 39.99rem) {
    .hub-asym {
        flex-direction: column;
    }
}

/* ============================================================ Der lange Abend
 *
 * ZWEI BREITWANDKARTEN NEBENEINANDER, und darueber eine Frage. Die Karten sind dieselben Wege wie vorher (`.hub-weg`,
 * Fenster oben, Marke, Titel, Satz, Knopf); neu ist die Lage. Zwei Karten in einer Reihe sind je rund 850 Pixel breit,
 * und ein Fenster von 16:9 darauf waere ein Bild von 480 Pixeln Hoehe — die Karte stuende als Plakat da, statt als
 * Angebot. Ab 40rem liegt das Fenster deshalb LINKS und nimmt gut ein Drittel; der Text steht rechts daneben.
 *
 * UNTER 40rem BLEIBT ES DIE KARTE VON VORHER: Fenster oben, Text darunter, eine Spalte. Ein Fenster von 38 Prozent
 * waere auf 375 Pixeln ein Daumennagel.
 */
.hub-abend {
    margin-bottom: var(--hub-gap-5);
}

.hub-abend__wege {
    display: grid;
    gap: var(--hub-spalt);
    align-items: stretch;
}

@media (min-width: 62rem) {
    .hub-abend__wege {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 40rem) {
    .hub-abend .hub-weg {
        flex-direction: row;
    }

    .hub-abend .hub-weg__fenster {
        flex: 0 0 38%;
        aspect-ratio: auto;
        min-height: 100%;
    }

    /* Das Bild fuellt das gestreckte Fenster: Eine Prozenthoehe an einem Kasten ohne feste Hoehe loest sich nicht auf. */
    .hub-abend .hub-weg__bild {
        position: absolute;
        inset: 0;
    }
}

/* ================================================================ Das Turnier
 *
 * DER ARENA-TURNIERMODUS: eine Karte mit dem Signal des Hauses oben, links der Satz und der Knopf, rechts der Weg fuer
 * den, der einen Code im Telefon hat. Sie ist KEIN Weg (`.hub-weg`) und traegt deshalb weder Fenster noch Eckdaten:
 * Bilder hat die Banderole darunter, und dort stehen alle Tische.
 *
 * DAS CODEFELD IST EIN NEBENWEG. Sechs Zeichen breit, 44 Pixel hoch, der Knopf daneben; `16px` bleibt die Untergrenze
 * des Schriftgrads, darunter zoomt iOS beim Antippen in das Feld hinein und die halbe Seite ist weg. Es traegt nicht
 * die Klasse des Feldes von `/tisch` (`.hub-terminal__feld`): Die ist mit dem Satz gebaut „das Feld IST der Zweck der
 * Seite" — `display: block`, volle Breite, Schriftgrad bis 2,4 rem — und stand hier einmal als Balken von 622 × 69
 * Pixeln unter dem Hauptknopf, der Nebenweg lauter als die Haupttuer.
 */
.hub-turnier {
    display: grid;
    gap: var(--hub-gap-4);
    margin-bottom: var(--hub-gap-5);
    padding: var(--hub-gap-4);
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-signal);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

@media (min-width: 62rem) {
    .hub-turnier {
        grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
        align-items: center;
    }
}

.hub-turnier__dach {
    margin: 0;
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-turnier__titel {
    margin: var(--hub-gap-1) 0 var(--hub-gap-2);
    font-size: clamp(1.6rem, 2.6vw, 2.2rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
}

.hub-turnier__satz {
    max-width: 100%;
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 1.02rem;
    line-height: 1.55;
}

.hub-turnier__knopf {
    margin: var(--hub-gap-3) 0 0;
}

.hub-turnier__code {
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    border-radius: var(--hub-radius-m);
    background: var(--hub-grund-subtil);
}

.hub-turnier__code-label {
    display: block;
    margin-bottom: var(--hub-gap-2);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-turnier__code-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-2);
}

.hub-turnier__code-feld {
    flex: 0 1 9ch;
    min-width: 7ch;
    min-height: var(--hub-griff);
    padding: var(--hub-gap-1) var(--hub-gap-2);
    border: var(--hub-border) solid var(--hub-kante-griff);
    background: var(--hub-grund-karte);
    color: var(--hub-tinte);
    font-family: var(--hub-font-zahl);
    font-size: max(16px, 1.05rem);
    letter-spacing: 0.2em;
    /* Die Sperrung haengt auch hinter dem letzten Zeichen und schoebe eine
       zentrierte Zeile sonst um genau diesen Betrag nach links. */
    text-indent: 0.2em;
    text-align: center;
    text-transform: uppercase;
    hyphens: none;
    border-radius: var(--hub-radius-m);
}

/*
 * EIN WEG IST GEBAUT WIE EINE KACHEL DES REGALS, und das ist Absicht: Wer von
 * hier nach `/faelle` geht, findet dort dieselbe Form wieder — Fenster oben,
 * Marke, Titel, Satz, Knopf. Eine eigene Formensprache fuer die Startseite
 * waere ein zweites Haus im selben Haus.
 *
 * Sie heisst trotzdem nicht `.hub-kachel`: Eine Kachel traegt einen Stand
 * (`data-hub-stand`), einen Akzent aus der Kartei und einen Titellink, der die
 * ganze Flaeche deckt. Ein Weg traegt nichts davon — er ist eine Entscheidung
 * und kein Gegenstand.
 */
.hub-weg {
    display: flex;
    flex-direction: column;
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
    overflow: hidden;
}

/*
 * DAS BRETTSPIEL TRÄGT MESSING, UND ZWAR DAMIT MAN ZWEI WEGE SIEHT UND NICHT
 * EINEN BLOCK.
 *
 * Die Karte der Fälle holt ihre Kante aus `spiele.akzent` des ersten Falls —
 * heute dasselbe Zinnober, das auch das Turnier darunter trägt. Das Brett
 * gehört keinem Fall und nicht der Arena; sein Ton ist das Holz seines eigenen
 * Bretts, und man sieht es einen Klick weiter wieder.
 */
.hub-weg--archiv {
    --hub-akzent: var(--hub-messing);
}

.hub-weg__fenster {
    position: relative;
    overflow: hidden;
    aspect-ratio: 16 / 9;
    background: var(--hub-kino);
}

/* Dieselbe Textur wie in jedem Fenster des Hauses: Vignette und Halbtonraster,
   die beiden Verlaeufe, die hier erlaubt sind — und beide als Textur. */
.hub-weg__fenster::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(circle at 50% 45%, transparent 45%, var(--hub-vignette) 100%),
        radial-gradient(var(--hub-halbton) 1px, transparent 1px);
    background-size: auto, var(--hub-halbton-size) var(--hub-halbton-size);
}

.hub-weg__bild {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hub-weg__text {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--hub-gap-2);
    padding: var(--hub-gap-3);
}

/*
 * DIE MARKE IST DIE EINE ZEILE MIT DEN ECKDATEN — Modus, Dauer, Besetzung.
 *
 * Sie steht in der Schrift der Akten und in Versalien, wie jede Kennzeile
 * dieses Hauses. `overflow-wrap: anywhere` steht daneben, weil sie auf 375 px
 * sonst an „2–4 PERSONEN" haengenbleibt und die Karte aufzieht.
 */
.hub-weg__marke {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    overflow-wrap: anywhere;
}

.hub-weg__titel {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--hub-gap-2);
    margin: 0;
    font-size: clamp(1.6rem, 2.6vw, 2.2rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
}

/* Die Gattung steht neben dem Namen und nicht darunter: „Die Arena" allein
   sagt nicht, dass dahinter gegeneinander gespielt wird. */
.hub-weg__gattung {
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    font-weight: 400;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-weg__satz {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 1.02rem;
    line-height: 1.55;
}

/*
 * DAS INHALTSVERZEICHNIS HINTER DEM LINKEN WEG.
 *
 * Drei Zeilen und keine Kacheln: Reihe, Titel, Stand. Es steht da, weil eine
 * Weiche sonst eine Frage offen laesst, die man vor dem Klick beantwortet
 * haben will — WAS liegt dahinter? Und es steht in der Schrift der Akten, weil
 * es ein Verzeichnis ist und kein Fliesstext.
 *
 * ES IST AUCH DAS GEGENGEWICHT ZUM CODEFELD IM RECHTEN WEG. Ohne es stand der
 * linke Knopf allein am Fuss einer Karte mit 180 Pixeln Leere darueber —
 * gleich hoch wie der Nachbar und halb so voll.
 */
.hub-weg__liste {
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-1);
    margin: var(--hub-gap-2) 0 0;
    padding: 0;
    list-style: none;
}

.hub-weg__zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--hub-gap-1) var(--hub-gap-2);
    padding: var(--hub-gap-1) 0;
    border-top: var(--hub-border) solid var(--hub-kante);
}

/*
 * DIE ZEILE IST EIN GRIFF UND MISST DESHALB 44 PIXEL — auch die einzeilige.
 *
 * `flex: 1 1 auto` STEHT NEBEN DER MINDESTHOEHE, und der Kommentar hier
 * behauptete einmal, es brauche es nicht („die Breite nimmt sie ohnehin ganz,
 * weil sie als flex-Kind waechst"). Gemessen war das Gegenteil: `inline-flex`
 * ohne `flex-grow` waechst nicht, und auf 1440 px mass der Griff 256 von 622
 * Pixeln — zwei Drittel der Zeile waren totes Feld neben einem Link, den man
 * treffen soll.
 */
.hub-weg__fall {
    display: inline-flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--hub-gap-2);
    min-height: var(--hub-griff);
    align-content: center;
    color: var(--hub-tinte);
    text-decoration: none;
}

.hub-weg__fall:hover .hub-weg__fall-titel,
.hub-weg__fall:focus-visible .hub-weg__fall-titel {
    text-decoration: underline;
    text-underline-offset: 3px;
}

.hub-weg__fall-reihe {
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-weg__fall-titel {
    font-size: 1rem;
    font-weight: 600;
}

.hub-weg__fall-stand {
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    white-space: nowrap;
}

/* Der Knopf sitzt unten, auch wenn der Nachbarweg mehr Text traegt: Zwei
   Knoepfe auf verschiedenen Hoehen sehen aus wie zwei Rangstufen. */
.hub-weg__knopf {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2);
    margin: auto 0 0;
    padding-top: var(--hub-gap-2);
}

/* ============================================================ Der Ablauf

   DREI SCHRITTE ALS ZEILE UND NICHT ALS KARTENRASTER.

   Ausgeschrieben steht der Ablauf auf `/konzept` als Kacheln (`.hub-schritte`,
   weiter unten). Hier sind es drei Woerter unter einer Entscheidung: Wer noch
   nicht weiss, ob er will, soll in einem Blick sehen, dass zwischen dem Klick
   und der ersten Runde nichts liegt — kein Konto, kein Download, keine
   Einladungsmail.

   SIE STEHT DIREKT UNTER DER WEICHE UND UEBER DER BANDEROLE. Weiter unten
   waere sie eine Fussnote; darueber stuende eine Anleitung vor der Frage, auf
   die sie antwortet.

   DIE ZIFFER KOMMT AUS DEM ZAEHLER, DER PFEIL AUS DEM PSEUDOELEMENT. Beides
   steht nicht im Wortlaut: Eine getippte „1." waere die vierte Stelle, an der
   jemand die Reihenfolge pflegen muesste, und eine Pfeilspitze im Text stuende
   auch dort, wo der Satz zitiert wird.

   AUF 375 PX BRICHT DIE KETTE IN DREI ZEILEN, und der Pfeil faellt dort weg:
   Ein Pfeil am Zeilenende zeigt ins Nichts. */

.hub-ablauf {
    margin-bottom: var(--hub-gap-5);
    padding: var(--hub-gap-3) var(--hub-gap-4);
    border: var(--hub-border) solid var(--hub-kante);
    border-radius: var(--hub-radius-m);
    background: var(--hub-grund-subtil);
}

.hub-ablauf__kette {
    counter-reset: hub-ablauf;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: var(--hub-gap-2) var(--hub-gap-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.hub-ablauf__schritt {
    counter-increment: hub-ablauf;
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.45em;
}

.hub-ablauf__schritt::before {
    content: counter(hub-ablauf) '.';
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-zahl);
}

/* Der Pfeil gehoert dem Zwischenraum und nicht dem letzten Schritt. */
.hub-ablauf__schritt:not(:last-child)::after {
    content: '→';
    color: var(--hub-tinte-gedaempft);
}

.hub-ablauf__wort {
    color: var(--hub-tinte);
}

.hub-ablauf__zusatz {
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.75rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    hyphens: none;
}

@media (max-width: 46rem) {
    .hub-ablauf__kette {
        justify-content: start;
    }

    .hub-ablauf__schritt:not(:last-child)::after {
        content: none;
    }
}

/* ===================================================== Die Vertrauenszeile

   VIER ZUSAGEN IN EINER ZEILE, ohne Zeichen und ohne Kasten.

   Ausgeschrieben stehen sie auf `/faelle` und `/konzept` als vier Flaechen
   (`.hub-merkmale`). Hier ist es eine Zeile: Wer bis hierher gelesen hat,
   sucht keine Erklaerung mehr, sondern die Versicherung — und vier Kaesten
   unter einer Weiche waeren eine zweite Entscheidung nach der einen, um die
   es geht.

   `overflow-wrap: anywhere` und `text-wrap: balance`: Auf 375 px bricht die
   Zeile in vier, und ohne den Ausgleich stuende „werbefrei" allein. */

.hub-vertrauen {
    margin-bottom: var(--hub-gap-5);
    padding: var(--hub-gap-3) var(--hub-gap-4);
    border: var(--hub-border) solid var(--hub-kante);
    border-radius: var(--hub-radius-m);
    background: var(--hub-grund-subtil);
}

.hub-vertrauen__zeile {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.82rem;
    letter-spacing: var(--hub-tracking);
    line-height: 1.8;
    text-align: center;
    text-transform: uppercase;
    text-wrap: balance;
    overflow-wrap: anywhere;
}

/* ------------------------------------------------------------- Siebe */

.hub-siebe {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-2);
    margin: 0 0 var(--hub-gap-3);
    padding: 0;
}

.hub-sieb {
    display: inline-flex;
    align-items: center;
    gap: var(--hub-gap-1);
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    padding: 0 var(--hub-gap-2);
    /*
     * DER GRIFFTON UND NICHT DIE HAARLINIE: Ein Sieb ist ein Bedienelement,
     * und seine Kante ist seine einzige Begrenzung — er traegt weder Flaeche
     * noch Schatten. --hub-kante haelt dort 1,31:1, --hub-kante-griff 3,34:1
     * und damit die 3,0 aus WCAG 1.4.11. Das "select" daneben in derselben
     * Zeile fuehrte den Griffton schon; zwei Masze in einer Leiste sind eines
     * zu viel.
     */
    border: var(--hub-border) solid var(--hub-kante-griff);
    text-decoration: none;
    border-radius: var(--hub-radius-m);
}

/* Der offene Sieb traegt drei Traeger und nicht einen: Kante, Flaeche und
   `aria-current`. Farbe allein waere nie genug. */
.hub-sieb[aria-current='page'] {
    border-color: var(--hub-tinte);
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

.hub-sieb__zahl {
    font-family: var(--hub-font-zahl);
    font-size: 0.8rem;
    /* Ein Bindestrich in einer Zahl waere eine Falle. */
    hyphens: none;
}

.hub-siebe__label {
    font-size: 0.85rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-siebe__wahl {
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    padding: 0 var(--hub-gap-2);
    border: var(--hub-border) solid var(--hub-kante-griff);
    background: var(--hub-feld-grund);
    color: var(--hub-tinte);
    font: inherit;
    border-radius: var(--hub-radius-m);
}

.hub-leer {
    margin: 0;
    padding: var(--hub-gap-4);
    border: var(--hub-border) dashed var(--hub-kante);
    border-radius: var(--hub-radius-m);
}

.hub-leer__zurueck {
    display: inline-flex;
    align-items: center;
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    margin-left: var(--hub-gap-2);
}

/* ------------------------------------------------------------- Regal */

.hub-regal-block {
    margin-bottom: var(--hub-gap-5);
}

/* Die Unterzeile der Regalueberschrift. Sie nennt den ganzen Ablauf in einem
   Satz – waehlen, oeffnen, Code schicken – und ersetzt damit die Inventur,
   die hier frueher stand. */
/*
 * DER VORSPANN IST KEIN FLIESSTEXT, UND 68ch WAREN HIER ZU WENIG.
 *
 * Er stand auf `--hub-mass` - dem Zeilenmass fuer Absaetze - und war damit
 * auf 586,5 Pixel gedeckelt. Der Satz braucht rund 640: Er war GENAU EIN WORT
 * zu lang, und "joinen." stand ab 584 Pixel Fensterbreite allein auf der
 * zweiten Zeile. Bis 1600 Pixel und darueber, denn `max-width` friert den
 * Kasten ein - er waechst nie ueber die Stelle hinaus, an der das Wort wieder
 * hochrutschen koennte.
 *
 * EIN EINZEILER IST KEINE AUSNAHME VOM ZEILENMASS, sondern ein anderer
 * Gegenstand: Eine Unterzeile unter einer Ueberschrift wird nicht gelesen wie
 * ein Absatz, sie wird ueberflogen. Dasselbe Argument wie bei
 * `--hub-hero-mass`, nur eine Stufe kleiner.
 */
.hub-regal__satz {
    max-width: 90ch;
    text-wrap: pretty;
    margin: calc(var(--hub-gap-3) * -1) 0 var(--hub-gap-3);
    color: var(--hub-tinte-sekundaer);
}

/*
 * KEIN EINZELNES WORT AUF DER SCHLUSSZEILE.
 *
 * `text-wrap: pretty` stand im ganzen Projekt null Mal, und deshalb endete
 * fast jeder Satz des Foyers, der seinen Kasten um weniger als ein Wort
 * ueberschreitet, auf einer Waise: "joinen.", "ist.", "direkt hin.",
 * "alles.", "daraus nie.", "einen Dritten.". Bei vier Merkmalkacheln
 * nebeneinander, von denen drei eine Restzeile mit einem Wort tragen, liest
 * sich das als Rasterfehler und nicht als Text.
 *
 * ES IST KEIN EFFEKT UND KEIN WEICHZEICHNER: Die Eigenschaft aendert nur, an
 * welcher Leerstelle der Browser bricht, und faellt in aelteren Browsern
 * folgenlos auf `wrap` zurueck.
 *
 * DER PROMINENTESTE SATZ DER STARTSEITE FEHLTE IN DIESER LISTE. Sie fuehrte
 * neun Selektoren bis hinunter zur Merkmalkachel, und ausgerechnet
 * .hub-aufmacher__satz stand nicht darin. Gemessen hebt `pretty` dort die
 * schlimmste Waise des 85-%-Bandes von sechs auf zehn Zeichen (1180 px) und
 * ebenso auf 414 px; jede andere Breite bleibt Zeichen fuer Zeichen gleich.
 * ES IST KEIN ERSATZ FUER DIE PROZENTZAHL EINE REGEL WEITER OBEN: Chromium
 * zieht damit nur ein einziges Wort herunter, die Waise verschwindet nicht.
 */
.hub-aufmacher__satz,
.hub-kasse__satz,
.hub-kasse__entlastung,
.hub-terminal__satz,
.hub-terminal__absage,
.hub-terminal__note,
.hub-merkmal__satz,
.hub-leer,
.hub-karte__satz,
.hub-stimme__satz,
.hub-wissen__punkt,
.hub-wissen__satz,
.hub-leerseite p {
    text-wrap: pretty;
}

/*
 * DIE SCHLAGZEILE ZERRISS "Online-Escape-Games" AM BINDESTRICH - fuer CSS ist
 * er eine Umbruchgelegenheit. `balance` verteilt die Zeilen gleichmaessig und
 * nimmt dem Bindestrich die Rolle des bevorzugten Bruchs. Die beiden Zimmer
 * fuehren dieselbe Zeile auf ihren Ueberschriften; das Foyer war das einzige
 * Haus ohne sie.
 */
.hub-aufmacher__zeile {
    text-wrap: balance;
}

.hub-regal {
    display: grid;
    gap: var(--hub-gap-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

/*
 * FESTE STUFEN, KEIN `auto-fit`/`auto-fill`. Die Zahl der Spiele ist bekannt
 * und steht in der Datenbank; ein Raster, das sie raet, laesst bei drei
 * Eintraegen eine vierte leere Spalte stehen (`auto-fill`) oder zieht drei
 * Kacheln auf siebenundzwanzig Rem auseinander (`auto-fit`). Beides sieht aus
 * wie ein Fehler und ist ein Wert.
 */
@media (min-width: 46rem) {
    .hub-regal[data-hub-lage='paar'],
    .hub-regal[data-hub-lage='reihe'] {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 68rem) {
    .hub-regal[data-hub-lage='reihe'] {
        grid-template-columns: repeat(3, 1fr);
    }
}

.hub-regal__fach {
    display: flex;
}

.hub-kachel {
    /* Der Containing Block fuer das Overlay des Titellinks. */
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

/*
 * DER STAND HAT DREI TRAEGER, nicht einen: das Wort in der Marke, die
 * Rahmenart und die Saettigung des Bildes. Farbe allein waere fuer jeden
 * Vierzehnten am Tisch keine Auskunft.
 */
.hub-kachel[data-hub-stand='wartung'] {
    border-style: dashed;
}

.hub-kachel[data-hub-stand='wartung'] .hub-kachel__bild {
    opacity: 0.82;
    filter: grayscale(0.6);
}

/*
 * EIN KOMMENDER FALL IST KEINE STOERUNG, und deshalb ist seine Kante nicht
 * dieselbe. `wartung` ist rundum gestrichelt - da war etwas und ist gerade
 * nicht da. `bald` behaelt die geschlossene Kante und bekommt die Akzentlinie
 * OBEN gepunktet: Die Akte ist angelegt, gedruckt ist noch nichts.
 */
.hub-kachel[data-hub-stand='bald'] {
    border-top-style: dotted;
    background: var(--hub-grund);
}

.hub-kachel__fenster,
.hub-akte__fenster {
    position: relative;
    overflow: hidden;
    aspect-ratio: 16 / 9;
    background: var(--hub-kino);
}

.hub-kachel__fenster::after,
.hub-akte__fenster::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(circle at 50% 45%, transparent 45%, var(--hub-vignette) 100%),
        radial-gradient(var(--hub-halbton) 1px, transparent 1px);
    background-size: auto, var(--hub-halbton-size) var(--hub-halbton-size);
}

.hub-kachel__bild {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/*
 * DAS LEERE FENSTER, und es ist keine Notloesung.
 *
 * Ohne es stuende eine Kachel ohne Bild neben zwei mit Bild, und das Regal
 * saehe aus, als fehle eine Datei. Mit ihm behaelt die Reihe ihre Hoehe, und
 * die Flaeche sagt selbst, warum sie leer ist: Von diesem Fall ist nichts
 * gedruckt. Die Textur darin ist dieselbe Vignette und dasselbe Halbtonraster
 * wie in jedem anderen Fenster - die zwei Verlaeufe, die dieses Haus erlaubt,
 * beide als Textur und nicht als Flaeche.
 */
/*
 * DIE VORSCHAU LIEGT UEBER DEM AUSHANG UND UNTER DER VIGNETTE.
 *
 * Kein `z-index`: Sie ist absolut gesetzt, der Aushang darunter ist es nicht, und die Koernung des Fensters
 * (`::after`) kommt im Dokument nach ihr. Damit steht die Reihenfolge von selbst richtig — eine Zahl hier waere
 * eine dritte Stelle, die beim naechsten Umbau nicht mitwandert.
 *
 * Solange niemand gedrueckt hat, traegt sie `hidden` und misst null mal null; das Skript im Fuss nimmt es ab.
 */
.hub-kachel__film {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hub-kachel__fenster--leer {
    display: flex;
    align-items: center;
    justify-content: center;
}

/*
 * DIE PLAKETTE LIEGT IM FENSTER, UND DAS FENSTER IST NACHT.
 *
 * Sie stand in --hub-tinte-gedaempft und --hub-kante — den Toenen der hellen
 * Seite —, und beide liegen hier auf --hub-kino: 3,52:1 fuer die Schrift, ein
 * Strich, den man gar nicht mehr sah. Gefunden hat das der Kontrastwaechter
 * in dem Lauf, der diesen Umbau abgenommen hat; von Hand war es nicht zu
 * sehen, weil man beim Umstellen auf die FLAECHEN schaut und nicht darauf,
 * WELCHE Flaeche unter einem Kasten liegt, der drei Regeln weiter oben
 * definiert ist.
 *
 * --hub-kino-still haelt 6,49:1, --hub-kino-kante ist der Strich derselben
 * Zone.
 */
.hub-kachel__leer {
    position: relative;
    z-index: 1;
    padding: var(--hub-gap-2) var(--hub-gap-3);
    border: 1px dashed var(--hub-kino-kante);
    color: var(--hub-kino-still);
    font-family: var(--hub-font-doc);
    font-size: 0.8rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-kachel__text {
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: var(--hub-gap-2);
    padding: var(--hub-gap-3);
}

.hub-kachel__kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--hub-gap-2);
    margin: 0;
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-kachel__reihe {
    color: var(--hub-tinte-sekundaer);
}

.hub-kachel__marke {
    padding: 2px var(--hub-gap-2);
    border: 1px solid var(--hub-kante-griff);
    color: var(--hub-tinte-sekundaer);
}

.hub-kachel[data-hub-stand='offen'] .hub-kachel__marke {
    border-color: var(--hub-akzent);
    color: var(--hub-tinte);
}

/*
 * DIE BADGE „NUR AUF DEUTSCH" — steht nur auf /en/escapes, an spielbaren
 * Kacheln ohne bilingualen Rahmen. Dieselbe Kante wie die Marke daneben,
 * aber ohne deren Akzentfarbe: Sie ist eine Einschraenkung, kein Status.
 */
.hub-kachel__sprachbadge {
    padding: 2px var(--hub-gap-2);
    border: 1px solid var(--hub-kante-griff);
    color: var(--hub-tinte-gedaempft);
    font-size: 0.78rem;
}

.hub-kachel__titel {
    margin: 0;
    font-size: 1.35rem;
    line-height: 1.15;
}

/*
 * DIE GANZE KACHEL IST DER GRIFF, aber es gibt genau EINEN Link darin.
 *
 * Der Titel bekommt ausdruecklich KEIN `position: relative` – sonst deckte
 * das Overlay nur den Titel ab und die Kachel waere kein Griff mehr. Und
 * ausdruecklich `inset: 0` und nicht `-100vmax`: Ein Kasten ueber die ganze
 * Seite legte jede frueher stehende Kachel tot.
 *
 * `min-height` UND `min-width`: Ein einzeiliger Titel misst sonst
 * dreiundzwanzig Pixel, und ein Lauf, der nur die Hoehe prueft, sieht es nicht.
 */
.hub-kachel__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    text-decoration: none;
}

.hub-kachel__link::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
}

.hub-kachel__tuer {
    position: relative;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-2);
    margin: auto 0 0;
    padding-top: var(--hub-gap-2);
}

/*
 * AUF DEM TELEFON STEHEN DIE BEIDEN KNOEPFE EINES FALLS UNTEREINANDER UND GLEICH BREIT. Nebeneinander passen „Tisch
 * eröffnen" und „Fall-Akte ansehen" auf 375 Pixeln nicht; umgebrochen standen sie als zwei verschieden lange Knoepfe
 * am linken Rand, und der kuerzere sah aus wie der unwichtigere. Beide sind ein Weg, und der Daumen trifft einen Streifen
 * ueber die ganze Kachel sicherer als einen Knopf von 150 Pixeln.
 */
@media (max-width: 45.99rem) {
    .hub-kachel__tuer .hub-btn {
        flex: 1 1 100%;
    }
}

.hub-kachel:has(.hub-kachel__link:focus-visible) {
    outline: var(--hub-ring) solid var(--hub-signal);
    outline-offset: 2px;
}

.hub-kachel__aufhaenger {
    margin: 0;
}

/*
 * DAS DOSSIER EINER KACHEL IN DER VITRINE: ein Aufklapper in der Schrift der
 * Akten und darunter der Absatz, wie ein Tisch funktioniert. Er stand als
 * Ueberblick unter allen Kacheln und wurde dort nicht gelesen.
 *
 * ES LIEGT UEBER DEM GRIFF DER KACHEL (`z-index` wie beim Tuerknopf): Das
 * Overlay des Titellinks deckt die ganze Kachel, und ein Tipp auf den
 * Aufklapper oeffnete sonst den Tisch statt des Absatzes. Es steht direkt ueber
 * dem Knopf, und aufgeklappt schiebt es ihn nach unten; der Knopf bleibt der
 * Fuss der Kachel.
 *
 * DER WINKEL IST EINE KANTE UND KEIN ZEICHEN IM TEXT, und er dreht sich in
 * derselben Zeit wie jeder Uebergang des Hauses. Der Absatz haelt 60 Zeichen je
 * Zeile, links eine Linie im Akzent, wie ein Vermerk am Rand einer Akte.
 */
.hub-kachel__dossier {
    position: relative;
    z-index: 2;
    margin-top: auto;
    border-top: var(--hub-border) solid var(--hub-kante);
}

.hub-kachel__dossier + .hub-kachel__tuer,
.hub-kachel__dossier + .hub-arenaknoepfe {
    margin-top: 0;
}

.hub-kachel__dossier-griff {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--hub-gap-2);
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    list-style: none;
    cursor: pointer;
    transition: color var(--hub-schnell);
}

.hub-kachel__dossier-griff::-webkit-details-marker {
    display: none;
}

.hub-kachel__dossier-griff::after {
    content: '';
    flex: none;
    width: 0.5rem;
    height: 0.5rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    rotate: 45deg;
    translate: 0 -0.15rem;
    transition: rotate var(--hub-schnell), translate var(--hub-schnell);
}

.hub-kachel__dossier[open] > .hub-kachel__dossier-griff::after {
    rotate: 225deg;
    translate: 0 0.15rem;
}

.hub-kachel__dossier-griff:hover,
.hub-kachel__dossier[open] > .hub-kachel__dossier-griff {
    color: var(--hub-tinte);
}

.hub-kachel__dossier-griff:focus-visible {
    outline: var(--hub-ring) solid var(--hub-signal);
    outline-offset: 2px;
}

.hub-kachel__dossier-text {
    max-width: 60ch;
    margin: 0 0 var(--hub-gap-2);
    padding-left: var(--hub-gap-3);
    border-left: 2px solid var(--hub-akzent);
    color: var(--hub-tinte-sekundaer);
    font-size: 0.95rem;
    line-height: 1.6;
    text-wrap: pretty;
}

.hub-kachel__bekannt {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 0.85rem;
}

/*
 * DIE KACHEL DER VITRINE IST KNAPPER ALS DIE DES REGALS DER FAELLE. Zwischen
 * Marke, Name und Satz stand dieselbe Luft wie zwischen den Eckdaten eines
 * Falls, und zwanzig Kacheln damit sind eine lange Seite. Der Abstand faellt
 * auf die kleinste Stufe.
 *
 * DER TITELLINK BEHAELT SEINE 44 PIXEL. Er ruht auf einer einzigen Zeile von
 * 25 Pixeln, und der Rest ist Luft ueber und unter dem Wort; der negative Rand
 * schiebt diese Luft unter die Nachbarzeilen, statt sie wegzunehmen. Der Griff
 * bleibt so gross, wie `dev/dev.ps1 hub` ihn misst, und das Wort rueckt an
 * Marke und Satz heran.
 */
.hub-regal--kompakt .hub-kachel__text {
    gap: var(--hub-gap-1);
    padding-top: var(--hub-gap-2);
}

.hub-regal--kompakt .hub-kachel__titel {
    margin-block: calc(-1 * var(--hub-gap-1));
}

/*
 * DIE PLAKETTEN DER VITRINE LIEGEN AUF DEM BANNER, OHNE IM FENSTER ZU STEHEN.
 *
 * Sie sind ein Geschwister des Fensters (`spiele.php` sagt warum) und liegen
 * trotzdem an derselben Stelle wie vorher: Die Kachel hat keinen Innenabstand,
 * das Fenster beginnt an ihrer Oberkante, und `top` rechnet von dort.
 * Spielerzahl links, „Auch solo" rechts. Sie liegen unter dem Griff der Kachel:
 * Ein Klick auf eine Plakette ist ein Klick auf den Tisch.
 */
.hub-kachel__plaketten {
    position: absolute;
    top: var(--hub-gap-2);
    right: var(--hub-gap-2);
    left: var(--hub-gap-2);
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--hub-gap-1);
    margin: 0;
}

.hub-kachel__plaketten > .hub-spieler {
    border: 1px solid var(--hub-kino-kante);
}

.hub-kachel__plaketten > .hub-spieler--solo {
    border-color: var(--hub-signal);
    background: var(--hub-signal);
    color: var(--hub-knopf-schrift);
}

/*
 * AUF DEM TELEFON IST DIE VITRINE EINE LISTE, UND KEINE REIHE VON PLAKATEN.
 *
 * Eine Kachel stand auf 390 Pixeln 530 Pixel hoch — Banner, Marke, Name,
 * Zweitname, Satz, Dossier, Knopf —, und einundzwanzig davon waren elf
 * Bildschirme. Solange das Raster eine Spalte hat (unter 46rem), liegt das
 * Banner als Daumennagel links neben Marke, Name, Zweitname und Plaketten;
 * darunter stehen der eine Satz und die Knoepfe ueber die ganze Breite. Das
 * Dossier faellt hier weg: Der Name fuehrt auf die Seite des Tisches, und dort
 * steht das Spielprinzip samt Regelblatt. Im Markup bleibt es stehen, fuer die
 * Suche und fuer den Schreibtisch.
 *
 * `display: contents` AM TEXT, NICHT AM FENSTER. Die Kinder des Textkastens
 * werden so Zellen des Rasters der Kachel, ohne dass das Markup zwei Fassungen
 * braucht; das Fenster bleibt ein Kasten, damit Vignette und Korn in ihm
 * liegen und nicht ueber der ganzen Kachel. Die Teaserkachel am Ende hat keine
 * Plaketten und keine Knoepfe — sie bleibt eine Spalte und verliert nur ihr
 * leeres Fenster.
 */
@media (max-width: 45.99rem) {
    .hub-regal--kompakt {
        gap: var(--hub-gap-2);
    }

    .hub-regal--kompakt .hub-kachel:not(.hub-kachel--bald) {
        display: grid;
        grid-template-columns: 6rem minmax(0, 1fr);
        grid-template-rows: auto auto auto 1fr auto auto;
        grid-template-areas:
            'bild kopf'
            'bild titel'
            'bild bekannt'
            'bild plaketten'
            'satz satz'
            'knoepfe knoepfe';
        align-items: start;
        gap: var(--hub-gap-1) var(--hub-gap-2);
        padding: var(--hub-gap-2);
    }

    .hub-regal--kompakt .hub-kachel:not(.hub-kachel--bald) .hub-kachel__text {
        display: contents;
    }

    .hub-regal--kompakt .hub-kachel__fenster {
        grid-area: bild;
        aspect-ratio: 1;
        border-radius: var(--hub-radius-m);
    }

    .hub-regal--kompakt .hub-kachel__kopf {
        grid-area: kopf;
    }

    .hub-regal--kompakt .hub-kachel__titel {
        grid-area: titel;
        font-size: 1.2rem;
    }

    .hub-regal--kompakt .hub-kachel__bekannt {
        grid-area: bekannt;
        font-size: 0.8rem;
        line-height: 1.35;
    }

    .hub-regal--kompakt .hub-kachel__plaketten {
        position: static;
        grid-area: plaketten;
        justify-content: flex-start;
    }

    .hub-regal--kompakt .hub-kachel__aufhaenger {
        grid-area: satz;
        margin-top: var(--hub-gap-1);
        font-size: 0.95rem;
        line-height: 1.5;
    }

    .hub-regal--kompakt .hub-kachel:not(.hub-kachel--bald) .hub-kachel__dossier {
        display: none;
    }

    .hub-regal--kompakt .hub-arenaknoepfe {
        grid-area: knoepfe;
        flex-wrap: nowrap;
        padding-top: var(--hub-gap-1);
    }

    .hub-regal--kompakt .hub-arenaknoepfe .hub-btn {
        flex: 1 1 0;
        padding-inline: var(--hub-gap-2);
        font-size: 0.88rem;
        letter-spacing: 0.02em;
    }

    .hub-regal--kompakt .hub-kachel--bald .hub-kachel__fenster {
        display: none;
    }
}

/*
 * DIE SPIELERZAHL IST EINE PLAKETTE AUS DEM KINO. Sie liegt auf dem Banner
 * einer Kachel und im Kopf einer Vitrine — beide Male die erste Frage an einen
 * Tisch, und beide Male in demselben Ton: `--hub-kino-text` auf `--hub-kino`
 * haelt 17,00:1, gleich ob darunter ein Bild liegt oder weisses Papier.
 *
 * AUF DEM BANNER LIEGT SIE UEBER DER VIGNETTE (`z-index`), aber unter dem
 * Griff der Kachel: Das Fenster bildet keinen eigenen Stapel, und der Link
 * steht im Markup spaeter. Ein Klick auf die Plakette ist ein Klick auf den
 * Tisch.
 */
.hub-spieler {
    display: inline-block;
    padding: 2px var(--hub-gap-2);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    white-space: nowrap;
    border-radius: var(--hub-radius-m);
}

.hub-kachel__fenster > .hub-spieler {
    position: absolute;
    top: var(--hub-gap-2);
    left: var(--hub-gap-2);
    z-index: 1;
    border: 1px solid var(--hub-kino-kante);
}

.hub-kachel__wartung {
    margin: 0;
    padding: var(--hub-gap-2);
    border-left: 4px solid var(--hub-signal);
    background: var(--hub-feld-grund);
    font-size: 0.9rem;
    border-radius: var(--hub-radius-m);
}

.hub-kachel__daten {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--hub-gap-1) var(--hub-gap-2);
    margin: 0;
    font-size: 0.85rem;
}

.hub-kachel__paar dt {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.7rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-kachel__paar dd {
    margin: 0;
    font-family: var(--hub-font-zahl);
    hyphens: none;
}

/*
 * DIE HERKUNFT EINER GEMESSENEN ZAHL STEHT ALS WORT DANEBEN und nie in einem
 * `title`: Kein Telefon zeigt einen Tooltip. "gemessen" heisst, die Zahl kommt
 * aus zehn echten Laeufen im Laufbuch.
 *
 * Ein zweites Wort gibt es nicht mehr. "geschaetzt" stand als Fussnote hinter
 * jeder ungemessenen Dauer und las sich wie eine Rueckversicherung gegen eine
 * Beschwerde; eine geschaetzte Dauer sagt man mit "ca." davor.
 */
.hub-kachel__quelle {
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-text);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-kachel__laufbuch {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.8rem;
    hyphens: none;
}

/*
 * HIER STAND `.hub-kachel__mehr`, EIN UNTERSTRICHENER LINK NEBEN EINEM KNOPF.
 *
 * Zwei Handgriffe von ungleichem Gewicht in derselben Zeile: Der eine war ein
 * Knopf in der Akzentfarbe, der andere sah aus wie eine Fussnote. Beide fuehren
 * inzwischen an einen Ort, an dem man etwas tut - der eine an den Tisch, der
 * andere in die Akte -, und beide sind deshalb Knoepfe: `hub-btn hub-btn--geist`.
 * Die Klasse ist ersatzlos gefallen, damit sie nicht als leerer Name
 * weiterlebt.
 */

/* ------------------------------------------------------- Die Banderole */

/*
 * ALLE ZEHN TISCHE, LANGSAM VORBEILAUFEND.
 *
 * SIE WAR EIN RASTER AUS VIER KACHELN — eine Spalte, ab 46rem zwei, ab 68rem
 * vier — mit einem Knopf „alle Spiele" daneben. Das hat die Arena kleiner
 * gemacht, als sie ist: vier Tische und ein Knopf, der sechs weitere
 * behauptet. Ein Band zeigt sie alle, ohne die Startseite zu einem zweiten
 * Regal zu machen.
 *
 * SIE IST DIE EINE BEWEGUNG DIESES FOYERS, DIE VON SELBST LAEUFT, und sie
 * haelt sich an die Hausregeln: `linear`, kein Federn, kein Nachwippen — nur
 * eben nicht 120 ms, sondern sechzig Sekunden. Ein Uebergang von 120 ms ist
 * eine Antwort auf einen Griff; das hier ist eine Auslage, die sich dreht. Der
 * Film auf `/faelle` ist der einzige andere, und auch der laeuft erst auf
 * Druck.
 *
 * DREI RIEGEL STEHEN DAVOR, und jeder schaltet sie ganz ab:
 *   · KEIN ZEIGEGERAET  — auf dem Telefon ist sie ein Streifen, den man
 *     wischt. Eine Bewegung, gegen die der Daumen anschiebt, ist ein Kampf.
 *   · ZEIGER ODER FOKUS DRIN — ein Ziel, das unter dem Zeiger wegläuft, ist
 *     keines; ein Fokusrahmen, der aus dem Bild fährt, erst recht nicht.
 *   · WENIGER BEWEGUNG BESTELLT — dann ist sie derselbe wischbare Streifen.
 *
 * DAS FENSTER SCROLLT IMMER (`overflow-x: auto`), auch auf dem Schreibtisch:
 * Wer die Bewegung anhält und weiterblättern will, soll es können — mit dem
 * Rad, mit dem Trackpad, mit der Tastatur. Und ohne diese Zeile stünde das
 * Band auf einem Telefon still und unerreichbar.
 */
.hub-banderole {
    margin-bottom: var(--hub-gap-5);
}

/*
 * ES IST EIN SCROLLKASTEN, UND DAS IST DIE AUSNAHME, DIE DIE UEBERLAUFPROBE
 * KENNT. `dev/portal.mjs` und `dev/hub.mjs` messen jedes Element gegen den
 * rechten Fensterrand und ueberspringen ausdruecklich, was in einem waagerecht
 * scrollbaren Kasten liegt — der Kasten SELBST wird weiter gemessen.
 */
.hub-banderole__fenster {
    display: flex;
    gap: var(--hub-gap-3);
    margin-bottom: var(--hub-gap-3);
    overflow-x: auto;
    overflow-y: hidden;
    /*
     * KEIN SCHIEBEBALKEN UNTER DEM BAND.
     *
     * Er stand auf `thin` und hat im Takt der Animation GEZUCKT: Der Transform
     * verschiebt das Band, die scrollbare Flaeche des Fensters waechst damit
     * ueber den Zyklus und springt an seinem Ende zurueck — und der Balken
     * zeichnet jede dieser Aenderungen mit. Auf dem Schreibtisch sah das aus,
     * als rechne die Seite an sich herum.
     *
     * Er faellt, und das Fenster bleibt trotzdem scrollbar: Auf dem Telefon
     * wischt der Daumen, und ein fokussiertes Element holt der Browser von
     * selbst ins Bild. Was hier verschwindet, ist die Anzeige und nicht die
     * Faehigkeit.
     */
    scrollbar-width: none;
    /*
     * DAS GLEIS FAENGT MIT LUFT AN UND HOERT MIT LUFT AUF.
     *
     * Ohne sie stand die erste Kachel hart an der Kante der Schale, und die
     * letzte lief ohne Rand hinaus: Was am Rand halb im Bild steht, sah nach
     * einem Ueberlauf aus und nicht nach einem Fenster, durch das etwas
     * vorbeizieht. Die Luft ist derselbe Abstand, den die Kacheln
     * untereinander haben — und der negative Rand haelt die Flucht mit dem
     * Text darueber.
     *
     * Die vier Pixel oben und unten bleiben: Ein Fokusrahmen an einer Kachel
     * laege sonst zur Haelfte unter der Kante.
     */
    padding: 4px var(--hub-gap-3);
    margin-inline: calc(var(--hub-gap-3) * -1);
}

.hub-banderole__fenster::-webkit-scrollbar {
    display: none;
}

/*
 * SCHNAPPEN NUR DORT, WO NICHTS LAEUFT.
 *
 * `scroll-snap-type` stand am Fenster und galt damit auch, waehrend das Band
 * faehrt — Snap-Bereiche, die sich in jedem Einzelbild verschieben, ziehen in
 * Chromium `scrollLeft` nach. Es gehoert dorthin, wo es etwas nuetzt: unter
 * den Daumen und auf den Schirm, der weniger Bewegung bestellt hat.
 */
@media (hover: none), (pointer: coarse) {
    .hub-banderole__fenster {
        scroll-snap-type: x proximity;
    }
}

@media (prefers-reduced-motion: reduce) {
    .hub-banderole__fenster {
        scroll-snap-type: x proximity;
    }
}

.hub-banderole__band {
    display: flex;
    flex: 0 0 auto;
    gap: var(--hub-gap-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

/*
 * DIE KOPIE STEHT NUR DA, WO DAS BAND LAEUFT.
 *
 * Sie ist die zweite Haelfte des Laufs: Ohne sie risse er am Ende ab. Laeuft
 * nichts, ist sie ein Streifen mit ZEHN sichtbaren, antippbaren Dubletten —
 * auf jedem Telefon und auf jedem Schirm, an dem jemand weniger Bewegung
 * bestellt hat. Fuer einen Schirmleser war sie nie da (`aria-hidden`); fuer
 * Auge und Daumen schon.
 *
 * Sie haengt deshalb an DERSELBEN Bedingung wie die Animation, und zwar
 * andersherum aufgebaut: verborgen als Vorgabe, sichtbar nur in der
 * Medienregel unten. Eine Ausnahme fuer `prefers-reduced-motion` braucht es
 * dann nicht — dort bleibt sie ohnehin verborgen.
 */
.hub-banderole__band--kopie {
    display: none;
}

/*
 * VIER KACHELN IM AUSSCHNITT AUF DEM SCHREIBTISCH, und die Zahl steht als
 * Rechnung da statt als Pixelbreite: vier Spalten und dreimal die Luecke
 * dazwischen, geteilt durch vier. Auf dem Telefon ist eine Kachel 78 Prozent
 * breit — die naechste lugt herein und sagt, dass es weitergeht.
 */
.hub-banderole__fach {
    display: flex;
    flex: 0 0 auto;
    width: 78vw;
    max-width: 22rem;
    scroll-snap-align: start;
}

@media (min-width: 46rem) {
    .hub-banderole__fach {
        width: calc((100% - var(--hub-gap-3)) / 2);
        max-width: none;
    }
}

@media (min-width: 68rem) {
    .hub-banderole__fach {
        /*
         * Das Fach misst gegen die Breite des BANDES und nicht gegen das
         * Fenster — das Band ist doppelt so lang wie sein Fenster. Deshalb
         * eine feste Rechnung aus der Fensterbreite und nicht 25 Prozent.
         */
        width: calc((100vw - 2 * var(--hub-luft) - 3 * var(--hub-gap-3)) / 4);
        max-width: 24rem;
    }
}

@media (min-width: 112.5rem) {
    /* Ab der Buehnenbreite waechst die Flaeche nicht mehr mit dem Fenster. */
    .hub-banderole__fach {
        width: calc((var(--hub-shell) - 2 * var(--hub-luft) - 3 * var(--hub-gap-3)) / 4);
    }
}

@keyframes hub-banderole-lauf {
    from { transform: translate3d(0, 0, 0); }
    /*
     * Ein Band plus die Luecke dahinter: Danach steht die Kopie exakt dort, wo
     * das Original stand, und der Sprung zurueck ist unsichtbar.
     */
    to { transform: translate3d(calc(-100% - var(--hub-gap-3)), 0, 0); }
}

@media (hover: hover) and (pointer: fine) {
    .hub-banderole__band {
        animation: hub-banderole-lauf 60s linear infinite;
    }

    .hub-banderole__band--kopie {
        display: flex;
    }

    /*
     * DIE BEIDEN KANTEN BLENDEN AUS, UND ZWAR NUR, SOLANGE ETWAS LAEUFT.
     *
     * Eine Kachel, die halb im Bild steht, ist bei einem Band der Normalfall —
     * am harten Rand der Schale sah sie trotzdem nach einem Ueberlauf aus:
     * „lette 1923" statt „Roulette 1923", und der Blick sucht den Fehler und
     * nicht die naechste Kachel. Die Blende sagt in zwei Zentimetern, was der
     * Schnitt bedeutet: Hier geht es weiter.
     *
     * ES IST EINE MASKE UND KEINE FLAECHE. Das Verbot in Abschnitt 7 gilt
     * Verlaeufen, die etwas EINFAERBEN; hier faerbt nichts, hier wird
     * abgedeckt. Und es ist kein Weichzeichner: Was durchscheint, ist das
     * Papier der Seite und kein verwaschenes Bild.
     *
     * SIE STEHT IN DERSELBEN MEDIENREGEL WIE DER LAUF. Wo nichts faehrt, gibt
     * es auch nichts, das aus dem Bild laeuft: Auf dem Telefon schnappt das
     * Band, und was dort halb dasteht, hat der Daumen selbst dorthin
     * geschoben. Eine Blende waere da eine Auskunft ueber nichts — und auf
     * einer Kante, die gerade unter dem Finger liegt, eine irritierende.
     */
    .hub-banderole__fenster {
        /*
         * SIE IST BREIT GENUG, UM EIN WORT ZU SCHLUCKEN, und das ist die Zahl,
         * auf die es ankommt. Bei dreissig Pixeln blieb „artenhai" stehen und
         * sah aus wie ein Tippfehler; erst wenn die Blende so breit ist wie
         * der Innenrand einer Kachel plus ein paar Buchstaben, liest sich der
         * Rand als Rand. Auf 375 px sind es zwei Zentimeter, auf 2560 fuenf.
         */
        --hub-blende: clamp(2rem, 6vw, 5rem);

        -webkit-mask-image: linear-gradient(
            to right,
            transparent 0,
            #000 var(--hub-blende),
            #000 calc(100% - var(--hub-blende)),
            transparent 100%
        );
        mask-image: linear-gradient(
            to right,
            transparent 0,
            #000 var(--hub-blende),
            #000 calc(100% - var(--hub-blende)),
            transparent 100%
        );
    }

    /*
     * UND SIE FAELLT, SOBALD JEMAND HINEINTABBT.
     *
     * Die Blende deckt die ersten Pixel ab — samt einem Fokusrahmen, der dort
     * liegt. Ein halb ausgeblendeter Fokusrahmen ist schlimmer als eine harte
     * Kante: Er sagt nicht mehr, wo man steht. Das Band haelt in demselben
     * Augenblick ohnehin an (`:focus-within` eine Regel weiter unten), und der
     * Browser holt das fokussierte Element von selbst ins Bild.
     */
    .hub-banderole__fenster:focus-within {
        -webkit-mask-image: none;
        mask-image: none;
    }

    .hub-banderole__fenster:hover .hub-banderole__band,
    .hub-banderole__fenster:focus-within .hub-banderole__band {
        animation-play-state: paused;
    }
}

.hub-vitrine {
    /* Der Containing Block fuer das Overlay des Titellinks, wie bei der Kachel. */
    position: relative;
    display: grid;
    grid-template-columns: 7rem minmax(0, 1fr);
    width: 100%;
    overflow: hidden;
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

@media (min-width: 46rem) {
    .hub-vitrine {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto 1fr;
    }
}

.hub-vitrine:has(.hub-vitrine__link:focus-visible) {
    outline: var(--hub-ring) solid var(--hub-signal);
    outline-offset: 2px;
}

.hub-vitrine__fenster {
    position: relative;
    min-height: 100%;
    background: var(--hub-kino);
}

@media (min-width: 46rem) {
    .hub-vitrine__fenster {
        aspect-ratio: 16 / 9;
    }
}

.hub-vitrine__bild {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hub-vitrine__text {
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-1);
    min-width: 0;
    padding: var(--hub-gap-2) var(--hub-gap-3) var(--hub-gap-3);
}

.hub-vitrine__kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-1) var(--hub-gap-2);
    margin: 0;
}

.hub-vitrine__marke {
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-vitrine__titel {
    margin: 0;
    font-size: 1.15rem;
    line-height: 1.2;
}

.hub-vitrine__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    text-decoration: none;
}

.hub-vitrine__link::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
}

.hub-vitrine__satz {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 0.92rem;
    text-wrap: pretty;
}

/* Der Weg in die Vitrine, unter dem Band. Er hiess `.hub-schaufenster__alle`,
   und das war der Rest eines Blocks, den es nicht mehr gibt — ein Element ohne
   seinen Block ist ein Name, den beim naechsten Umbau niemand mehr findet. */
.hub-banderole__alle {
    margin: 0;
}

/* ============================================================ Das Schaufenster
 *
 * SECHS TISCHE IM ERSTEN BILDSCHIRM. Die Kachel ist die der Vitrine (`.hub-vitrine`), nur waagerecht und ohne Satz: das
 * Bild links, rechts die Spielerzahl, der Name und die Knoepfe. Ein Bild oben haette bei drei Spalten je 240 Pixel gekostet,
 * zwei Reihen also fast die ganze Hoehe eines Schreibtischfensters — und die Startseite soll ihr Angebot zeigen, nicht
 * ihr Titelbild. Marke und Satz („warum man sich an diesen Tisch setzt“) traegt die Vitrine; hier kostete jede der beiden
 * Zeilen in jeder Kachel zwanzig bis vierzig Pixel, ueber zwei Reihen ein ganzes Fenster.
 *
 * DAS RASTER WECHSELT AN DEN KANTEN DES HAUSES: eine Spalte unter 40rem (dort steht die Kachel als Zeile mit dem
 * kleinen Bild, wie in der Banderole), zwei bis 64rem, drei darueber. Die Knoepfe stehen nebeneinander, solange der
 * Text daneben sie fasst, und sonst untereinander (`flex-wrap`) — dieselbe Kachel wird so auf 1440 Pixeln rund 150 und
 * auf 1100 rund 200 Pixel hoch, und keine Breite braucht eine eigene Regel.
 *
 * DIE KNOEPFE LIEGEN UEBER DEM OVERLAY DES TITELS (`.hub-arenaknoepfe`, `z-index`): Der Titel deckt die ganze Kachel,
 * und ohne die Ebene waere jeder Tipp auf einen Knopf ein Tipp auf den Titel.
 */
.hub-top {
    margin-top: var(--hub-gap-4);
}

.hub-top__raster {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--hub-spalt);
    margin: 0 0 var(--hub-gap-3);
    padding: 0;
    list-style: none;
}

@media (min-width: 40rem) {
    .hub-top__raster {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 64rem) {
    .hub-top__raster {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.hub-top__fach {
    display: flex;
}

.hub-top__alle {
    display: flex;
    justify-content: center;
    margin: 0;
}

/* ============================================================ Die Flaggschiff-Buehne
 *
 * DAS POINT & CLICK UNTER DER SCHLAGZEILE, auf dem Sockel des Hauses (`--hub-kino`) wie der Salon: links das
 * Bildschirmfoto aus dem Spiel, rechts Dach, Titel, der Satz des Spiels, der Satz des Hauses, Eckdaten und EIN Knopf.
 * Die Goldkante oben ist Praegung und keine Flaeche (zwei Pixel, Abschnitt 7). Nebeneinander erst ab 62rem, der Kante
 * des Hauses fuer Raster; darunter steht das Bild ueber dem Text.
 *
 * DER TITEL IST DER WEG, UND ER DECKT DIE GANZE BUEHNE (`::after`): Wer auf das Bild tippt, will ins Spiel. Der Knopf
 * liegt darueber (`z-index: 2`) und fuehrt mit `?tisch=1` gleich an das Namensfeld.
 *
 * SIE STEHT HINTER DEN SECHS TISCHEN UND VOR DEM SALON, auf jeder Breite (`portal.php` sagt, warum).
 */
.hub-flaggschiff {
    position: relative;
    display: grid;
    gap: var(--hub-gap-3) var(--hub-gap-4);
    align-items: center;
    margin-top: var(--hub-gap-4);
    padding: clamp(var(--hub-gap-2), 2vw, var(--hub-gap-4));
    border-top: 2px solid var(--hub-gold);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    border-radius: var(--hub-radius-l);
}

@media (min-width: 62rem) {
    .hub-flaggschiff {
        grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    }
}

.hub-flaggschiff__fenster {
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--hub-kino-karte);
    border-radius: var(--hub-radius-m);
}

.hub-flaggschiff__bild {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hub-flaggschiff__text {
    display: grid;
    gap: var(--hub-gap-2);
    align-content: start;
}

.hub-flaggschiff__dach {
    margin: 0;
    color: var(--hub-messing-hell);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-flaggschiff__titel {
    margin: 0;
    font-size: clamp(1.9rem, 3.2vw, 2.8rem);
    font-weight: 800;
    line-height: 1.05;
}

.hub-flaggschiff__link {
    color: inherit;
    text-decoration: none;
}

.hub-flaggschiff__link::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
}

.hub-flaggschiff__link:focus-visible {
    outline: none;
}

.hub-flaggschiff:has(.hub-flaggschiff__link:focus-visible) {
    outline: 3px solid var(--hub-messing-hell);
    outline-offset: 3px;
}

.hub-flaggschiff__aufhaenger {
    margin: 0;
    font-family: var(--hub-font-comic);
    font-size: 1.1rem;
    line-height: 1.45;
}

.hub-flaggschiff__satz,
.hub-flaggschiff__fein {
    margin: 0;
    color: var(--hub-kino-still);
}

.hub-flaggschiff__fein {
    font-size: 0.85rem;
}

/* Die Plaketten der Wege stehen sonst auf Papier; auf dem Sockel tragen sie dessen Kante und Schrift. */
.hub-flaggschiff .hub-weg__eck {
    border-color: var(--hub-kino-kante);
    background: transparent;
    color: var(--hub-kino-text);
}

.hub-flaggschiff__knopf {
    position: relative;
    z-index: 2;
    margin: 0;
}

/* Waagerecht auf JEDER Breite: Die Regel der Vitrine stapelt ab 46rem, und diese hier steht spaeter und gewinnt. */
.hub-vitrine--top {
    grid-template-columns: minmax(5.5rem, 30%) minmax(0, 1fr);
    grid-template-rows: none;
}

@media (min-width: 46rem) {
    .hub-vitrine--top .hub-vitrine__fenster {
        aspect-ratio: auto;
    }
}

.hub-vitrine--top .hub-vitrine__text {
    padding: var(--hub-gap-2);
}

.hub-vitrine--top .hub-arenaknoepfe .hub-btn {
    padding-inline: var(--hub-gap-2);
    font-size: 0.85rem;
    letter-spacing: 0.02em;
}

/* ========================================================== Die zwei Knoepfe
 *
 * „ALLEIN ZOCKEN“ UND „MIT FREUNDEN“ — auf der Startseite wie in der Vitrine, aus derselben Funktion
 * (`tr_arena_knoepfe()`). Der erste ist das warme Messing und der Hauptweg, wo es ihn gibt; der zweite ist der
 * Geistknopf des Hauses. Die Zeichen sind SVG-Pfade in der Schriftfarbe des Knopfes und keine Emoji.
 *
 * SIE LIEGEN UEBER DEM OVERLAY DES TITELLINKS (`position: relative; z-index: 2`), aus demselben Grund wie der
 * Tuerknopf der Kachel, und der Streifen sitzt unten (`margin-top: auto`): Zwei Kacheln in einer Reihe haben
 * verschieden lange Saetze, und zwei Knopfreihen auf verschiedenen Hoehen sehen aus wie zwei Rangstufen.
 */
.hub-arenaknoepfe {
    position: relative;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2);
    margin: auto 0 0;
    padding-top: var(--hub-gap-2);
}

.hub-arenaknoepfe .hub-btn {
    flex: 1 1 auto;
}

.hub-btn__zeichen {
    flex: 0 0 auto;
    width: 1.05em;
    height: 1.05em;
    fill: currentColor;
}

.hub-btn--solo {
    border-color: var(--hub-messing);
    background: var(--hub-messing-hell);
    color: var(--hub-tinte);
}

.hub-btn--solo:hover {
    border-color: var(--hub-tinte);
    background: var(--hub-tinte);
    color: var(--hub-messing-hell);
}

/* --------------------------------------------------- Blockabstaende */

/*
 * HIER STANDEN SECHS BLOECKE, VON DENEN VIER MIT DER FALLSEITE GEFALLEN SIND:
 * .hub-schleuse (elf Elemente), .hub-steckbrief, .hub-bedarf und .hub-eckdaten.
 * Sie hatten genau einen Verbraucher — den Steckbrief unter /fall/<slug> —, und
 * der ist zur Weiche geworden: Die Akte selbst liegt seither im Zimmer.
 *
 * Was blieb, ist der gemeinsame Abstand darunter und das Zeilenmass.
 */
.hub-terminal,
.hub-technik,
.hub-kasse,
.hub-leerseite {
    margin-bottom: var(--hub-gap-5);
}

.hub-kasse__satz,
.hub-leerseite p {
    max-width: var(--hub-mass);
    margin: 0 0 var(--hub-gap-3);
}

/* ---------------------------------------- Die Registratur und die Akte */

/*
 * DER SCHRANK STEHT AUCH IM FOYER, und zwar seit die Akte eines Falls ohne
 * Zimmer die EINE kanonische Sicht dieses Falls ist.
 *
 * Wer in einem Zimmer auf den Reiter von Fall 03 greift, landet hier — und
 * muss von hier aus zu jedem anderen Fall zurueckfinden, ohne den Umweg ueber
 * das Regal. Das Markup baut shared/haus/haus.php; die Gestalt gehoert dem
 * Haus, in dem der Schrank steht: hier Naturpapier und Tinte, drueben die Palette
 * des jeweiligen Falls.
 *
 * DER OFFENE DECKEL TRAEGT HIER aria-current UND NICHT aria-pressed. Unter ihm
 * liegt kein Blatt, das ein Schalter umklappen koennte — die SEITE ist der
 * Vorgang. Deshalb steht dort ein <span> und kein <button>.
 */
.registratur {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: var(--hub-gap-1);
    margin-bottom: 0;
}

.registratur__akte {
    /*
     * Drei Deckel passen auf 375 px nicht in eine Reihe: Bei je knapp 110 px
     * braeche der Titel vierzeilig um. Eine echte Basis laesst den dritten in
     * die zweite Reihe fallen — ein Registraturschrank mit zwei Reihen Reiter
     * ist immer noch ein Registraturschrank.
     */
    flex: 1 1 11rem;
    min-width: 0;
    display: grid;
    align-content: center;
    gap: 0.1rem;
    min-height: var(--hub-griff);
    /*
     * DER OFFENE DECKEL STEHT HOEHER, und das ist die eigentliche Auskunft.
     * Farbe ist nie der einzige Informationstraeger.
     */
    margin-top: 8px;
    padding: var(--hub-gap-2);
    /*
     * DER GRIFFTON, UND ZWAR AUS DEMSELBEN GRUND WIE BEIM SIEB. Ein
     * geschlossener Deckel ist weisse Flaeche auf fast weissem Papier
     * (1,05:1) ohne Schatten — seine Kante traegt ihn allein. Mit
     * --hub-kante waren das 1,31:1, und zwei Deckel nebeneinander waren
     * durch ihre 0,35rem Lucke nicht als zwei Griffe zu erkennen.
     * --hub-kante-griff haelt 3,34:1 gegen die Seite und 3,51:1 gegen die
     * eigene Flaeche.
     */
    border: 1px solid var(--hub-kante-griff);
    border-bottom: 0;
    background: var(--hub-grund-karte);
    color: var(--hub-tinte-sekundaer);
    text-decoration: none;
    transition: color var(--hub-schnell), background-color var(--hub-schnell);
}

.registratur__akte:hover {
    color: var(--hub-tinte);
    background: var(--hub-grund-subtil);
}

.registratur__akte[aria-current='page'] {
    margin-top: 0;
    border-top: 3px solid var(--hub-akzent);
    padding-top: calc(var(--hub-gap-2) - 2px);
    background: var(--hub-grund);
    color: var(--hub-tinte);
}

.registratur__nummer {
    font-family: var(--hub-font-doc);
    font-size: 0.66rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.registratur__titel {
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.15;
    /* Ein einziges langes Wort hielte die Spalte sonst auf. */
    overflow-wrap: anywhere;
}

.registratur__stand {
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    color: var(--hub-tinte-gedaempft);
}

.registratur__pfeil {
    /* In em, damit er mit der Nummer waechst. Auf der Grundlinie statt
       darueber: Die Nummer steht in Versalien. */
    width: 0.95em;
    height: 0.95em;
    vertical-align: baseline;
}

/*
 * DIE AKTE SELBST — und der Satz, der hier stand, ist mit dem Umbau gefallen.
 *
 * Er lautete: "Blech, kein Papier — von diesem Fall ist nichts gedruckt", und
 * er trug die Unterscheidung, dass der Papierton dem GEGENSTAND gehoert und
 * nicht der Ansicht. Die Regel gilt woertlich weiter; ihr BELEG ist ein
 * anderer geworden, seit das ganze Foyer auf Papier steht. Blech gibt es hier
 * nicht mehr, gegen das sich eine duenne Akte absetzen koennte.
 *
 * Was von diesem Fall nichts gedruckt hat, sagt seitdem der INHALT: keine
 * Schlagzeile, kein Korrespondent, ein Aktenzeichen, ein Aushang und vier
 * Absaetze. Und die Anrisskante oben traegt seine eigene Farbe aus der Kartei.
 */
.hub-akte {
    padding: var(--hub-gap-4);
    border: 1px solid var(--hub-kante);
    border-top: 3px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

.hub-akte__kopf {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--hub-gap-2);
    margin-bottom: var(--hub-gap-3);
    padding-bottom: var(--hub-gap-2);
    border-bottom: 1px solid var(--hub-kante);
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.7rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

/*
 * DER STEMPEL. Eine Kante und ein Wort — kein Balken Druckerschwaerze: Eine
 * harte Flaeche ueber einer Zeile sieht nach einem kaputten Schirm aus und
 * nicht nach einem Vermerk.
 */
.hub-akte__marke {
    display: inline-block;
    margin: 0 0 var(--hub-gap-3);
    padding: 0.25rem var(--hub-gap-2);
    border: 1px solid var(--hub-akzent);
    color: var(--hub-tinte);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-akte__zeile {
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-akte__titel {
    max-width: var(--hub-hero-mass);
    margin: var(--hub-gap-1) 0 var(--hub-gap-3);
    font-size: clamp(1.6rem, 4vw, 2.4rem);
    line-height: 1.1;
    text-wrap: balance;
}

/*
 * DER KOERPER DER AKTE: eine Spalte auf dem Telefon, zwei ab 60rem.
 *
 * Links der Vorgang (Absaetze, Randvermerk, Stimmen), rechts der Aushang und
 * der Vordruck. Die Schwelle haengt am FENSTER und nicht am Geraet: Unter
 * 60rem waere die Randspalte so schmal, dass der Aushang zur Briefmarke und
 * das Adressfeld zur Rinne wird.
 *
 * `align-items: start` ist Pflicht, sonst zieht die laengere Spalte die
 * kuerzere auf ihre Hoehe und der Aushang steht in der Mitte eines leeren
 * Kastens.
 *
 * `minmax(0, 1fr)` und nicht `1fr`: Eine Grid-Spalte ist von Haus aus
 * mindestens so breit wie ihr laengster unteilbarer Inhalt, und das Bild
 * darin bringt 1920 Pixel mit. Ohne die Null sprengt es die Spalte, und der
 * Ueberlaufmesser meldet auf jeder Breite eine Seite, die seitwaerts rollt.
 */
.hub-akte__koerper {
    display: grid;
    gap: var(--hub-gap-4);
}

@media (min-width: 60rem) {
    .hub-akte__koerper {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        align-items: start;
    }
}

/*
 * Die Randspalte klebt beim Mitscrollen NICHT. Sie ist kuerzer als der
 * Vorgang daneben, und eine mitfahrende Karte mit einem Eingabefeld darin ist
 * auf einem kurzen Schirm genau das, was man beim Lesen nicht gebrauchen kann.
 */
.hub-akte__spalte {
    min-width: 0;
}

/* Dasselbe Fenster wie auf der Kachel: Wer vom Regal kommt, erkennt den Aushang wieder. */
.hub-akte__bild {
    margin: 0 0 var(--hub-gap-3);
}

.hub-akte__fenster {
    border-radius: var(--hub-radius-m);
}

.hub-akte__bildzeile {
    margin-top: var(--hub-gap-1);
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-akte__satz p {
    max-width: 100%;
    margin: 0 0 var(--hub-gap-3);
    text-wrap: pretty;
}

.hub-akte__notiz {
    max-width: 100%;
    margin: 0 0 var(--hub-gap-4);
    padding-left: var(--hub-gap-3);
    border-left: 2px solid var(--hub-kante);
    color: var(--hub-tinte-gedaempft);
    font-style: italic;
    text-wrap: pretty;
}

.hub-akte__comic {
    margin: 0 0 var(--hub-gap-4);
}

/*
 * STIMMEN AUF DER AKTE — untereinander und nicht als Kartenraster.
 *
 * Die Startseite stellt bis zu drei Stimmen NEBENEINANDER: Dort sind sie ein
 * Beleg unter vielen, und drei Karten lesen sich als eine Reihe. Hier stehen
 * sie in einem Dokument, zwischen Prosa und einem Formular — nebeneinander
 * wären sie ein Kasten, der die Akte unterbricht.
 *
 * Sie nehmen dieselben Kindklassen wie im Regal (`.hub-stimme__*`): Dieselbe
 * Sache sieht an zwei Orten gleich aus, nur anders angeordnet.
 */
.hub-akte__stimmen {
    max-width: 100%;
    margin: 0 0 var(--hub-gap-4);
}

.hub-akte__stimmenkopf {
    margin: 0 0 var(--hub-gap-2);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-akte__stimme {
    display: grid;
    gap: var(--hub-gap-2);
    margin: 0 0 var(--hub-gap-3);
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    border-left: 3px solid var(--hub-stern);
    border-radius: var(--hub-radius-m);
    background: var(--hub-grund-karte);
}

.hub-akte__vormerkung {
    max-width: 100%;
    margin-top: var(--hub-gap-4);
    padding-top: var(--hub-gap-3);
    border-top: 1px solid var(--hub-kante);
}

.hub-akte__aufruf {
    margin: 0 0 var(--hub-gap-2);
    text-wrap: pretty;
}

/*
 * DAS ANKREUZFELD BRINGT SEINE GRUNDSTELLUNG SELBST MIT.
 *
 * Dieselbe Falle wie im Meldebogen des Tresens: Ein Haus, dessen base.css
 * "input { width: 100% }" fuehrt, macht daraus ein Kaestchen von 377 Pixeln
 * Breite mit der Beschriftung rechts daneben. Das Foyer fuehrt die Regel
 * heute nicht — aber der naechste Umbau kann sie bringen, und dann sucht
 * niemand den Fehler hier.
 */
.hub-akte__haken {
    display: flex;
    align-items: center;
    gap: var(--hub-gap-2);
    min-height: var(--hub-griff);
    cursor: pointer;
}

.hub-akte__haken input {
    flex: none;
    width: 1.15rem;
    height: 1.15rem;
    margin: 0;
}

.hub-akte__feld {
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-2);
    margin-top: var(--hub-gap-2);
}

.hub-akte__vormerkkopf {
    margin: 0 0 var(--hub-gap-2);
    font-size: clamp(1.15rem, 3.2vw, 1.45rem);
    line-height: 1.2;
    text-wrap: balance;
}

/*
 * Die Aufschrift des Eingabefeldes, nicht die des Hakens: Der Haken ist auch
 * ein <label> und steht seit dem Umbau IM Feldkasten — in Versalien und
 * 0,72 rem waere seine Einwilligung eine Fussnote.
 */
.hub-akte__feld > label:not(.hub-akte__haken) {
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    color: var(--hub-tinte-sekundaer);
}

.hub-akte__feld input[type='email'] {
    /* Vierundvierzig in BEIDE Richtungen: Der Daumen ist rund. */
    min-height: var(--hub-griff);
    width: min(100%, var(--hub-terminal-mass));
    padding: 0 var(--hub-gap-2);
    border: 1px solid var(--hub-kante-griff);
    border-radius: 0;
    background: var(--hub-feld-grund);
    color: var(--hub-tinte);
    font: inherit;
}

.hub-akte__note,
.hub-akte__quittung {
    max-width: 100%;
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-size: 0.78rem;
    text-wrap: pretty;
}

.hub-akte__quittung:empty {
    display: none;
}

/*
 * DER WEG ZURUECK INS REGAL — und er heisst nicht mehr `hub-akte__zurueck`.
 *
 * Er gehoerte dem Aktenblock und stand seit `/spenden` auf einer Seite, die
 * keine Akte ist: ein Kindklassenname ausserhalb seines Blocks. Er traegt
 * ohnehin nur einen Abstand, und den braucht jede Seite, die unten einen
 * einzelnen Knopf hat.
 */
.hub-zurueck {
    margin: var(--hub-gap-4) 0 0;
}

/* -------------------------------------------------- Das Code-Terminal */

/*
 * DIE SEITE /tisch HAT EINEN ZWECK UND DARIN EIN FELD.
 *
 * Hier standen `.hub-schluessel__form` und drei Geschwister: eine liegende
 * Flexzeile aus Label, Feld und Knopf, linksbuendig ueber die volle
 * Schalenbreite. Auf einem Schreibtisch war das ein Formularfeld von sieben
 * Zeichen irgendwo links oben und daneben tausend Pixel Blech.
 *
 * Jetzt ist es eine Karte, mittig, schmal – und das Feld darin ist gross.
 * Wer hierher kommt, hat fuenf Zeichen im Ohr und sucht den Kasten, in den
 * sie gehoeren.
 */
.hub-terminal {
    /* min(): Auf 375 px ist die Hoechstbreite kein Mass, sondern ein
       Ueberlauf – die Karte nimmt dort, was da ist. */
    width: min(var(--hub-terminal-mass), 100%);
    margin-inline: auto;
    padding: var(--hub-gap-4);
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    text-align: center;
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

.hub-terminal__titel {
    margin: 0 0 var(--hub-gap-2);
    font-size: clamp(1.3rem, 3vw, 1.7rem);
    line-height: 1.25;
}

.hub-terminal__satz {
    margin: 0 0 var(--hub-gap-3);
    color: var(--hub-tinte-sekundaer);
}

/* Ein Satz mit einer Signalkante links liest sich mittig gesetzt wie ein
   Umbruchfehler: Die Kante steht dann neben zwei kurzen Zeilen statt vor
   einem Absatz. */
.hub-terminal__absage {
    margin: 0 0 var(--hub-gap-3);
    text-align: left;
}

.hub-terminal__form {
    margin: 0;
}

.hub-terminal__label {
    display: block;
    margin-bottom: var(--hub-gap-1);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.75rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-terminal__feld {
    display: block;
    width: 100%;
    min-height: calc(var(--hub-griff) * 1.4);
    padding: var(--hub-gap-2);
    border: var(--hub-border) solid var(--hub-kante-griff);
    background: var(--hub-feld-grund);
    color: var(--hub-tinte);
    font-family: var(--hub-font-zahl);
    /* Der untere Wert ist ABSOLUT und liegt ueber sechzehn Pixeln: Darunter
       zoomt iOS beim Antippen in das Feld hinein und die halbe Seite ist weg.
       Nach oben darf es hier weit gehen – das Feld IST der Zweck der Seite. */
    font-size: clamp(24px, 8vw, 2.4rem);
    letter-spacing: 0.25em;
    /* Die Sperrung haengt auch hinter dem letzten Zeichen und schoebe eine
       zentrierte Zeile sonst um genau diesen Betrag nach links. */
    text-indent: 0.25em;
    text-align: center;
    text-transform: uppercase;
    hyphens: none;
    border-radius: var(--hub-radius-m);
}

.hub-terminal__knopf {
    display: flex;
    width: 100%;
    margin-top: var(--hub-gap-3);
}

/*
 * ZWEI WEGE NEBENEINANDER — die Einstiegskachel von `/spiele`.
 *
 * `__knopf` daneben ist EIN Knopf ueber die volle Breite (das Terminal von
 * `/tisch` hat genau einen). Hier stehen zwei, und sie gehoeren in eine Reihe,
 * die auf dem Telefon umbricht. Zentriert, weil die ganze Kachel es ist.
 */
.hub-terminal__knoepfe {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--hub-gap-2);
    margin: var(--hub-gap-3) 0 0;
}

.hub-terminal__note {
    margin: var(--hub-gap-3) 0 0;
    color: var(--hub-tinte-gedaempft);
    font-size: 0.85rem;
}

/* ---------------------------------------------------------- Kasse */

.hub-kasse__rolle {
    max-width: var(--hub-mass);
    margin: 0 0 var(--hub-gap-3);
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    background: var(--hub-grund-karte);
    list-style: none;
    font-family: var(--hub-font-doc);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

.hub-kasse__zeile {
    display: flex;
    align-items: baseline;
    gap: var(--hub-gap-2);
}

.hub-kasse__zeile + .hub-kasse__zeile {
    margin-top: var(--hub-gap-1);
}

/* Eine gepunktete Fuellzeile und ausdruecklich KEIN Balken: Ein Balken waere
   ein Fortschritt auf ein Ziel, und ein Ziel erzeugt die Frage, was passiert,
   wenn es nicht erreicht wird. */
.hub-kasse__punkte {
    flex: 1;
    border-bottom: 1px dotted var(--hub-kante-griff);
    transform: translateY(-0.25em);
}

.hub-kasse__zahl {
    hyphens: none;
}

.hub-kasse__wege {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2);
    margin: 0 0 var(--hub-gap-3);
}

.hub-kasse__entlastung {
    max-width: var(--hub-mass);
    margin: 0 0 var(--hub-gap-2);
    color: var(--hub-tinte-sekundaer);
}

.hub-kasse__bon {
    max-width: var(--hub-mass);
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

/* -------------------------------------------------------- Merkmale */

/*
 * VIER ZUSAGEN ALS VIER FLAECHEN, und das ist kein Schmuck.
 *
 * "Was hier nicht passiert" stand als ein Absatz von vier Saetzen in einer
 * Spalte von 68 Zeichen - auf einem Breitbild eine schmale Saeule links, rechts
 * daneben zwei Drittel leeres Blech. Vier Zusagen, die man einzeln pruefen
 * koennen soll (kein Konto? keine Werbung? keine Installation? kostenlos?),
 * lesen sich als Aufzaehlung und nicht als Fliesstext: Wer nach EINER davon
 * sucht, findet sie in einem Absatz erst beim dritten Lesen.
 *
 * DIE ZEICHEN SIND SVG-PFADE IM MARKUP und keine Icon-Schrift und kein Emoji -
 * dasselbe Verbot wie im Zimmer nebenan. Sie tragen keine Auskunft: Ueber jedem
 * steht das Wort, das sie meinen.
 */
.hub-merkmale {
    display: grid;
    gap: var(--hub-gap-3);
    margin: 0 0 var(--hub-gap-4);
    padding: 0;
    list-style: none;
}

@media (min-width: 42rem) {
    .hub-merkmale {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 68rem) {
    .hub-merkmale {
        grid-template-columns: repeat(4, 1fr);
        gap: var(--hub-gap-4);
    }
}

.hub-merkmal {
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-2);
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

.hub-merkmal__zeichen {
    display: block;
    width: 2rem;
    height: 2rem;
    fill: none;
    stroke: var(--hub-akzent-schrift);
    stroke-width: 2;
    stroke-linecap: square;
}

.hub-merkmal__titel {
    margin: 0;
    font-size: 1rem;
    letter-spacing: 0.02em;
}

.hub-merkmal__satz {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 0.92rem;
}

/* ----------------------------------------------------------- Karten */

/*
 * DAS ALLZWECKRASTER FUER SEITEN, DIE ERKLAEREN (Konzept, Ueber uns).
 *
 * Beide Seiten waren Ketten von Ueberschrift-plus-Absatz, jeder Absatz auf 68
 * Zeichen beschnitten und linksbuendig - eine Spalte Text und daneben nichts.
 * Als Karten stehen dieselben Saetze nebeneinander statt untereinander: Man
 * sieht auf einen Blick, dass es VIER Antworten sind, und liest die, die man
 * sucht.
 *
 * `--hub-karten-spalten` steht als Eigenschaft am Raster und nicht als eigene
 * Klasse je Spaltenzahl: Eine Seite mit drei Karten bekommt sonst
 * `.hub-karten--drei` und die naechste `.hub-karten--fuenf`.
 */
.hub-karten {
    --hub-karten-spalten: 2;
    display: grid;
    gap: var(--hub-gap-3);
    margin: 0 0 var(--hub-gap-4);
    padding: 0;
    list-style: none;
}

/*
 * EINE STUFE, UND DAS BLEIBT SO — hier stand eine Nacht lang eine zweite.
 *
 * Der Gedanke war: Vier Karten brauchen mehr Fenster als drei, also erst ab
 * 68rem — dann ab 74 — die gewuenschte Zahl und darunter immer zwei. Gemessen
 * hat sich das nicht gehalten. Bei 74rem stand /konzept zwischen 800 und 1184
 * Pixeln als zwei Karten und eine Waise da; bei 62rem waren die vier Karten
 * von /ueber-uns auf 1024 Pixeln hundertsechzig Pixel breit — drei Woerter je
 * Zeile. **Eine Schwelle, die fuer DREI und fuer VIER Satzkarten gleichzeitig
 * richtig ist, gibt es nicht**, und ein Media-Query kann keine Custom Property
 * lesen, um die Zahl selbst zu erfahren.
 *
 * Wer das doch loesen will, braucht eine Angabe je Liste — und damit genau
 * das, wogegen die Property oben steht. Solange es zwei Kartenlisten im Foyer
 * gibt, ist die eine Stufe die ehrlichere Antwort: Wer mehr Spalten will,
 * setzt `--hub-karten-spalten` und prueft seine Seite auf 800 Pixeln nach.
 */
@media (min-width: 50rem) {
    .hub-karten {
        grid-template-columns: repeat(var(--hub-karten-spalten), 1fr);
        gap: var(--hub-gap-4);
    }
}

.hub-karte {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-2);
    padding: var(--hub-gap-4);
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    overflow: hidden;
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

.hub-karte__marke {
    margin: 0;
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-karte__titel {
    margin: 0;
    font-size: 1.15rem;
    line-height: 1.25;
}

.hub-karte__satz {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
}

/*
 * DIE WERKSTATTKARTE steht am Fuss von "Ueber uns" und traegt keine Akzentkante:
 * Sie ist kein Fall dieses Hauses, sondern ein Verweis nach draussen.
 */
.hub-karte--werkstatt {
    border-top-color: var(--hub-kante);
}

/* ------------------------------------------------------------ Wissen */

/*
 * DER TEXT UNTER DEN KACHELN DER ARENA, und er ist ausdruecklich KEINE KARTE.
 *
 * Direkt unter drei Kacheln stuenden sonst drei weitere weisse Karten mit
 * Schatten und denselben drei Namen — das liest sich als Doppelung und nicht
 * als Text. Gegliedert wird mit einer Linie links, derselben wie unter einer
 * Stimme vom Tisch (`--hub-kante-stark`: eine sichtbare Zaesur, kein Griff),
 * und mit der sekundaeren Tinte.
 *
 * ZWEI SPALTEN AB 62rem UND KEIN KARTENRASTER DARIN: links die Zusagen,
 * rechts die Kurzfassung der Arena. Rechts standen alle Absaetze aus
 * `TR_ARENA` untereinander; die liegen jetzt als Dossier auf ihren Kacheln.
 */
.hub-wissen {
    display: grid;
    gap: var(--hub-gap-4);
    margin-bottom: var(--hub-gap-5);
}

/*
 * ZWEI DOSSIER-KARTEN NEBENEINANDER, mit demselben Polster und derselben
 * Kante wie jede andere Karte dieses Hauses. Die Akzentlinie oben fehlt
 * ausdruecklich: Sie gehoert einem Gegenstand — einem Fall, einem Tisch —,
 * und diese beiden Karten sind Auskunft ueber die Seite selbst.
 */
.hub-wissen__spalte {
    padding: var(--hub-gap-4);
    border: var(--hub-border) solid var(--hub-kante);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

/*
 * DAS SUBGRID IST MIT DEN HAARLINIEN GEFALLEN.
 *
 * Es stand hier, weil beide Ueberschriften eine Unterkante trugen: Die schmale
 * Spalte traegt den langen Kopf, er brach ab 62rem in zwei Zeilen, der daneben
 * blieb bei einer — und die beiden Linien sassen eine Zeile versetzt. Das las
 * sich als Rasterfehler, und das Subgrid gab beiden Spalten dieselben zwei
 * Zeilen.
 *
 * Seit die beiden Bloecke KARTEN sind, gibt es die Linien nicht mehr (die
 * Kante der Karte hat ihre Aufgabe uebernommen) — und damit auch nichts mehr,
 * was versetzt sitzen koennte. Was blieb, war eine leere Zeile unter dem
 * kurzen Kopf: Das Subgrid dehnte ihn auf die Hoehe des langen, und in einer
 * Karte liest sich das als vergessener Absatz. Gleich hoch sind die beiden
 * ohnehin, das macht `align-items: stretch` des Rasters.
 *
 * ZWEI ZU DREI BLEIBT: Links stehen drei kurze Zusagen, rechts zwei Absaetze.
 */
@media (min-width: 62rem) {
    .hub-wissen {
        grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    }
}

/*
 * DER KOPF DER KARTE TRAEGT KEINE ZWEITE LINIE. `.hub-titel` bringt eine
 * Unterkante mit; in einer Karte mit eigener Kante sind das zwei Striche
 * uebereinander, zwei Zentimeter auseinander. Was den Kopf vom Rumpf trennt,
 * ist der Abstand.
 */
.hub-wissen__spalte > .hub-titel {
    border-bottom: 0;
    padding-bottom: 0;
    margin-bottom: var(--hub-gap-3);
    text-wrap: balance;
}

/*
 * `align-content: start`, WEIL DIE KARTE DIE LISTE DEHNT. Beide Karten sind
 * gleich hoch (`align-items: stretch` des Rasters), und die kuerzere zoege
 * ihre drei Zusagen sonst ueber die ganze Hoehe auseinander — jede mit einer
 * Haarlinie von zweihundert Pixeln daneben. Der Grund stand einmal beim
 * Subgrid; das ist gefallen, die Zeile bleibt.
 */
.hub-wissen__liste {
    display: grid;
    align-content: start;
    gap: var(--hub-gap-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

/*
 * DIE HAARLINIE LINKS IST GEFALLEN, DIE KARTE IST DA.
 *
 * Beide Bloecke standen als nackter Text am Seitenende, abgesetzt nur durch
 * einen Strich von einem Pixel — zwei Absaetze, die aussahen, als haette
 * jemand vergessen, sie einzurahmen. Auf einer Seite, auf der DARUEBER zehn
 * Kacheln mit Kante, Rundung und Schatten stehen, liest sich das nicht als
 * Ruhe, sondern als Rest.
 *
 * Jetzt sind es Karten: dieselbe Kante, dieselbe Rundung, derselbe Schatten
 * und dasselbe Polster wie bei `.hub-karte` — kein zweiter Kartenstil, nur
 * dieselben Tokens. Der Strich links braucht es danach nicht mehr; zwei
 * Absetzungen ineinander sind eine zu viel.
 */
.hub-wissen__punkt {
    padding-left: var(--hub-gap-3);
    border-left: var(--hub-border) solid var(--hub-kante-stark);
}

/* `align-content: start` aus demselben Grund wie bei der Liste: Die Karte wird auf die Hoehe der Nachbarkarte gedehnt. */
.hub-wissen__kurz {
    display: grid;
    align-content: start;
    gap: var(--hub-gap-2);
}

.hub-wissen__punkt,
.hub-wissen__satz {
    max-width: 100%;
    margin: 0;
    color: var(--hub-tinte-sekundaer);
}

.hub-wissen__spalte-titel {
    margin: 0 0 var(--hub-gap-2);
    color: var(--hub-tinte);
    font-size: 1.05rem;
    font-weight: 600;
}

.hub-wissen__marke {
    color: var(--hub-tinte);
    font-weight: 600;
}

.hub-wissen__verweis {
    max-width: 100%;
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-size: 0.92rem;
}

/* ---------------------------------------------------- Stimmen vom Tisch */

/*
 * EINE STIMMENKARTE IST EINE KARTE UND KEIN NEUER KASTEN.
 *
 * Sie nimmt `.hub-karte` mit allem, was daran haengt: Kante, Schatten,
 * Radius, Innenabstand, die eine Umbruchstufe bei 50rem. Ein eigener Block
 * waere die zweite Stelle, an der jemand den Kartenschatten nachzieht - und
 * genau der ist es, der eine weisse Karte auf Naturpapier ueberhaupt
 * sichtbar macht (1,03:1 ohne ihn).
 *
 * IHRE KANTE IST DER STERNTON UND NICHT DER AKZENT. Der Akzent gehoert dem
 * FALL und wird je Kachel ueberschrieben; eine Stimme gehoert keinem Fall,
 * sondern einem Abend.
 */
.hub-karte--stimme {
    border-top-color: var(--hub-stern);
}

.hub-stimme__note {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-2);
    margin: 0;
}

.hub-sterne {
    display: inline-flex;
    gap: 2px;
}

/*
 * DER STERN IST EIN ZEICHEN UND TRAEGT NIE ALLEIN DIE AUSKUNFT. Neben der
 * Reihe steht die Zahl ausgeschrieben, und die Reihe selbst ist fuer die
 * Vorlesehilfe unsichtbar (`aria-hidden` am Umschlag).
 *
 * LEER IST NICHT UNSICHTBAR: Der ungefuellte Stern behaelt seine Kontur im
 * Griffton (3,51:1). Ein Stern, den man nicht sieht, macht aus "drei von
 * fuenf" ein "drei".
 */
.hub-stern {
    width: 1rem;
    height: 1rem;
    fill: none;
    stroke: var(--hub-kante-griff);
    stroke-width: 1.6;
    stroke-linejoin: round;
}

.hub-stern--voll {
    fill: var(--hub-stern);
    stroke: var(--hub-stern);
}

.hub-stimme__zahl {
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

/*
 * DAS ZITAT.
 *
 * Ein `blockquote` bringt in jedem Browser einen Einzug mit; hier steht es
 * auf null und traegt stattdessen eine Kante links - dieselbe Haarlinie wie
 * jede andere Gliederung des Foyers. Keine Anfuehrungszeichen als
 * Schmuckzeichen: Was hier steht, ist ein Zitat, und das Element sagt es
 * bereits.
 */
.hub-stimme__satz {
    margin: 0;
    padding-left: var(--hub-gap-3);
    border-left: var(--hub-border) solid var(--hub-kante-stark);
    color: var(--hub-tinte);
    font-size: 1.02rem;
    line-height: 1.5;
}

.hub-stimme__herkunft {
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.82rem;
    hyphens: none;
}

/*
 * DIE WERTUNG AUF EINER FALLKACHEL.
 *
 * Dieselbe Stelle und dasselbe Gewicht wie die Laufbuchzeile darunter: Beide
 * sind gemessene Zahlen ueber diesen Fall und keine Werbung. Der Stern steht
 * davor, der Schnitt in kraeftiger Schrift, der Rest gedaempft.
 */
.hub-kachel__wertung {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4ch;
    margin: 0 0 var(--hub-gap-1);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.8rem;
    hyphens: none;
}

.hub-kachel__wertung .hub-stern {
    fill: var(--hub-stern);
    stroke: var(--hub-stern);
}

.hub-kachel__wertung strong {
    color: var(--hub-tinte);
    font-family: var(--hub-font-zahl);
}

/* ------------------------------------------------------- Grundzeichen */

/*
 * EIN ZEICHEN IM GRUND DER KARTE, und es ist eine Textur und keine Auskunft.
 *
 * Es liegt unten rechts, in Schriftfarbe und auf einem Zehntel Deckkraft, und
 * es sagt nichts, was nicht drei Zeilen darueber als Wort stuende – Personen,
 * Geraet, Mikrofon, Uhr. Deshalb `aria-hidden` im Markup und deshalb dieser
 * Schwund: Waere es kraeftiger, waere es eine zweite Ansage; waere es weicher,
 * braeuchte es einen Weichzeichner, den dieses Haus nicht hat.
 *
 * ES MACHT DIE KARTE NIE HOEHER. Absolut positioniert, also ausserhalb des
 * Flusses; `overflow: hidden` am Kasten schneidet ab, was in die Ecke laeuft.
 *
 * EINE KLASSE FUER ZWEI BLOECKE. Karte und Schritt sind verschiedene Kaesten
 * mit verschiedenem Innenabstand, aber dasselbe Problem – zwei Bauweisen
 * dafuer waeren die zweite Stelle, an der jemand den Schwund nachzieht.
 */
.hub-zeichen--grund {
    position: absolute;
    right: calc(var(--hub-gap-2) * -1);
    bottom: calc(var(--hub-gap-2) * -1);
    z-index: 0;
    width: var(--hub-zeichen-gross);
    height: var(--hub-zeichen-gross);
    opacity: var(--hub-zeichen-schwund);
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: square;
    pointer-events: none;
}

/*
 * UND DER TEXT LIEGT DARUEBER. Ohne diese Zeile gewinnt das Zeichen: Ein
 * positioniertes Element malt nach der Malordnung SPAETER als der Fliesstext
 * seiner Geschwister, auch ohne `z-index`. Der Schwund haette das kaschiert
 * und die Regel trotzdem gebrochen.
 */
.hub-karte > :not(.hub-zeichen--grund),
.hub-schritt > :not(.hub-zeichen--grund) {
    position: relative;
    z-index: 1;
}

/* --------------------------------------------------------- Bekenntnis */

/*
 * DER AUFMACHER VON "UEBER UNS".
 *
 * Ein Satz in Groesse statt ein Absatz in Fliesstext: Es ist die Antwort auf
 * die Frage, mit der jemand hierherkommt, und sie stand bisher als vierte Zeile
 * mitten in einer Aufzaehlung. Der Nachsatz darunter bleibt Fliesstext und
 * bleibt beim Zeilenmass - er wird gelesen, nicht ueberflogen.
 *
 * DAS MASS SASS AM TEXT UND NICHT AM KASTEN, und das sah nach einem Fehler aus.
 *
 * Der Kasten lief ueber die ganze schmale Schale (82rem), der Aufmachersatz
 * brach bei 46rem ab und der Nachsatz bei 68 Zeichen: ein Block von
 * dreizehnhundert Pixeln, in dem der Text nach der Haelfte aufhoerte und
 * rechts daneben Blech stand. Wer das sieht, sucht das fehlende Bild.
 *
 * Repariert wird es mit einer ZWEITEN SPALTE statt mit einem schmaleren
 * Kasten. Beides beendet das Abhacken, aber nur eines nutzt die Breite, die
 * dasteht: Der Kasten laeuft ueber die volle Schale und teilt sich ab 50rem in
 * zwei Spalten - links der Aufmachersatz, rechts der Nachsatz. Jede Spalte
 * misst rund 600 Pixel, und damit haelt der grosse Satz sein Mass und der
 * kleine seines. "max-width weg" waere der dritte Weg gewesen und der falsche:
 * Eine Fliesstextzeile ueber dreizehnhundert Pixel liest niemand
 * (CLAUDE.md, Abschnitt 7).
 *
 * DIE SCHWELLE IST DIESELBE WIE BEIM KARTENRASTER (50rem), und das ist der
 * eigentliche Gewinn: Beide brechen an derselben Stelle um, und die Kante des
 * Kastens liegt auf der Kante der Karten darunter. Ein schmalerer Kasten haette
 * mit keiner Linie der Seite eine gemeinsame gehabt.
 */
.hub-bekenntnis {
    display: grid;
    gap: var(--hub-gap-3) var(--hub-gap-4);
    align-items: start;
    margin-bottom: var(--hub-gap-5);
    padding: var(--hub-gap-4);
    border: var(--hub-border) solid var(--hub-kante);
    border-left: 6px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

@media (min-width: 50rem) {
    .hub-bekenntnis {
        grid-template-columns: 1fr 1fr;
    }

    /* Die Ueberschrift gehoert ueber beide Spalten, nicht in die erste. */
    .hub-bekenntnis > .hub-titel {
        grid-column: 1 / -1;
    }
}

.hub-bekenntnis__satz {
    margin: 0;
    font-size: clamp(1.25rem, 2.4vw, 1.7rem);
    line-height: 1.35;
}

.hub-bekenntnis__nach {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
}

/* ------------------------------------- Der Kopf der Vitrine (/spiele) */

/*
 * ZWEI KARTEN UEBEREINANDER SCHOBEN DIE KACHELN UNTER DEN FALZ.
 *
 * Auf `/spiele` standen das Bekenntnis (Ueberschrift, Lead, Nachsatz) und die
 * Einstiegskachel (Titel, Satz, zwei Knoepfe) als zwei volle Bloecke
 * untereinander. Beide sind richtig, beide gehoeren vor die Vitrine — und
 * zusammen fuellten sie den ersten Schirm so weit, dass von den acht Tischen,
 * wegen derer jemand hier ist, keiner mehr zu sehen war.
 *
 * Nebeneinander kostet dasselbe nur eine Zeile: links der Kopf, rechts die
 * Aktionskarte. Das Verhaeltnis ist rund 65 zu 35 — der Kopf traegt Saetze und
 * braucht Mass, die Karte traegt zwei Knoepfe und braucht nur Platz fuer sie.
 *
 * DIE SCHWELLE IST 62rem, DIESELBE WIE BEI `.hub-wissen` weiter unten auf
 * derselben Seite. Eine eigene Zahl waere eine zweite Kante im selben Blatt:
 * Kopf und Schlusstext braechen an verschiedenen Stellen um, und beim naechsten
 * Umbau wuesste niemand mehr, welche der beiden gemeint war.
 */
.hub-arenakopf {
    display: grid;
    gap: var(--hub-gap-4);
    align-items: start;
    margin-bottom: var(--hub-gap-5);
}

/*
 * DER AUSSENABSTAND GEHOERT DEM WRAPPER. Beide Sektionen bringen ihren eigenen
 * `margin-bottom` mit — und `/tisch` und `/spenden` brauchen ihn dort
 * weiterhin. Hier stuenden sonst zwei Abstaende zwischen Kopf und Regal, und in
 * der zweispaltigen Lage haenge er unter der hoeheren der beiden Karten.
 */
.hub-arenakopf > .hub-bekenntnis,
.hub-arenakopf > .hub-terminal {
    margin-bottom: 0;
}

@media (min-width: 62rem) {
    .hub-arenakopf {
        grid-template-columns: minmax(0, 65fr) minmax(0, 35fr);
    }

    /*
     * DAS BEKENNTNIS BLEIBT HIER EINSPALTIG. Es teilt sich ab 50rem selbst in
     * Satz und Nachsatz — richtig ueber die volle Schale, falsch in einer
     * Spalte von 65 Prozent: Der grosse Lead stuende dort in Spalten von rund
     * elf Zeichen.
     */
    .hub-arenakopf > .hub-bekenntnis {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Der Lead ist hier eine Unterzeile und kein Aufmacher mehr. */
    .hub-arenakopf .hub-bekenntnis__satz {
        font-size: clamp(1.1rem, 1.5vw, 1.35rem);
    }

    /*
     * Die Karte nimmt ihre Spalte ganz. `--hub-terminal-mass` ist das Mass
     * eines Codefeldes auf einer leeren Seite; in einer Spalte von 35 Prozent
     * stuende sie damit schmal und mittig in einer Luecke, die sie selbst
     * aufmacht.
     */
    .hub-arenakopf > .hub-terminal {
        width: 100%;
        margin-inline: 0;
    }
}

.hub-karte__fuss {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2);
    margin: var(--hub-gap-2) 0 0;
}

/* ---------------------------------------------------------- Klappen */

.hub-film,
.hub-recht {
    max-height: 88vh;
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-tinte);
    background: var(--hub-grund);
    color: var(--hub-tinte);
    overflow: auto;
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-schwebend);
}

/* Der Film will Breite, der Rechtstext will Mass. */
.hub-film {
    width: min(64rem, 94vw);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-schwebend);
}

/*
 * NEUNHUNDERT PIXEL, UND DER TEXT STEHT MITTIG DARIN.
 *
 * Die Klappe war so breit wie die Filmklappe (1024 px), der Text darin auf 68
 * Zeichen begrenzt und linksbuendig: Rechts blieb eine leere Spalte von rund
 * vierhundert Pixeln stehen, und jeder Absatz sah aus, als sei er abgeschnitten
 * worden. Ein Rechtstext ist kein Film - er bekommt eine Buchseite und keine
 * Leinwand.
 */
.hub-recht {
    width: min(56.25rem, 94vw);
    padding: var(--hub-gap-3) var(--hub-gap-4) var(--hub-gap-4);
}

.hub-film::backdrop,
.hub-recht::backdrop {
    /* Kein Weichzeichner. Eine Klappe deckt zu, sie verschmiert nicht. */
    background: rgba(0, 0, 0, 0.82);
}

.hub-film__zeile,
.hub-recht__zeile {
    display: flex;
    justify-content: flex-end;
    margin: 0 0 var(--hub-gap-2);
}

.hub-film__zu,
.hub-recht__zu {
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    padding: 0 var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-tinte);
    background: transparent;
    color: var(--hub-tinte);
    font: inherit;
    cursor: pointer;
}

.hub-film__titel {
    margin: 0 0 var(--hub-gap-2);
    font-size: 1rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

/*
 * DIE KLAPPE KENNT IHRE HOEHE, BEVOR SIE IHREN FILM KENNT.
 *
 * Sie trug ihre Quelle im Markup, und damit stand ihre Groesse fest, sobald
 * das Poster geladen war. Seit sie den Film des gedrueckten Knopfes zeigt,
 * steht beim Aufklappen ein Video ohne Quelle da — und ein solches misst nach
 * Spezifikation 300 x 150. Ohne diese Zeile springt die Klappe bei jedem
 * Oeffnen einmal auf.
 */
.hub-film__video {
    width: 100%;
    aspect-ratio: 16 / 9;
    background: var(--hub-kino);
}

.hub-recht__text {
    max-width: var(--hub-mass);
    margin: 0 auto;
}

/*
 * `--seite` ist die Volltextfassung unter /impressum und /datenschutz, also
 * dieselben Absaetze ohne Klappe. Sie brauchte hier einmal ein eigenes
 * `margin: 0 auto`; seit die Klappe ihren Text ohnehin mittig stellt, ist der
 * Unterschied der Aussenabstand nach oben und nichts weiter.
 */
.hub-recht__text--seite {
    padding-top: var(--hub-gap-4);
}

.hub-recht__text h2 {
    margin: 0 0 var(--hub-gap-2);
    font-size: 1.4rem;
}

.hub-recht__text h3 {
    margin: var(--hub-gap-3) 0 var(--hub-gap-1);
    font-size: 1rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-recht__stempel {
    margin: 0 0 var(--hub-gap-3);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
}

.hub-recht__hinweis {
    margin-top: var(--hub-gap-3);
    padding-top: var(--hub-gap-2);
    border-top: 1px solid var(--hub-kante);
    color: var(--hub-tinte-sekundaer);
    font-size: 0.9rem;
}

/* ----------------------------------------------------------- Fusszeile */

/* Auch sie steht in `shared/haus/haus.css` - siehe den Block "Kopf" oben. */

/* ------------------------------------------------------- Konzeptseite */

/*
 * VIER SCHRITTE ALS ECHTE ORDINALLISTE, und die Nummern kommen aus dem
 * Zaehler des Browsers statt aus getippten Ziffern: Wer einen Schritt
 * einschiebt, nummeriert sonst drei von Hand um - und vergisst einen.
 *
 * `list-style: none` allein nimmt manchen Schirmlesern die Ansage "Liste mit
 * vier Eintraegen". Die Nummer steht deshalb als eigener Zaehler im ::before
 * und nicht als Aufzaehlungszeichen.
 */
.hub-schritte {
    counter-reset: hub-schritt;
    display: grid;
    gap: var(--hub-gap-3);
    margin: 0 0 var(--hub-gap-4);
    padding: 0;
    list-style: none;
}

@media (min-width: 46rem) {
    .hub-schritte {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--hub-gap-4);
    }
}

/*
 * VIER SCHRITTE IN VIER SPALTEN, und erst ab 76rem.
 *
 * Sie standen zwei mal zwei, und das las sich wie zwei Paare statt wie eine
 * Kette: Schritt 3 begann wieder links, also sah er aus wie ein neuer Anfang.
 * Nebeneinander ist ein Ablauf ein Ablauf. Die Schwelle liegt hoch, weil vier
 * Karten mit je drei Zeilen Text darunter zu Spalten von zwoelf Zeichen werden.
 */
@media (min-width: 76rem) {
    .hub-schritte {
        grid-template-columns: repeat(4, 1fr);
    }
}

.hub-schritt {
    position: relative;
    counter-increment: hub-schritt;
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    overflow: hidden;
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

.hub-schritt__titel {
    margin: 0 0 var(--hub-gap-2);
    font-size: 1.15rem;
    line-height: 1.2;
}

.hub-schritt__titel::before {
    content: counter(hub-schritt) ' · ';
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-zahl);
}

.hub-schritt__satz {
    max-width: 100%;
    margin: 0;
}

/* ------------------------------------------------------------- Ruhe */

/*
 * WER WENIGER BEWEGUNG BESTELLT HAT, BEKOMMT KEINE.
 *
 * Das Standbild tritt an die Stelle der Schleife – das wirkt auch ohne
 * JavaScript. Das Skript im Fuss haelt das Video zusaetzlich an, denn ein
 * `display: none`-Video darf nach Spezifikation weiterlaufen und zoege dann
 * Bandbreite fuer ein Bild, das niemand sieht.
 */
/* ----------------------------------------------------- Der Drahtbericht */

/*
 * DIE DEPESCHE: eine Karteikarte aus dem Telegrafenamt.
 *
 * SIE IST DASSELBE MOEBEL WIE DIE RECHTSKLAPPE (`.hub-recht`) und kein
 * zweiter Klappenstil — dieselbe Kante, dieselbe Rundung, derselbe Rand,
 * dasselbe Backdrop. Was sie unterscheidet, ist die Breite: Ein Rechtstext
 * ist eine Seite, dies hier sind fuenf Zeilen und ein Feld.
 *
 * DER STREIFEN OBEN IST DER EINZIGE SCHMUCK, und er ist eine FLAECHE und kein
 * Verlauf: vier Pixel Signalfarbe, wie die Akzentlinie jeder Karte dieses
 * Hauses. Was eine Depesche ausmacht, macht die Schrift.
 */
.hub-drahtbericht {
    width: min(94vw, 30rem);
    padding: 0;
    border: var(--hub-border) solid var(--hub-kante-stark);
    border-top: 4px solid var(--hub-signal);
    background: var(--hub-grund-karte);
    color: var(--hub-tinte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-schwebend);
}

.hub-drahtbericht::backdrop {
    background: rgba(20, 20, 22, 0.55);
}

.hub-drahtbericht__blatt {
    display: grid;
    gap: var(--hub-gap-2);
    padding: var(--hub-gap-4);
}

/* Der Kopf einer Depesche: Amt und Stempel, in der Schrift der Akten. */
.hub-drahtbericht__marke {
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-drahtbericht__titel {
    margin: 0;
    font-size: 1.6rem;
    line-height: 1.15;
    letter-spacing: -0.02em;
}

.hub-drahtbericht__satz {
    margin: 0 0 var(--hub-gap-2);
    color: var(--hub-tinte-sekundaer);
    text-wrap: pretty;
}

/*
 * EIN HAKEN IST EINE ZEILE ZUM ANFASSEN, und sie misst 44 Pixel — auch die
 * einzeilige. Das `<label>` umschliesst das Kaestchen, der ganze Satz schaltet
 * also mit; wer auf einem Telefon ein Kaestchen von 13 Pixeln treffen muss,
 * trifft es nicht.
 *
 * `flex-shrink: 0` AM KAESTCHEN: `base.css` fuehrt in beiden Zimmern
 * `input { width: 100% }`, und dieselbe Regel hat den Meldebogen des Tresens
 * schon einmal mit einem Kaestchen von 377 Pixeln dastehen lassen. Das Foyer
 * traegt sie heute nicht — ein Rahmen, der sich darauf verlaesst, welche
 * Elementregeln das Haus unter ihm mitbringt, ist der naechste Bogen, den
 * niemand sucht.
 */
.hub-drahtbericht__haken {
    display: flex;
    align-items: center;
    gap: var(--hub-gap-2);
    min-height: var(--hub-griff);
    cursor: pointer;
}

.hub-drahtbericht__haken input {
    flex: 0 0 auto;
    width: 1.15rem;
    height: 1.15rem;
    margin: 0;
    accent-color: var(--hub-signal);
}

.hub-drahtbericht__feldkopf {
    margin-top: var(--hub-gap-2);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

/*
 * `16px` IST DIE UNTERGRENZE UND KEINE VORLIEBE: Darunter zoomt iOS beim
 * Antippen in das Feld hinein, und die halbe Klappe ist weg.
 */
.hub-drahtbericht__feld {
    width: 100%;
    min-height: var(--hub-griff);
    padding: var(--hub-gap-2);
    border: var(--hub-border) solid var(--hub-kante-griff);
    background: var(--hub-feld-grund);
    color: var(--hub-tinte);
    font-family: var(--hub-font-text);
    font-size: max(16px, 1rem);
    border-radius: var(--hub-radius-m);
}

.hub-drahtbericht__recht {
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-size: 0.85rem;
    text-wrap: pretty;
}

.hub-drahtbericht__knoepfe {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2);
    margin: var(--hub-gap-2) 0 0;
}

/*
 * DIE QUITTUNG NIMMT KEINEN PLATZ, SOLANGE SIE LEER IST — sonst steht unter
 * jedem Knopf eine Leerzeile, die aussieht, als fehle etwas. Sie ist eine
 * Live-Region: Ein Text, der sich in einem ausgeblendeten Element aendert,
 * wird von keinem Schirmleser angesagt.
 */
.hub-drahtbericht__quittung {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.85rem;
    text-wrap: pretty;
}

.hub-drahtbericht__quittung:empty {
    display: none;
}

/*
 * DER RUF AUF DER KACHEL: ein Satz und ein Knopf, abgesetzt vom Rest.
 *
 * Er steht UNTER der Knopfzeile und nicht darin: Was darueber steht, fuehrt an
 * einen Tisch; das hier fuehrt nirgendwohin, es notiert eine Adresse. Zwei
 * Sorten Handlung in einer Reihe waeren drei gleich aussehende Knoepfe mit
 * zwei verschiedenen Versprechen.
 */
.hub-kachel__draht {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-1) var(--hub-gap-2);
    margin: var(--hub-gap-2) 0 0;
    padding-top: var(--hub-gap-2);
    border-top: var(--hub-border) solid var(--hub-kante);
}

.hub-kachel__draht-satz {
    color: var(--hub-tinte-gedaempft);
    font-size: 0.85rem;
}

/*
 * ER SIEHT AUS WIE EIN LINK UND IST EIN KNOPF. Ein dritter Knopf in
 * Knopfform stuende gleichrangig neben „Tisch eroeffnen"; was hier passiert,
 * ist eine Notiz und kein Aufbruch.
 *
 * `z-index: 2` UND `position: relative`, weil das Overlay des Titellinks
 * (`.hub-kachel__link::after`) die ganze Kachel deckt. Ohne die beiden Zeilen
 * faengt der Titellink den Klick ab, und der Knopf tut nichts — dieselbe
 * Vorkehrung wie bei `.hub-kachel__tuer`.
 */
.hub-kachel__draht-knopf {
    position: relative;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    min-height: var(--hub-griff);
    padding: 0;
    border: 0;
    background: none;
    color: var(--hub-akzent-schrift);
    font: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.hub-kachel__draht-knopf:hover,
.hub-kachel__draht-knopf:focus-visible {
    color: var(--hub-tinte);
}

/* Derselbe Knopf in der Vertrauenszeile der Weiche — dort ohne Satz daneben,
   weil die Zeile darueber schon einer ist. */
.hub-vertrauen__draht {
    margin: var(--hub-gap-2) 0 0;
    text-align: center;
}

.hub-vertrauen__knopf {
    display: inline-flex;
    align-items: center;
    min-height: var(--hub-griff);
    padding: 0;
    border: 0;
    background: none;
    color: var(--hub-signal);
    font-family: var(--hub-font-doc);
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.hub-vertrauen__knopf:hover,
.hub-vertrauen__knopf:focus-visible {
    color: var(--hub-tinte);
}

@media (prefers-reduced-motion: reduce) {
    .hub-aufmacher__video {
        display: none;
    }

    .hub-aufmacher__standbild {
        display: block;
    }

    /*
     * UND DIE KNOEPFE DAZU GEHEN MIT. Wer weniger Bewegung bestellt hat,
     * bekommt statt der Schleife ein Standbild — und daneben standen bis
     * hierher drei Knoepfe, die einen Film bedienen, den es auf diesem Schirm
     * nicht gibt: Ton an, anhalten, gross ansehen. Der erste tat nichts, der
     * zweite hielt etwas an, das stillstand, der dritte machte eine Klappe mit
     * genau der Bewegung auf, die abbestellt war.
     *
     * Es steht im Stilblatt und nicht im Skript, weil es auch ohne JavaScript
     * gelten muss — dieselbe Begruendung wie beim Standbild darueber.
     *
     * UND ZWAR AUF DIESEM BLATT, NICHT IM GANZEN HAUS. Die drei Selektoren
     * standen ungebunden da und trafen damit jedes `data-film` der Seite — auch
     * den Knopf auf Blatt 1, der gar keine Schleife bedient, sondern eine Klappe
     * mit `controls` aufzieht, die niemand von selbst startet. Wer weniger
     * Bewegung bestellt hat, kam damit ueberhaupt nicht mehr an den Film. Die
     * Begruendung oben gilt woertlich fuer das Filmblatt und nur dort: Dort
     * steht das Standbild, und dort waeren die drei Knoepfe ohne Gegenstand.
     */
    .hub-aufmacher__blatt--film .hub-aufmacher__spielen,
    .hub-aufmacher__blatt--film [data-film],
    .hub-aufmacher__blatt--film [data-film-ton],
    /* Und derselbe Knopf im Titelbild: Er bedient eine Schleife, die auf
       diesem Schirm durch ihr Standbild ersetzt ist. Der Weg in die Klappe
       bleibt daneben stehen — sie hat eine Bedienleiste und faengt nicht von
       selbst an. */
    .hub-monolith [data-held-lauf],
    /* Und die Vorschau im Aushang einer Kachel: Sie ist eine stumme Schleife
       und sonst nichts — ohne sie steht dort derselbe Aushang, den sie als
       Standbild traegt. Es geht also nichts verloren ausser der Bewegung. */
    .hub-kachel__fenster [data-kachel-lauf] {
        display: none;
    }

    /*
     * UND DIE BANDEROLE STEHT STILL. Die Zeile darunter setzt nur die
     * UEBERGAENGE auf null; eine Animation mit `infinite` liefe davon
     * unbeeindruckt weiter — und sie ist die einzige Bewegung dieses Hauses,
     * die von selbst anfaengt. Das Band bleibt dabei erreichbar: Sein Fenster
     * scrollt waagerecht, genau wie auf einem Telefon.
     */
    .hub-banderole__band {
        animation: none !important;
    }

    /* Und ohne Lauf braucht es die zweite Haelfte nicht — sie waere hier
       dasselbe wie auf dem Telefon: zehn sichtbare Dubletten. */
    .hub-banderole__band--kopie {
        display: none;
    }

    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
    }
}

/*
 * DIE MARKE DES DIRECTOR'S CUT — sie stand hier als SPERRBANNER, mit demselben
 * Kasten und demselben Zinnober, und sagte, ab wann es weitergeht.
 *
 * Jetzt sagt sie, dass es weitergeht. Der Kasten bleibt, wo er war: IN der Kachel
 * und über dem Knopf, nicht als Overlay über dem Aushang — das Bild ist der Grund,
 * warum jemand stehen bleibt. Kein Verlauf, keine Rundung, kein Schatten; die
 * Zinnoberkante macht aus der Zeile ein Schild.
 *
 * ZWEI ZEILEN UND ZWEI GRÖSSEN: oben die Marke in Versalien, darunter der Satz in
 * normaler Schreibweise. Eine Marke allein sagt nur, dass etwas anders ist; der
 * Satz sagt, was — und er ist der Grund, sich den Abend noch einmal anzusehen.
 *
 * Wer sie abräumt, löscht diesen Block, BM_SCHNITT_* in shared/regal.php und den
 * Zweig in hub/seiten/katalog.php.
 */
/*
 * DER TRANSPARENZHINWEIS AUF ENGLISCH: „Game interface & audio currently in
 * German". Er ist eine Auskunft und kein Alarm — deshalb keine Akzentkante
 * wie beim Schnitt darüber, nur gedämpfte Schrift in derselben Größe wie ein
 * Datum. Er steht ausschließlich hinter tr_sprache_aktuell() === 'en': auf
 * /en/escapes und /en/spiele (katalog.php, spiele.php) und auf den beiden
 * Weichen-Karten Archiv/Arena von /en/ (portal.php).
 */
.hub-kachel__sprachhinweis {
  margin: 0 0 var(--hub-luft-klein, 0.75rem);
  color: var(--hub-tinte-gedaempft);
  font-size: 0.78rem;
  font-style: italic;
  line-height: 1.4;
}

/* ------------------------------------------ Die Bande zum Brettspiel */

/*
 * DER QUERVERWEIS AUF „ALARM IM ARCHIV" — auf dem Regal der Fälle und auf der
 * Vitrine der Arena.
 *
 * Er ist eine BANDE und keine Kachel: quer statt hochkant, ein Bild links, der
 * Text rechts, ein Knopf. Als Kachel stünde er in einer Reihe mit Dingen, die
 * er nicht ist — das Brettspiel steht weder in der Kartei der Fälle noch im
 * Pool der Arena. Als Bande liegt er zwischen den beiden Regalen und gehört
 * sichtbar zu keinem.
 *
 * SEIN AKZENT IST DAS MESSING SEINES EIGENEN BRETTS, genau wie auf der Weiche:
 * Wer ihn dort schon gesehen hat, erkennt ihn hier wieder.
 */
.hub-archiv {
    --hub-akzent: var(--hub-messing);
    display: grid;
    gap: 0;
    margin-bottom: var(--hub-gap-5);
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    border-radius: var(--hub-radius-l);
    background: var(--hub-grund-karte);
    box-shadow: var(--hub-schatten-karte);
    overflow: hidden;
}

/*
 * QUER ERST AB DEM SCHREIBTISCH. Auf dem Telefon liegt das Bild oben und der
 * Text darunter — ein Bild von zwei Fünfteln der Breite wäre dort ein
 * Briefmarkenfeld neben drei Zeilen Blocksatz.
 */
@media (min-width: 62rem) {
    .hub-archiv {
        grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
        align-items: stretch;
    }
}

.hub-archiv__fenster {
    position: relative;
    overflow: hidden;
    aspect-ratio: 16 / 9;
    background: var(--hub-kino);
}

/* Dieselbe Textur wie in jedem Fenster des Hauses: Vignette und Halbtonraster. */
.hub-archiv__fenster::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(circle at 50% 45%, transparent 45%, var(--hub-vignette) 100%),
        radial-gradient(var(--hub-halbton) 1px, transparent 1px);
    background-size: auto, var(--hub-halbton-size) var(--hub-halbton-size);
}

.hub-archiv__bild {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

@media (min-width: 62rem) {
    .hub-archiv__fenster {
        height: 100%;
        aspect-ratio: auto;
    }
}

.hub-archiv__text {
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-2);
    padding: var(--hub-gap-4);
}

.hub-archiv__marke {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    overflow-wrap: anywhere;
}

.hub-archiv__titel {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--hub-gap-2);
    margin: 0;
    font-size: clamp(1.5rem, 2.4vw, 2rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
}

.hub-archiv__gattung {
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    font-weight: 400;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-archiv__satz {
    max-width: 100%;
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    text-wrap: pretty;
}

.hub-archiv__knopf {
    margin: var(--hub-gap-2) 0 0;
}

/* ============================================================ Die Zusagen ===
 *
 * VIER HAEKCHEN DIREKT UNTER DER SCHLAGZEILE.
 *
 * SIE SIND NICHT DIE VERTRAUENSZEILE EIN ZWEITES MAL, und der Unterschied ist
 * die Stelle. Jene steht ganz unten (`.hub-vertrauen`) und ist die
 * Versicherung fuer den, der schon gelesen hat; diese hier steht ueber der
 * Entscheidung und beantwortet die Frage VOR der Frage dieser Seite: Wartet
 * hier eine Anmeldemaske? Dafuer hat sie anderthalb Sekunden.
 *
 * SIE STEHEN IN DER SCHRIFT DER AKTEN, weil sie Eckdaten sind und kein
 * Fliesstext — dieselbe Schrift wie die Plaketten auf den drei Wegen darunter.
 *
 * `flex-wrap` IST DIE GANZE MOBILREGEL. Auf 375 px stehen sie zweizeilig, auf
 * dem Schreibtisch einzeilig; eine Medienregel dafuer waere eine Schwelle, die
 * niemand nachmisst. `dev/dev.ps1 hub` haelt jede Seite auf 375 px gegen
 * seitliches Scrollen.
 *
 * KONTRAST: `--hub-tinte-sekundaer` haelt 8,81:1 auf Naturpapier; der Haken
 * traegt `--hub-akzent-schrift` (das gedunkelte Zinnober), und der ist als
 * NICHTTEXT gegen den Grund zu messen — WCAG 1.4.11 verlangt dort 3,0, und
 * neben ihm steht das Wort, das er meint. Farbe ist hier nirgends der einzige
 * Informationstraeger.
 */
.hub-zusagen {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2) var(--hub-gap-3);
    max-width: min(100%, 105ch);
    margin: var(--hub-gap-3) 0 0;
    padding: 0;
    list-style: none;
}

.hub-zusage {
    display: inline-flex;
    align-items: center;
    gap: var(--hub-gap-1);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.82rem;
    letter-spacing: 0.02em;
}

/*
 * JEDE ZUSAGE TRAEGT IHR EIGENES ZEICHEN: ein Siegel fuer „kostenlos", ein offenes Schloss fuer „ohne Konto", ein
 * Roehrenfernseher fuer „im Browser", zwei Koepfe fuer „Koop & Solo". Es standen einmal vier gleiche Haken da, und
 * vier gleiche Haken sind eine Liste, die nichts unterscheidet. Die Zeichen sind SVG-Pfade in der Schrift des Hauses
 * (Kante, keine Flaeche, `square` wie alle Zeichen dieses Hauses) und tragen keine Auskunft: Das Wort daneben ist die
 * Zusage, das Zeichen ist der Griff, an dem man sie wiederfindet.
 *
 * 1,35rem statt 1rem: Ein Haken ist ein Strich, ein Siegel hat einen Rand, ein Ring und ein Band — darunter fliesst
 * es zu einem Klecks.
 */
.hub-zusage__zeichen {
    flex: 0 0 auto;
    width: 1.35rem;
    height: 1.35rem;
    fill: none;
    stroke: var(--hub-akzent-schrift);
    stroke-width: 1.7;
    stroke-linecap: square;
    stroke-linejoin: miter;
}

/* ====================================== Die Eckdaten eines Weges als Feld ===
 *
 * SIE STANDEN ALS EIN SATZ IN SCHREIBMASCHINE: „KOOPERATIV · 45–60 MIN · 2–4
 * PERSONEN". Das ist drei Auskuenfte lang und liest sich als eine; wer die
 * drei Wege vergleichen will — und genau dafuer steht er auf dieser Seite —,
 * muss dreimal eine Zeile lesen statt neunmal ein Feld zu sehen.
 *
 * DIE QUELLE BLEIBT EINE ZEICHENKETTE in `TR_WORTE`; `portal.php` zerlegt den
 * Mittelpunkt, der ohnehin schon darin stand. `hub/daten/archiv.php` setzt
 * dieselbe Zeile weiterhin als Fliesstext in die Querverweis-Bande.
 *
 * SIE SIND KEINE GRIFFE. Kein Link, kein Knopf, kein Tabstopp — die
 * Mindestflaeche von 44 Pixeln gilt ihnen deshalb nicht, und ein Feld von 44
 * Pixeln Hoehe waere hier ein Kasten statt einer Plakette.
 */
.hub-weg__eckdaten {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.hub-weg__eck {
    padding: 2px var(--hub-gap-2);
    border: var(--hub-border) solid var(--hub-kante-stark);
    background: var(--hub-grund-subtil);
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-doc);
    font-size: 0.7rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    border-radius: var(--hub-radius-m);
}

/* ======================================================== Die vier Fragen ===
 *
 * KURZ GEFRAGT: das Akkordeon am Fuss der Weiche.
 *
 * ES IST EIN `<details>` UND KEIN SKRIPT. Die Antwort steht im Markup, ein
 * Crawler liest sie, ohne etwas aufzumachen, und ohne JavaScript klappt sie
 * trotzdem auf — dieselbe Bauform wie das Dossier auf jeder Kachel der
 * Vitrine.
 *
 * DER GRIFF MISST 44 PIXEL. `dev/dev.ps1 hub` macht jedes `<details>` auf,
 * bevor es misst, und nimmt `summary` ausdruecklich in die Liste der Griffe:
 * Ein zugeklappter Aufklapper misst null mal null und wuerde uebersprungen.
 *
 * DAS ZEICHEN IST EIN PSEUDOELEMENT UND KEINE SCHRIFT. `list-style: none` am
 * `summary` nimmt das Dreieck des Browsers weg (samt Webkit-Marker fuer
 * aelteres Safari); was dasteht, ist ein Plus, das beim Aufklappen zum Minus
 * wird — kein Emoji, kein Icon-Font.
 */
/*
 * SIE STAND AUF DEM ZEILENMASS UND KLEBTE LINKS.
 *
 * `--hub-mass` (68ch, rund 590 Pixel) ist das Mass fuer einen ABSATZ, und der
 * Block hatte dazu keine seitlichen Aussenabstaende: Auf einem Schirm von 1440
 * oder 2560 Pixeln stand das Akkordeon damit als schmale Saeule am linken Rand
 * einer Buehne von 1800 — darueber drei gleich breite Wege, darunter der Fuss
 * ueber die ganze Seite, und dazwischen neunhundert Pixel Leere.
 *
 * EINE KARTE IST KEIN ABSATZ, und genau das ist der Unterschied: Was hier
 * nebeneinander steht, ist ein Griff mit einem Pluszeichen und einer Frage,
 * keine Zeile, die man entlangliest — dasselbe Argument wie bei
 * `.hub-regal__satz` eine Stufe weiter oben, nur andersherum. Die Karten
 * nehmen deshalb 920 Pixel und stehen mittig unter der Weiche.
 *
 * DIE ANTWORT NIMMT DIE GANZE KARTE. Hier stand, sie behalte ihr Zeilenmass,
 * und das hiess: rund 640 Pixel Text in einer Karte von 920, und rechts davon
 * vierzig Prozent leeres Papier bei jeder offenen Frage. Die Karte IST schon
 * das Mass — ein zweiter Deckel darin bricht Zeilen, wo noch Platz ist
 * (CLAUDE.md, Abschnitt 7). Die Ueberschrift braucht keine eigene Regel — sie
 * ist ein Kind dieses Kastens und schliesst mitsamt ihrer Unterkante bündig
 * mit der Kartenkante ab.
 */
.hub-fragen {
    display: grid;
    gap: var(--hub-gap-2);
    width: 100%;
    max-width: 920px;
    margin-top: var(--hub-gap-5);
    margin-inline: auto;
}

.hub-fragen > .hub-titel {
    margin-bottom: var(--hub-gap-1);
}

.hub-frage {
    border: var(--hub-border) solid var(--hub-kante-stark);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-m);
}

.hub-frage__griff {
    display: flex;
    align-items: center;
    gap: var(--hub-gap-2);
    min-height: var(--hub-griff);
    padding: var(--hub-gap-1) var(--hub-gap-3);
    color: var(--hub-tinte);
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}

.hub-frage__griff::-webkit-details-marker {
    display: none;
}

/*
 * DAS ZEICHEN STEHT AM RECHTEN RAND DER KARTE, UND DORT IMMER AN DERSELBEN STELLE.
 *
 * Hier stand es vorn, mit der Begruendung, am Ende einer Frage stuende es bei jeder Zeile woanders. Das gilt fuer ein
 * Zeichen, das der Frage FOLGT; dieses haengt an der Kante der Karte (`margin-left: auto`) und bildet eine Spalte, die
 * sich haelt, egal wie lang die Frage ist. Die Frage beginnt dafuer buendig an der Kante, wie jede Zeile darueber.
 *
 * EIN KASTEN UND KEIN KREIS: Das Foyer rundet mit `--hub-radius-m` und nicht rund. Offen kehrt er sich um — Papier auf
 * Tinte —, und die Karte bekommt die Griffkante: Wo man gerade liest, sagt nicht die Farbe allein.
 */
.hub-frage__griff::after {
    content: '+';
    display: grid;
    flex: none;
    place-items: center;
    width: 1.9rem;
    height: 1.9rem;
    margin-left: auto;
    border: var(--hub-border) solid var(--hub-kante-griff);
    border-radius: var(--hub-radius-m);
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-weight: 700;
    line-height: 1;
    transition: background var(--hub-schnell), color var(--hub-schnell);
}

.hub-frage[open] > .hub-frage__griff::after {
    content: '\2212';
    border-color: var(--hub-tinte);
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

.hub-frage[open] {
    border-color: var(--hub-kante-griff);
}

.hub-frage__antwort {
    margin: 0;
    padding: 0 var(--hub-gap-3) var(--hub-gap-3);
    max-width: 100%;
    color: var(--hub-tinte-sekundaer);
    line-height: 1.6;
    text-wrap: pretty;
}

/*
 * AUF DER STARTSEITE STEHT DAS FAQ IN ZWEI SPALTEN: links ein Drittel mit Dach, Titel, einem Satz und dem Weg zur
 * eigenen Frage, rechts zwei Drittel Karten. Dieselbe Bauform wie der Kasten des Turniers (Dach, Titel, Satz, Knopf),
 * nur ohne Kasten darum — die Karten sind die Flaeche. Die Vitrine und die Seite eines Tisches behalten ihre Saeule von
 * 920 Pixeln: Dort stehen drei Fragen zu einem Ding und keine Einladung, eine eigene zu stellen.
 *
 * DIE KARTEN SIND DAS MASS, AUCH HIER: Die Antwort nimmt die ganze Karte (Abschnitt 7, „Text in einer bereits
 * begrenzten Komponente"), und die Spalte ist die Grenze der Karte.
 */
.hub-fragen--start {
    max-width: none;
    gap: var(--hub-gap-4);
}

@media (min-width: 64rem) {
    .hub-fragen--start {
        grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
        column-gap: var(--hub-gap-5);
        align-items: start;
    }
}

.hub-fragen__kopf {
    display: grid;
    align-content: start;
    gap: var(--hub-gap-2);
}

.hub-fragen__dach {
    margin: 0;
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.78rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-fragen__titel {
    margin: 0;
    font-size: clamp(1.6rem, 2.6vw, 2.2rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
}

.hub-fragen__satz {
    max-width: 100%;
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 1.02rem;
    line-height: 1.55;
}

.hub-fragen__knopf {
    margin: var(--hub-gap-2) 0 0;
}

.hub-fragen__liste {
    display: grid;
    gap: var(--hub-gap-2);
}

.hub-fragen--start .hub-frage__griff {
    padding: var(--hub-gap-2) var(--hub-gap-3);
    font-size: 1.05rem;
}

/* ============================================== Der Spielefinder der Arena ===
 *
 * EINUNDZWANZIG KACHELN SIND EIN REGAL, IN DEM MAN SUCHT STATT FINDET.
 *
 * Er blendet aus, er laedt nicht nach: Jede Kachel bleibt im Markup, und ein
 * Crawler liest alle. Gefiltert wird mit `hidden` am Fach — das ist das Kind
 * des Rasters, und nur so wird die Reihe kuerzer statt loechrig.
 *
 * EINE ZEILE, DIE MAN WISCHT, UND KEIN BLOCK, DEN MAN UEBERSCROLLT. Die Pillen
 * brachen um; auf 390 Pixeln waren es fuenf Zeilen in zwei Gruppen, 250 Pixel
 * vor der ersten Kachel. Jetzt stehen sie nebeneinander und laufen seitwaerts
 * aus dem Bild — die angeschnittene Pille am Rand sagt, dass es weitergeht.
 * Einen Rollbalken gibt es nicht (`scrollbar-width`, `::-webkit-scrollbar`),
 * und die Reihe reicht auf dem Telefon von Kante zu Kante: Sie traegt die
 * Seitenluft als Innenabstand, nicht als Rand.
 *
 * SIE KLEBT, UND SIE IST DECKEND. Wer weit unten in den Kacheln steht, hat die
 * Pillen unter dem Daumen, statt zurueckzuscrollen. Unter ihr bewegt sich
 * Inhalt hindurch wie unter dem Kopf des Hauses — aber sie ist kein zweites
 * Glas: kein Weichzeichner, keine Durchsicht, ein voller Papierton und eine
 * Kante. Wie weit oben sie klebt, misst das Skript an der Kopfleiste
 * (`top`): Die steht je nach Breite auf 56, 73 oder 106 Pixeln, und eine
 * getippte Zahl stuende an zwei von drei Breiten falsch.
 *
 * DIE PILLEN MESSEN 44 PIXEL IN BEIDE RICHTUNGEN, wie jeder Griff dieses
 * Hauses (`--hub-griff`): Der Daumen ist rund. `touch-action: manipulation`
 * nimmt dem Doppeltipp das Zoomen, und der Druck zeichnet sofort, ohne
 * Uebergang — wer an der Haltestelle tippt, soll nicht auf 90 ms warten.
 *
 * DIE GEWAEHLTE PILLE IST NICHT NUR ANDERS GEFAERBT. `aria-pressed` sagt es
 * einem Schirmleser, und die Flaeche kehrt um — Farbe ist nirgends in diesem
 * Haus der einzige Informationstraeger.
 *
 * KONTRAST: Ruhe steht auf `--hub-tinte-sekundaer` auf `--hub-grund-karte`
 * (9,23:1), die Kante auf `--hub-kante-griff` (3,34:1 gegen den Grund, die
 * 3,0 aus WCAG 1.4.11 fuer ein Bedienelement). Gedrueckt ist es Papier auf
 * Tinte (17,50:1).
 */
.hub-filter {
    position: sticky;
    top: 0;
    z-index: 5;
    margin: var(--hub-gap-3) calc(-1 * var(--hub-luft));
    border-bottom: var(--hub-border) solid var(--hub-kante);
    background: var(--hub-grund);
}

/*
 * DER FOKUSRING BRAUCHT PLATZ INNERHALB DER ZEILE. Eine Zeile, die seitwaerts
 * rollt, schneidet auch oben und unten ab; ohne die paar Pixel Innenabstand
 * stuende vom Ring der gewaehlten Pille nur die Haelfte da.
 */
.hub-filter__gruppe {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--hub-gap-2);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding: var(--hub-gap-2) var(--hub-luft);
    scroll-padding-inline: var(--hub-luft);
    scrollbar-width: none;
}

.hub-filter__gruppe::-webkit-scrollbar {
    display: none;
}

/*
 * `[hidden]` BRAUCHT HIER EINE EIGENE ZEILE, UND DAS IST DIE TEUERSTE FALLE
 * DIESER LEISTE.
 *
 * Das Attribut versteckt ueber eine Regel im Stilblatt des BROWSERS, und die
 * verliert gegen jede Regel eines Autors — auch gegen die Zeilen darueber.
 * Ohne diese hier stuende die Leiste trotz `hidden` im Markup da (also auch
 * ohne JavaScript, als tote Knopfreihe), und jedes ausgeblendete Fach stuende
 * weiter im Raster. Gemessen haette das kein Lauf: Beide sehen korrekt aus,
 * solange man nicht filtert.
 *
 * Dieselbe Zeile steht am Fach des Regals, aus demselben Grund
 * (`.hub-regal__fach` ist `display: flex`).
 */
.hub-filter[hidden],
.hub-regal__fach[hidden] {
    display: none;
}

.hub-filter__pille {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: var(--hub-gap-1);
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    padding: 0 var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante-griff);
    background: var(--hub-grund-karte);
    color: var(--hub-tinte-sekundaer);
    font: inherit;
    font-size: 0.88rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--hub-schnell), color var(--hub-schnell);
    border-radius: var(--hub-radius-m);
}

/* Nur wo es einen Zeiger gibt: Auf dem Telefon bliebe ein Hover nach dem Tipp an der Pille haengen. */
@media (hover: hover) {
    .hub-filter__pille:hover {
        border-color: var(--hub-tinte);
        color: var(--hub-tinte);
    }
}

.hub-filter__pille:focus-visible {
    outline: var(--hub-ring) solid var(--hub-signal);
    outline-offset: 2px;
}

.hub-filter__pille[aria-pressed='true'],
.hub-filter__pille:active {
    border-color: var(--hub-tinte);
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

.hub-filter__pille:active {
    transition: none;
}

/*
 * DIE ZAHL IST LEISER ALS DAS WORT UND TROTZDEM LESBAR.
 *
 * `--hub-tinte-gedaempft` haelt 5,05:1 auf Naturpapier und 4,63:1 auf der
 * gedaempften Flaeche — beides ueber den 4,5, die WCAG fuer Fliesstext
 * verlangt. Auf der GEDRUECKTEN Pille waere sie ein Befund: Dort liegt Papier
 * auf Tinte, und eine gedaempfte Tinte darauf haette 3,4:1. Sie erbt deshalb
 * dort die Farbe ihrer Pille und wird nur durch ihre Deckung leiser.
 */
.hub-filter__zahl {
    color: var(--hub-tinte-gedaempft);
    font-family: var(--hub-font-zahl);
    font-size: 0.82rem;
    font-weight: 400;
}

.hub-filter__pille[aria-pressed='true'] .hub-filter__zahl,
.hub-filter__pille:active .hub-filter__zahl {
    color: inherit;
    opacity: 0.8;
}

/*
 * DIE SOLO-PLAKETTE LIEGT RECHTS OBEN, GEGENUEBER DER SPIELERZAHL.
 *
 * `.hub-kachel__fenster > .hub-spieler` setzt beide absolut an dieselbe Ecke —
 * zwei Plaketten uebereinander waeren eine unlesbare. Diese hier wandert an
 * die andere Seite, und damit stehen die beiden Auskuenfte nebeneinander und
 * nicht ineinander: links, fuer wie viele der Tisch ist, rechts, dass es auch
 * allein geht.
 *
 * KONTRAST: Papier auf `--hub-signal` haelt 5,23:1 — ueber den 4,5 fuer eine
 * Schrift von elf Pixeln. Die Plakette daneben bleibt Kinoschwarz; zwei
 * gleiche Plaketten nebeneinander waeren eine Angabe in zwei Teilen.
 */
.hub-kachel__fenster > .hub-spieler--solo {
    right: var(--hub-gap-2);
    left: auto;
    border-color: var(--hub-signal);
    background: var(--hub-signal);
    color: var(--hub-knopf-schrift);
}

/*
 * DER SALON ÜBER DEN KACHELN: eine Überschrift und ein Raster, dessen erste Karte immer die eigene ist.
 *
 * ER WAR EINE WEISSE KARTE MIT EINER ZEILE, DIE SICH AUFKLAPPTE, und genau das liess ihn leer aussehen: Ohne offenen
 * Tisch stand dort ein Satz, der erklaerte, wie einer hierherkommt; mit einem stand eine einzelne Karte in einem
 * Kasten ueber die ganze Buehne — eine Baustelle in einer weissen Flaeche. Jetzt steht er wie jeder andere Abschnitt
 * der Seite auf dem Papier, ohne eigenen Kasten, und die erste Karte ist „Eigenen Tisch eröffnen“. Leer ist er nie.
 *
 * DAS RASTER DARF HIER RATEN (`auto-fill`), anders als das Regal darunter: Die Zahl der offenen Tische kennt niemand
 * vorher. Eine Zeile traegt die Hoehe ihrer hoechsten Karte (`grid-auto-rows: 1fr`), und die Wege sitzen am Fuss
 * (`margin-top: auto`) — zwei Karten nebeneinander mit Knoepfen auf verschiedenen Hoehen saehen aus wie zwei Rangstufen.
 */
.hub-salon {
    margin: 0 0 var(--hub-gap-4);
}

.hub-salon__kopf {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--hub-gap-1) var(--hub-gap-2);
}

.hub-salon__zahl {
    color: var(--hub-tinte-sekundaer);
    font-family: var(--hub-font-zahl);
    font-size: 0.88rem;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
}

.hub-salon__tische {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
    gap: var(--hub-gap-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

/*
 * DIE KARTE EINES OFFENEN TISCHES: der Name fuehrt, darunter als feine Notiz, was und wie lange gespielt wird, dann
 * Host und Plaetze, und am Fuss die beiden Wege. Sie liegt als weisse Karte auf dem Papier, mit der Kante und dem
 * Schatten des Rahmens — auf Naturpapier ist eine weisse Flaeche ohne sie vom Grund nicht zu unterscheiden.
 */
.hub-salon__tisch {
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-1);
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante-stark);
    background: var(--hub-grund-karte);
    color: var(--hub-tinte);
    border-radius: var(--hub-radius-m);
    box-shadow: var(--hub-schatten-karte);
}

/*
 * GLEICHE HOEHEN ERST AB ZWEI SPALTEN. Nebeneinander traegt jede Zeile die Hoehe ihrer hoechsten Karte und jede Karte
 * eine Mindesthoehe, damit eine Zeile mit einem einzigen Tisch nicht halb so hoch steht wie die darueber. Untereinander
 * waere dieselbe Regel nur Leere: Auf dem Telefon stand die erste Karte mit einer Handbreit Luft zwischen Satz und Knopf.
 */
@media (min-width: 40rem) {
    .hub-salon__tische {
        grid-auto-rows: 1fr;
    }

    .hub-salon__tisch {
        min-height: 11.5rem;
    }
}

.hub-salon__spiel {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1.3;
}

/* Was gespielt wird und wie lange: die feine Notiz unter dem Namen. */
.hub-salon__modus {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 0.85rem;
}

.hub-salon__dauer {
    white-space: nowrap;
}

/*
 * DAS SCHLOSS STEHT NEBEN DEM MODUS und traegt ein kurzes Wort daneben: „PIN“. Ein Zeichen allein saehe jeder anders;
 * die ganze Fassung („PIN erforderlich“) steht im Namen der beiden Wege, fuer den Schirmleser.
 */
.hub-salon__pin {
    display: inline-flex;
    align-items: center;
    gap: 0.2em;
    color: var(--hub-tinte);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    white-space: nowrap;
}

.hub-salon__zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-1) var(--hub-gap-2);
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 0.85rem;
}

.hub-salon__host {
    margin-top: var(--hub-gap-1);
    color: var(--hub-tinte);
}

.hub-salon__stand {
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-salon__augen {
    display: inline-flex;
    align-items: center;
    gap: 0.25em;
}

/*
 * Auge und Schloss sind SVG-Pfade in der Schriftfarbe und keine Zeichen im Text: Ein Emoji saehe auf jedem System anders
 * aus. Das Wort daneben ist die Auskunft.
 */
.hub-salon__auge,
.hub-salon__schloss {
    flex: none;
    width: 1.1em;
    height: 1.1em;
    fill: currentColor;
}

/*
 * DIE WEGE NEBENEINANDER AM FUSS. Eine Stufe kleiner als der Knopf des Hauses: Auf 375 Pixeln bleiben einer Karte rund
 * 260 Pixel, und „Platz nehmen“ und „Zuschauen“ in voller Groesse braeuchten 275. Nebeneinander heisst hier gleichrangig
 * nebeneinander, und das geht nur, solange beide passen.
 */
.hub-salon__wege {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2);
    margin-top: auto;
    padding-top: var(--hub-gap-2);
}

.hub-salon__wege .hub-btn {
    flex: 1 1 auto;
    padding-inline: var(--hub-gap-2);
    font-size: 0.9rem;
    letter-spacing: 0.02em;
}

/*
 * DIE ERSTE KARTE IST DIE EIGENE, UND SIE IST DUNKEL. Kinoschwarz wie der Sockel des Hauses, Messing fuer Zeichen und
 * Knopf — die Farbe, die im Foyer zum Spielen einlaedt (`.hub-btn--solo`). So steht sie unter den weissen Karten der
 * fremden Tische als etwas anderes da: nicht ein Tisch, sondern der Stuhl, an dem man selbst einen aufmacht.
 *
 * KONTRAST: Kinotext auf Kinoschwarz 17,00:1, die Notiz (`--hub-kino-still`) 6,49:1, das Messing des Zeichens 8,97:1;
 * die Kante des Knopfes (`--hub-messing`) haelt gegen die Karte 3,46:1 — ueber den 3,0 fuer ein Bedienelement.
 */
.hub-salon__tisch--eroeffnen {
    border-color: var(--hub-kino);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
}

.hub-salon__tisch--eroeffnen .hub-salon__modus {
    color: var(--hub-kino-still);
}

.hub-salon__plus {
    flex: none;
    width: 2rem;
    height: 2rem;
    margin-bottom: var(--hub-gap-1);
    fill: none;
    stroke: var(--hub-messing-hell);
    stroke-width: 1.6;
    stroke-linecap: square;
}

/*
 * AUF DEM DUNKLEN GRUND KEHRT SICH DER HOVER DES MESSINGKNOPFES UM. Er wird im Haus tintenschwarz, und das waere auf
 * Kinoschwarz ein Knopf, der beim Darueberfahren verschwindet. Hier bleibt die Kante und wird die Schrift Messing.
 */
.hub-salon__tisch--eroeffnen .hub-btn--solo:hover,
.hub-salonruf .hub-btn--solo:hover {
    border-color: var(--hub-messing-hell);
    background: var(--hub-kino);
    color: var(--hub-messing-hell);
}

/*
 * DER SALON AUF DER STARTSEITE, unter dem Schaufenster: ein Band aus Kinoschwarz, das immer dasteht.
 *
 * Ruhig ist es eine Zeile mit einem Knopf — „Keine Verabredung heute?“ —, lebhaft zwei Spalten: links die Zahl und der
 * Weg in die Vitrine, rechts die Karte des lebhaftesten Tisches, eine weisse Karte auf dem dunklen Band. Es liegt auf
 * demselben Sockel wie Fuss und Filmbild und hebt sich damit vom Papier ab, ohne eine Farbe dafuer zu brauchen.
 *
 * DIE KANTE OBEN IST MESSING UND NICHT ZINNOBER. Zinnober ist das Signal dieses Hauses (Absagen, Solo-Plakette, der
 * Fokusring); ein Salon ist keine Warnung, sondern eine Einladung.
 */
.hub-salonruf {
    display: grid;
    align-items: center;
    gap: var(--hub-gap-3) var(--hub-gap-4);
    margin-top: var(--hub-gap-4);
    padding: var(--hub-gap-3) clamp(var(--hub-gap-3), 3vw, var(--hub-gap-4));
    border-top: 3px solid var(--hub-messing-hell);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    border-radius: var(--hub-radius-l);
}

@media (min-width: 48rem) {
    .hub-salonruf {
        grid-template-columns: minmax(0, 1fr) auto;
    }

    .hub-salonruf--live {
        grid-template-columns: minmax(0, 1fr) minmax(0, 24rem);
    }
}

.hub-salonruf__text {
    display: grid;
    gap: var(--hub-gap-1);
}

.hub-salonruf__marke {
    display: flex;
    align-items: center;
    gap: var(--hub-gap-1);
    margin: 0;
    color: var(--hub-messing-hell);
    font-family: var(--hub-font-doc);
    font-size: 0.75rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

/* Er steht still: Banderole und Filmstreifen sind die Bewegungen, die im Foyer von selbst laufen (Abschnitt 7). */
.hub-salonruf__punkt {
    flex: none;
    width: 0.55rem;
    height: 0.55rem;
    border-radius: 50%;
    background: var(--hub-messing-hell);
}

.hub-salonruf__titel {
    margin: 0;
    font-size: clamp(1.25rem, 2.2vw, 1.6rem);
    font-weight: 700;
    line-height: 1.2;
}

.hub-salonruf__satz {
    max-width: var(--hub-mass);
    margin: 0;
    color: var(--hub-kino-still);
}

.hub-salonruf__alle,
.hub-salonruf__ruhe {
    margin: 0;
}

/* Der Abstand vor dem Pfeil steht als gap: In einem Flexkasten faellt das Leerzeichen zwischen zwei Kindern weg. */
.hub-salonruf__weg {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    min-height: var(--hub-griff);
    color: var(--hub-messing-hell);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.hub-salonruf__weg:hover {
    color: var(--hub-kino-text);
}

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

.hub-salonruf__tisch .hub-salon__tisch {
    min-height: 0;
    border-color: var(--hub-kino-kante);
    box-shadow: none;
}

/* ============================================ Die Seite eines Tisches ===
 *
 * `/spiele/<schluessel>` (`hub/seiten/spiel.php`): Brotkrumen, ein Kopf aus Banner und Text, darunter der Absatz
 * zum Spiel neben dem Salon und den Nachbarn, am Fuss die Fragen. Gebaut aus den Teilen, die schon da sind — dem
 * Fenster der Kachel samt Plaketten, den Knoepfen aus `tr_arena_knoepfe()`, dem Akkordeon der Fragen —, damit ein
 * Tisch auf seiner Seite genauso aussieht wie auf seiner Kachel.
 *
 * DIE SCHWELLE IST 62rem, dieselbe wie beim Kopf der Vitrine (`.hub-arenakopf`): Wer von dort hierher kommt, soll
 * die Kante an derselben Stelle finden. Was Saetze traegt, bleibt auf dem Zeilenmass.
 */

.hub-pfad {
    margin-bottom: var(--hub-gap-3);
    font-size: 0.85rem;
}

.hub-pfad__liste {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 var(--hub-gap-1);
    margin: 0;
    padding: 0;
    list-style: none;
    color: var(--hub-tinte-gedaempft);
}

/* Der Trenner steht im Stilblatt und nicht im Markup: Ein Schirmleser liest die Stufen einer Liste vor, keine Pfeile. */
.hub-pfad__stufe + .hub-pfad__stufe::before {
    content: '/';
    margin-right: var(--hub-gap-1);
    color: var(--hub-kante-griff);
}

/*
 * EIN LINK IN EINER ZEILE, ABER KEIN SATZ: Die Brotkrumen stehen allein, und jede Stufe ist eine Tippflaeche. Sie
 * bekommt deshalb ihre 44 Pixel in der Hoehe; die Breite traegt das Wort, und „Spiele" ist breit genug.
 */
.hub-pfad__link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--hub-griff);
    min-width: var(--hub-griff);
    color: var(--hub-tinte-sekundaer);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.hub-pfad__link:hover {
    color: var(--hub-tinte);
}

.hub-spielseite {
    display: grid;
    gap: var(--hub-gap-5);
}

.hub-spielseite__kopf {
    display: grid;
    gap: var(--hub-gap-4);
    align-items: center;
    padding: var(--hub-gap-4);
    border: var(--hub-border) solid var(--hub-kante);
    border-top: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

@media (min-width: 62rem) {
    .hub-spielseite__kopf {
        grid-template-columns: minmax(0, 55fr) minmax(0, 45fr);
    }
}

.hub-spielseite__fenster {
    border-radius: var(--hub-radius-m);
}

.hub-spielseite__text {
    display: grid;
    gap: var(--hub-gap-2);
    min-width: 0;
}

.hub-spielseite__marke {
    margin: 0;
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.8rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-spielseite__titel {
    margin: 0;
    font-size: clamp(1.7rem, 3.4vw, 2.6rem);
    line-height: 1.15;
    overflow-wrap: anywhere;
    text-wrap: balance;
}

.hub-spielseite__bekannt {
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-size: 0.9rem;
}

.hub-spielseite__satz {
    max-width: 100%;
    margin: 0;
    font-size: clamp(1.05rem, 1.6vw, 1.25rem);
    line-height: 1.45;
    text-wrap: pretty;
}

/* Die Knoepfe stehen hier im Fluss und nicht am Fuss einer Kachel: Der Rand oben ist ihr Abstand, nicht ein `auto`. */
.hub-spielseite__text .hub-arenaknoepfe {
    margin-top: var(--hub-gap-2);
    padding-top: 0;
}

/*
 * „TISCH ERÖFFNEN" IST HIER DIE HAUPTSACHE UND KEIN GEIST. Auf der Kachel steht er neben „Allein zocken" als zweiter
 * Weg; auf der Seite eines Tisches ab zwei ist er der einzige, und ein weisser Knopf mit grauer Kante las sich dort wie
 * ein Nachsatz. Er steht deshalb in Tinte — 17,5:1 gegen die Karte —, und nur hier.
 */
.hub-spielseite__text .hub-btn--geist {
    border-color: var(--hub-tinte);
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

.hub-spielseite__text .hub-btn--geist:hover {
    background: var(--hub-grund-karte);
    color: var(--hub-tinte);
}

.hub-spielseite__zusage {
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-size: 0.85rem;
}

/*
 * „SPIEL TEILEN“: ein leiser dritter Weg unter den beiden an den Tisch. Er traegt die Griffkante des Hauses (3,06:1,
 * WCAG 1.4.11) und keine Flaeche, denn er fuehrt nicht an den Tisch, sondern holt jemanden dazu. `[hidden]` braucht
 * die eigene Zeile: Das Attribut verliert sonst gegen `display: flex`, und ohne Skript stuende ein toter Knopf da.
 */
.hub-teilen {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-1) var(--hub-gap-2);
}

.hub-teilen[hidden],
[data-teilen][hidden] {
    display: none;
}

.hub-teilen__knopf {
    padding-inline: var(--hub-gap-2);
    border-color: var(--hub-kante-griff);
    color: var(--hub-tinte-sekundaer);
    font-size: 0.9rem;
    font-weight: 500;
    letter-spacing: 0.02em;
}

.hub-teilen__knopf:hover {
    border-color: var(--hub-tinte);
    background: transparent;
    color: var(--hub-tinte);
}

.hub-teilen__quittung {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 0.85rem;
    overflow-wrap: anywhere;
}

.hub-teilen__quittung:empty {
    display: none;
}

.hub-spielseite__rumpf {
    display: grid;
    gap: var(--hub-gap-4);
    align-items: start;
}

@media (min-width: 62rem) {
    .hub-spielseite__rumpf {
        grid-template-columns: minmax(0, 65fr) minmax(0, 35fr);
    }
}

/*
 * DIE SPALTE IST DAS ZEILENMASS. Der Absatz steht in der linken Spalte eines Rasters von 65 zu 35 und stand darin auf
 * --hub-mass (68ch): Auf 1440 Pixeln blieben rechts neben ihm rund 350 Pixel Papier, und die Spalte las sich wie ein
 * halber Satzspiegel. In einem mehrspaltigen Raster ist die Spalte selbst die Grenze (CLAUDE.md, Abschnitt 7, „Drei
 * Breiten"); unter 62rem stehen die Blöcke untereinander, und dort begrenzt ohnehin das Fenster.
 */
.hub-spielseite__ueberblick {
    max-width: none;
    margin: 0 0 var(--hub-gap-3);
    font-size: 1.05rem;
    line-height: 1.7;
    text-wrap: pretty;
}

.hub-spielseite__nach {
    max-width: none;
    margin: 0 0 var(--hub-gap-3);
    color: var(--hub-tinte-sekundaer);
}

/*
 * ---------------------------------------------------------------- Das Regelblatt auf der Seite eines Tisches
 *
 * Geschichte, Ziel, Bildkarten und Steuerung, so wie die Arena sie hinter [?] zeigt (`tr_arena_regelblatt()`). Die
 * Zwischentitel sind h3 unter dem h2 „So wird gespielt": Die Seite hat genau ein h1, und das ist der Name des Tisches.
 */
.hub-spielseite__block {
    display: grid;
    gap: var(--hub-gap-3);
    min-width: 0;
    margin-top: var(--hub-gap-4);
}

.hub-spielseite__zwischen {
    margin: 0;
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1.3;
}

/*
 * DAS TRIPTYCHON STEHT AUF DEM KINO. Die Panels sind Noir, und auf Naturpapier stuenden drei schwarze Bilder wie
 * Loecher im Blatt; der dunkle Sockel ist derselbe wie unter jedem Filmbild des Foyers. Nebeneinander stehen sie erst
 * ab 48rem: Darunter bliebe je Panel kaum ein Drittel eines Telefons, und der Satz darunter stuende in Zeilen von drei
 * Woertern.
 */
.hub-triptychon {
    display: grid;
    gap: var(--hub-gap-3);
    padding: var(--hub-gap-3);
    background: var(--hub-kino);
    border-radius: var(--hub-radius-l);
}

@media (min-width: 48rem) {
    .hub-triptychon {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.hub-triptychon__panel {
    display: grid;
    grid-template-rows: auto 1fr;
    min-width: 0;
    margin: 0;
}

/* Ziffer und Bild teilen sich die erste Zeile; fehlt die Datei, steht die Ziffer allein ueber ihrem Satz. */
.hub-triptychon__panel > .hub-triptychon__zahl,
.hub-triptychon__panel > .hub-triptychon__bild {
    grid-area: 1 / 1;
}

.hub-triptychon__panel > .hub-triptychon__text {
    grid-area: 2 / 1;
}

.hub-triptychon__zahl {
    z-index: 1;
    align-self: start;
    justify-self: start;
    min-width: 1.8rem;
    padding: 0.1rem 0.45rem;
    background: var(--hub-messing-hell);
    color: var(--hub-kino);
    font-family: var(--hub-font-doc);
    font-size: 0.9rem;
    font-weight: 700;
    line-height: 1.5;
    text-align: center;
    border-radius: var(--hub-radius-m) 0 var(--hub-radius-m) 0;
}

/*
 * Das Seitenverhaeltnis steht fest, damit der Satz darunter nicht springt, sobald die Datei eintrifft — und damit die
 * beiden Spiele mit Panels in 4:3 nicht aus der Reihe fallen. Beschnitten wird wie im Triptychon der Arena.
 */
.hub-triptychon__bild {
    display: block;
    width: 100%;
    max-width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    background: var(--hub-kino-karte);
    border-radius: var(--hub-radius-m) var(--hub-radius-m) 0 0;
}

.hub-triptychon__text {
    margin: 0;
    padding: var(--hub-gap-2) var(--hub-gap-3);
    border-top: 2px solid var(--hub-gold);
    background: var(--hub-comic-papier);
    color: var(--hub-tinte);
    font-family: var(--hub-font-comic);
    font-size: 1rem;
    line-height: 1.5;
    text-wrap: pretty;
    overflow-wrap: break-word;
    border-radius: 0 0 var(--hub-radius-m) var(--hub-radius-m);
}

/*
 * DER COMICSTREIFEN (`tr_story_streifen()`): vier Panels aus dem Heft unter /comic/buchmafia/, auf dem Sockel des
 * Hauses wie jedes Filmbild, jedes mit einer Unterschrift auf Comic-Papier (Abschnitt 7, „Eine Bildunterschrift ist
 * weder Sprechblase noch Formular"). Er steht still; bewegen darf sich das Heft, nicht das Foyer.
 *
 * DIE PANELS SIND VERSCHIEDEN BREIT, UND DAS IST DER STRIP. Zwei Motive sind fast quadratisch, zwei sind Streifen von
 * 2,3 und 2,6 zu 1. Ein gemeinsamer Rahmen schnitte die Streifen zur Hälfte weg; so teilt `flex` die Breite nach dem
 * Seitenverhältnis (`--verhaeltnis`, aus den Maßen der Datei), und alle vier stehen gleich hoch und ganz da. Auf dem
 * Telefon stehen die schmalen zu zweit und die breiten je über die ganze Zeile.
 */
.hub-story {
    display: grid;
    gap: var(--hub-gap-3);
    margin-bottom: var(--hub-gap-5);
    padding: var(--hub-gap-3) clamp(var(--hub-gap-3), 3vw, var(--hub-gap-4));
    border-top: 3px solid var(--hub-messing-hell);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    border-radius: var(--hub-radius-l);
}

.hub-story__kopf {
    display: grid;
    gap: var(--hub-gap-1);
}

.hub-story__marke {
    margin: 0;
    color: var(--hub-messing-hell);
    font-family: var(--hub-font-doc);
    font-size: 0.75rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-story__titel {
    margin: 0;
    font-size: clamp(1.25rem, 2.2vw, 1.6rem);
    font-weight: 700;
    line-height: 1.2;
}

.hub-story__satz {
    max-width: var(--hub-mass);
    margin: 0;
    color: var(--hub-kino-still);
}

.hub-story__streifen {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--hub-gap-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.hub-story__panel {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.hub-story__panel--breit {
    grid-column: 1 / -1;
}

@media (min-width: 48rem) {
    .hub-story__streifen {
        display: flex;
        align-items: stretch;
        gap: var(--hub-gap-3);
    }

    .hub-story__panel {
        flex: var(--verhaeltnis, 1) 1 0;
    }
}

.hub-story__bild {
    display: block;
    width: 100%;
    max-width: 100%;
    height: auto;
    background: var(--hub-kino-karte);
    border-radius: var(--hub-radius-m) var(--hub-radius-m) 0 0;
}

/* Die zwei schmalen stehen auf dem Telefon nebeneinander; eine Höhe für beide, der Unterschied ist ein Zehntel. */
@media (max-width: 47.99rem) {
    .hub-story__panel:not(.hub-story__panel--breit) .hub-story__bild {
        aspect-ratio: 9 / 10;
        object-fit: cover;
    }
}

.hub-story__unterschrift {
    flex: 1 0 auto;
    margin: 0;
    padding: var(--hub-gap-1) var(--hub-gap-2);
    border-top: 2px solid var(--hub-gold);
    background: var(--hub-comic-papier);
    color: var(--hub-tinte);
    font-family: var(--hub-font-comic);
    font-size: 0.95rem;
    line-height: 1.4;
    text-wrap: pretty;
    overflow-wrap: break-word;
    border-radius: 0 0 var(--hub-radius-m) var(--hub-radius-m);
}

.hub-story__weg {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-2) var(--hub-gap-3);
    margin: 0;
}

.hub-story__spoiler {
    max-width: var(--hub-mass);
    color: var(--hub-kino-still);
    font-size: 0.9rem;
}

.hub-spielziel {
    display: grid;
    gap: var(--hub-gap-1);
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    border-left: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-m);
}

.hub-spielziel__marke {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hub-gap-2);
    margin: 0;
    font-size: 1.15rem;
    font-weight: 700;
}

/* Die Plakette spricht wie die Spielerzahl auf dem Banner: Kino, Schreibmaschine, Versalien. */
.hub-spielziel__wort {
    padding: 2px var(--hub-gap-2);
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    font-weight: 400;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
    border-radius: var(--hub-radius-m);
}

.hub-spielziel__text {
    margin: 0;
    line-height: 1.6;
    text-wrap: pretty;
}

.hub-spielziel__zusatz {
    margin: 0;
    color: var(--hub-tinte-gedaempft);
    font-size: 0.92rem;
    line-height: 1.55;
}

.hub-lehre {
    display: grid;
    gap: var(--hub-gap-2);
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: hub-lehre;
}

@media (min-width: 40rem) {
    .hub-lehre {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Knack und Schocken fuehren fuenf Karten, Nagelbalken drei: Die letzte nimmt dann die Zeile, statt ein Loch zu lassen. */
    .hub-lehre > .hub-lehre__karte:last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }
}

.hub-lehre__karte {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-content: start;
    gap: 0.15rem var(--hub-gap-2);
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-m);
    counter-increment: hub-lehre;
}

.hub-lehre__karte::before {
    content: counter(hub-lehre);
    display: inline-flex;
    grid-row: 1 / span 2;
    align-items: center;
    justify-content: center;
    width: 1.7rem;
    height: 1.7rem;
    border-radius: 50%;
    background: var(--hub-messing-hell);
    color: var(--hub-kino);
    font-family: var(--hub-font-doc);
    font-size: 0.85rem;
    font-weight: 700;
}

.hub-lehre__karte > .hub-lehre__wort,
.hub-lehre__karte > .hub-lehre__lang {
    grid-column: 2;
}

.hub-lehre__wort {
    font-size: 1.02rem;
    line-height: 1.7rem;
}

.hub-lehre__lang {
    color: var(--hub-tinte-sekundaer);
    line-height: 1.55;
    text-wrap: pretty;
}

.hub-lehre__hinweis {
    margin: 0;
    padding: var(--hub-gap-2) var(--hub-gap-3);
    background: var(--hub-grund-subtil);
    color: var(--hub-tinte-sekundaer);
    line-height: 1.6;
    border-radius: var(--hub-radius-m);
}

.hub-lehre__hinweis > strong {
    color: var(--hub-tinte);
}

.hub-spielseite__steuerung {
    margin: 0;
    line-height: 1.65;
    text-wrap: pretty;
}

.hub-spielseite__fragezeichen {
    display: flex;
    align-items: flex-start;
    gap: var(--hub-gap-2);
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: 0.92rem;
    line-height: 1.55;
}

/*
 * Das Fragezeichen, wie es in der Kopfleiste der Arena steht — als Plakette und nicht als Knopf: Hier drueckt man es
 * nicht, man soll es dort wiedererkennen. Eine Griffkante wuerde etwas versprechen, das diese Seite nicht haelt.
 */
.hub-spielseite__fragezeichenmarke {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 1.55rem;
    height: 1.55rem;
    background: var(--hub-kino);
    color: var(--hub-kino-text);
    font-family: var(--hub-font-doc);
    font-weight: 700;
    border-radius: var(--hub-radius-m);
}

.hub-spielseite__rand {
    display: grid;
    gap: var(--hub-gap-4);
}

/*
 * DER RAND LAEUFT AUF DEM SCHREIBTISCH MIT. Seit das Regelblatt links steht, ist die linke Spalte zwei- bis dreimal so
 * hoch wie der Rand, und das Loch unter „Aehnliche Tische" war dasselbe, das vorher links unter dem Absatz klaffte —
 * nur auf der anderen Seite. Klebend begleitet der Rand das Lesen, und der Weg an einen Tisch bleibt neben den Regeln
 * stehen. Nur, wo er ganz ins Fenster passt: Ein klebender Kasten, der hoeher ist als das Fenster, versteckt seinen Fuss.
 * Kein Glas und kein Weichzeichner — unter ihm bewegt sich nichts hindurch.
 */
@media (min-width: 62rem) and (min-height: 46rem) {
    .hub-spielseite__rand {
        position: sticky;
        top: calc(var(--haus-kopf-hoehe) + var(--hub-gap-3));
    }
}

.hub-spielseite__salon,
.hub-spielseite__nachbarn {
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
}

.hub-spielseite__nachbarliste {
    display: grid;
    gap: var(--hub-gap-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.hub-spielseite__nachbar {
    display: grid;
    gap: 0.1rem;
    min-height: var(--hub-griff);
    padding: var(--hub-gap-2) var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante-griff);
    color: var(--hub-tinte);
    text-decoration: none;
    border-radius: var(--hub-radius-m);
    transition: background var(--hub-schnell), color var(--hub-schnell);
}

.hub-spielseite__nachbar:hover {
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

.hub-spielseite__nachbarname {
    font-weight: 600;
}

.hub-spielseite__nachbarmarke {
    font-size: 0.8rem;
    opacity: 0.8;
}

/* Die Fragen stehen hier im Raster der Seite und bringen ihren eigenen Abstand nach oben nicht noch einmal mit. */
.hub-spielseite > .hub-fragen {
    margin-top: 0;
}

.hub-spielseite > .hub-zurueck {
    margin: 0;
}

/* ================================================== Das Magazin ===
 *
 * `/magazin` (`hub/seiten/magazin.php`) und `/magazin/<slug>` (`hub/seiten/artikel.php`): eine Uebersicht aus Karten und
 * ein Artikel, dazu der Kasten auf der Seite jedes Tisches. Gebaut aus den Teilen des Foyers — Karte, Brotkrumen, Knopf —,
 * und der Text steht in der Serife der Bildunterschriften (`--hub-font-comic`): Ein Feuilleton liest sich nicht in der
 * Schrift eines Formulars.
 *
 * DER ARTIKEL STEHT IN ZWEI SPALTEN UEBER DIE VOLLE BUEHNE: links der Text auf der vollen Breite seiner Spalte, rechts
 * ein klebender Rand mit Tisch und Teilen, unter dem Raster die weiteren Artikel als Kartenreihe. Er stand erst auf `--hub-mass`
 * (68ch), dann auf 54rem, beide Male am linken Rand: ein Titel in drei kurzen Brocken und rechts daneben eine leere
 * Buehne. Die Schrift des Textes waechst mit dem Fenster bis 1,45rem, die Zwischenzeile mit ihr, damit die Rangfolge
 * haelt (CLAUDE.md, Abschnitt 7, „Drei Breiten“).
 *
 * KEINE SILBENTRENNUNG. `hyphens: auto` riss „Tref-fer“ und „sieb-zehn“ auseinander, und in einer Serife mit
 * Flatterrand ist ein Trennstrich teurer als eine kurze Zeile. Gebrochen wird nur, wo der Text selbst einen Bindestrich
 * oder ein weiches Trennzeichen traegt (`manual`), gesetzt wird linksbuendig.
 */

.hub-magazinkopf {
    display: grid;
    gap: var(--hub-gap-2);
    margin-bottom: var(--hub-gap-4);
}

.hub-magazinkopf__marke,
.hub-artikel__marke,
.hub-magazin__marke,
.hub-spielseite__magazinmarke {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--hub-gap-2);
    margin: 0;
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.8rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

/* Der Trenner steht im Stilblatt: Vorgelesen werden die Angaben, nicht die Punkte dazwischen. */
.hub-artikel__marke > span + span::before,
.hub-magazin__marke > span + span::before,
.hub-spielseite__magazinmarke > span + span::before {
    content: '·';
    margin-right: var(--hub-gap-2);
}

.hub-magazinkopf__titel {
    margin: 0;
    font-family: var(--hub-font-comic);
    font-size: clamp(2rem, 4vw, 3.2rem);
    line-height: 1.1;
}

.hub-magazinkopf__satz {
    max-width: var(--hub-mass);
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    font-size: clamp(1.05rem, 1.6vw, 1.2rem);
    line-height: 1.5;
    text-wrap: pretty;
}

/* Eine Spalte auf dem Telefon, zwei ab 40rem, drei ab 64rem — dieselben Kanten wie das Schaufenster der Startseite. */
.hub-magazin {
    display: grid;
    gap: var(--hub-gap-4);
    margin: 0 0 var(--hub-gap-5);
    padding: 0;
    list-style: none;
}

@media (min-width: 40rem) {
    .hub-magazin {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 64rem) {
    .hub-magazin {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.hub-magazin__fach {
    display: grid;
}

/*
 * DIE GANZE KARTE IST DER WEG, UND DER LINK STEHT AM TITEL. Die Flaeche darueber spannt ein `::after` auf, und das ist
 * keine zweite Tippflaeche, sondern die grosse Fassung derselben: Ein Schirmleser liest einen Link mit dem Titel als
 * Namen, und ein Daumen trifft die Karte irgendwo.
 */
.hub-magazin__karte {
    position: relative;
    display: grid;
    grid-template-rows: auto 1fr;
    overflow: hidden;
    border: var(--hub-border) solid var(--hub-kante);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

.hub-magazin__bild {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 900 / 502;
    object-fit: cover;
}

.hub-magazin__text {
    display: flex;
    flex-direction: column;
    gap: var(--hub-gap-1);
    padding: var(--hub-gap-3);
}

/*
 * DER TEILEN-KNOPF UNTEN RECHTS: `margin-top: auto` schiebt ihn an den Fuss der Karte, gleich wie lang Titel und
 * Unterzeile sind, und `z-index` hebt ihn ueber die Flaeche, die den Rest der Karte zum Weg in den Artikel macht. Die
 * Quittung steht links daneben. Ohne Skript steht das Fach nicht da (`hidden`).
 */
.hub-magazin__fuss {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--hub-gap-2);
    margin-top: auto;
    padding-top: var(--hub-gap-1);
}

.hub-magazin__fuss[hidden] {
    display: none;
}

.hub-magazin__teilen {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    padding: 0;
    border-color: var(--hub-kante-griff);
    background: var(--hub-grund-karte);
    color: var(--hub-tinte-sekundaer);
}

.hub-magazin__teilen:hover {
    border-color: var(--hub-tinte);
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

.hub-magazin__titel {
    margin: 0;
    font-family: var(--hub-font-comic);
    font-size: 1.35rem;
    line-height: 1.2;
}

.hub-magazin__link {
    display: flex;
    align-items: center;
    min-height: var(--hub-griff);
    color: var(--hub-tinte);
    text-decoration: none;
    overflow-wrap: anywhere;
}

.hub-magazin__link::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
}

.hub-magazin__karte:hover .hub-magazin__link {
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

.hub-magazin__unterzeile {
    margin: 0;
    color: var(--hub-tinte-sekundaer);
    line-height: 1.45;
}

/* ---------------------------------------------------------------- Der Artikel */

/*
 * DIE SEITE EINES ARTIKELS IST EIN RASTER AUS ZWEI SPALTEN, ab 64rem: links Brotkrumen, Titel, Fakt und Text, rechts ein
 * Rand von 22rem mit der Kachel des Tisches und dem Teilen. Es nimmt die volle Buehne wie Kopf und Fuss: Die linke Kante
 * steht unter der Marke, die rechte unter den Handgriffen der Leiste. Es war bei 84rem gedeckelt und stand damit auf
 * einem Breitbild je Seite 180 Pixel innerhalb der Leiste — ein Blatt, das schmaler ist als sein Rahmen. Darunter ist
 * es eine Spalte, in der Reihenfolge des Markups.
 *
 * DIE WEITEREN ARTIKEL STEHEN AUSSERHALB DIESES RASTERS (`.hub-artikelseite__mehr`, ein Geschwister danach). Sie standen
 * in seiner rechten Spalte unter dem klebenden Rand, in einer eigenen Zeile — und Chrome haelt ein klebendes Rasterkind
 * am ganzen Raster fest und nicht an seinem Bereich: Beim Scrollen schob sich die Liste mitten durch Kachel und Teilen.
 * Jetzt endet der Rand mit dem Raster, und die Liste folgt darunter als Reihe von Karten ueber die volle Breite.
 *
 * DIE BEREICHE HAENGEN AN DEN KINDERN DIESES RASTERS und nirgends sonst: Ein benannter Bereich an `.hub-pfad` allein
 * risse auf der Seite eines Tisches eine zweite Spalte auf (CLAUDE.md, Abschnitt 10).
 */
.hub-artikelseite {
    display: grid;
    gap: var(--hub-gap-4);
    max-width: 100%;
}

.hub-artikelseite > .hub-pfad {
    margin: 0;
}

.hub-artikelseite__rand,
.hub-artikelseite__mehr {
    display: grid;
    align-content: start;
    gap: var(--hub-gap-4);
}

.hub-artikelseite__mehr {
    margin-top: var(--hub-gap-5);
}

@media (min-width: 64rem) {
    .hub-artikelseite {
        grid-template-columns: minmax(0, 1fr) 22rem;
        grid-template-rows: auto 1fr;
        grid-template-areas:
            'pfad rand'
            'haupt rand';
        align-items: start;
    }

    .hub-artikelseite > .hub-pfad {
        grid-area: pfad;
    }

    .hub-artikelseite > .hub-artikel {
        grid-area: haupt;
    }

    .hub-artikelseite > .hub-artikelseite__rand {
        grid-area: rand;
    }
}

/*
 * DER RAND LAEUFT MIT, und zwar nur, wo er ganz ins Fenster passt — dieselbe Regel wie beim Rand der Seite eines
 * Tisches: Ein klebender Kasten, der hoeher ist als das Fenster, versteckt seinen Fuss. Kachel und Teilen sind rund
 * 610 Pixel hoch, mit Kopfleiste und Luft braucht er 45rem Fensterhoehe; das hat ein Laptop mit 1536 × 864 auch nach
 * Abzug der Browserleisten. Gemessen in `dev/hub.mjs` (`magazin()`). Kein Glas und kein Weichzeichner — unter ihm
 * bewegt sich nichts hindurch.
 */
@media (min-width: 64rem) and (min-height: 45rem) {
    .hub-artikelseite__rand {
        position: sticky;
        top: calc(var(--haus-kopf-hoehe) + var(--hub-gap-3));
    }
}

.hub-artikel {
    display: grid;
    gap: var(--hub-gap-4);
}

.hub-artikel__kopf,
.hub-artikel__hinweis,
.hub-artikel__text {
    width: 100%;
    max-width: 100%;
}

.hub-artikel__kopf {
    display: grid;
    gap: var(--hub-gap-2);
}

.hub-artikel__titel {
    margin: 0;
    font-family: var(--hub-font-comic);
    font-size: clamp(2rem, 4.4vw, 3.4rem);
    line-height: 1.1;
    overflow-wrap: anywhere;
    text-wrap: balance;
}

/*
 * DER FAKT: die Unterzeile als Aufhaenger, in einem Kasten mit der Akzentkante links und einem Hauch Akzent als Grund.
 * Er ist kein Hinweis (`.hub-artikel__hinweis` sagt etwas UEBER die Seite) und keine Bildunterschrift (die liegt auf
 * Papier unter einem Bild); er ist der erste Satz, den man liest, und der, mit dem der Artikel geteilt wird. Derselbe
 * Kasten steht auf der Seite des Tisches unter den Regeln (`.hub-spielseite__magazin`, weiter unten).
 */
.hub-artikel__fakt,
.hub-spielseite__magazin {
    display: grid;
    gap: var(--hub-gap-1);
    margin-top: var(--hub-gap-1);
    padding: var(--hub-gap-3);
    border-left: 4px solid var(--hub-akzent);
    background: var(--hub-akzent-hauch);
    border-radius: 0 var(--hub-radius-m) var(--hub-radius-m) 0;
}

.hub-artikel__faktmarke {
    margin: 0;
    color: var(--hub-akzent-schrift);
    font-family: var(--hub-font-doc);
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-artikel__unterzeile,
.hub-spielseite__magazinsatz {
    margin: 0;
    color: var(--hub-tinte);
    font-family: var(--hub-font-comic);
    font-size: clamp(1.15rem, 1rem + 0.6vw, 1.5rem);
    line-height: 1.45;
    text-wrap: pretty;
}

.hub-artikel__hinweis {
    margin: 0;
    padding: var(--hub-gap-2) var(--hub-gap-3);
    border-left: 4px solid var(--hub-akzent);
    background: var(--hub-grund-karte);
    color: var(--hub-tinte-sekundaer);
}

/* Die Initiale ist Satz und kein Bild: Sie traegt Tinte, und vorgelesen wird der Buchstabe wie jeder andere. */
.hub-artikel__text {
    font-family: var(--hub-font-comic);
    font-size: clamp(1.15rem, 1rem + 0.45vw, 1.45rem);
    line-height: 1.7;
    text-align: left;
}

.hub-artikel__text p,
.hub-artikel__liste li {
    text-wrap: pretty;
    hyphens: manual;
}

.hub-artikel__text p {
    margin: 0 0 var(--hub-gap-3);
}

/* Eine Aufzaehlung ordnet Regeln und Zahlen; die Marke steht in der Farbe der Zwischenzeilen und nicht in der Tinte. */
.hub-artikel__liste {
    display: grid;
    gap: var(--hub-gap-2);
    margin: 0 0 var(--hub-gap-3);
    padding-inline-start: 1.4em;
}

.hub-artikel__liste li {
    padding-inline-start: 0.2em;
}

.hub-artikel__liste li::marker {
    color: var(--hub-akzent-schrift);
    font-weight: 700;
}

.hub-artikel__text > p:first-child::first-letter {
    float: left;
    margin: 0.08em 0.1em 0 0;
    font-size: 3.3em;
    font-weight: 700;
    line-height: 0.8;
}

.hub-artikel__zwischen {
    margin: var(--hub-gap-4) 0 var(--hub-gap-2);
    font-family: var(--hub-font-comic);
    font-size: clamp(1.4rem, 1rem + 0.9vw, 1.8rem);
    line-height: 1.25;
}

/* Die Ueberschriften im Rand tragen den Titelstrich des Foyers, aber keinen eigenen Abstand: den macht das Raster. */
.hub-artikelseite__rand .hub-titel {
    margin: 0;
}

.hub-artikelseite__mehr .hub-titel {
    margin: 0;
}

.hub-artikelseite__mehr > .hub-zurueck {
    margin: 0;
}

/*
 * DIE KACHEL ZUM TISCH: Banner, Name, Spielerzahl und Dauer einer Runde und der Knopf, auf dem Kino wie jedes Filmbild
 * des Foyers, mit der Goldkante der Bildunterschriften oben. Im Rand steht sie hochkant; auf einer Spalte zwischen 40rem
 * und 64rem liegt sie quer, sonst waere das Banner dort so hoch wie ein halber Bildschirm.
 */
.hub-artikel__tisch {
    display: grid;
    gap: var(--hub-gap-3);
    align-items: center;
    padding: var(--hub-gap-3);
    border-top: 2px solid var(--hub-gold);
    background: var(--hub-kino);
    border-radius: var(--hub-radius-l);
}

@media (min-width: 40rem) and (max-width: 63.99rem) {
    .hub-artikel__tisch {
        grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    }
}

.hub-artikel__tischbild {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--hub-radius-m);
}

.hub-artikel__tischtext {
    display: grid;
    gap: var(--hub-gap-2);
}

.hub-artikel__tischmarke {
    margin: 0;
    color: var(--hub-kino-still);
    font-family: var(--hub-font-doc);
    font-size: 0.8rem;
    letter-spacing: var(--hub-tracking);
    text-transform: uppercase;
}

.hub-artikel__tischname {
    margin: 0;
    color: var(--hub-kino-text);
    font-family: var(--hub-font-comic);
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.2;
}

.hub-artikel__tischdaten {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-1);
    margin: 0;
}

/* Knapper gesperrt als die Plaketten des Foyers: Spielerzahl und Dauer sollen im Rand von 22rem in EINER Zeile stehen. */
.hub-artikel__tischdaten > span {
    padding: 2px var(--hub-gap-1);
    border: var(--hub-border) solid var(--hub-kino-kante);
    color: var(--hub-kino-text);
    font-family: var(--hub-font-doc);
    font-size: 0.72rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    white-space: nowrap;
    border-radius: var(--hub-radius-m);
}

/* Der Pfeil steht im Stilblatt und nicht im Wort: Vorgelesen wird der Weg, nicht das Zeichen. */
.hub-artikel__tischweg::after,
.hub-spielseite__magazinlink::after {
    content: '→';
}

/*
 * ARTIKEL TEILEN: WhatsApp ueber die ganze Breite, darunter „Teilen“ und „Link kopieren“ nebeneinander — oder einer
 * allein ueber die ganze Breite, wo das Geraet keinen eigenen Dialog hat und „Teilen“ verborgen bleibt.
 */
.hub-artikel__teilen {
    display: grid;
    gap: var(--hub-gap-3);
    padding: var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante);
    background: var(--hub-grund-karte);
    border-radius: var(--hub-radius-l);
    box-shadow: var(--hub-schatten-karte);
}

.hub-artikel__teilwege {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hub-gap-2);
}

.hub-artikel__teilwege > .hub-btn {
    flex: 1 1 0;
}

/*
 * DER WHATSAPP-KNOPF IST GRUEN, UND DIE SCHRIFT DARAUF IST TINTE: Weiss haelt auf diesem Gruen nur 1,98:1, Tinte 9,3:1.
 * Gegen die weisse Karte ist die Flaeche allein 1,98:1, und darum traegt er die tiefe Kante (6,6:1) — WCAG 1.4.11 verlangt fuer
 * ein Bedienelement 3,0, dieselbe Rechnung wie beim Messing von „Allein zocken“. Im Hover kehrt er um: Weiss auf Tief.
 */
.hub-artikel__teilwege > .hub-artikel__whatsapp {
    flex-basis: 100%;
    border-color: var(--hub-whatsapp-tief);
    background: var(--hub-whatsapp);
    color: var(--hub-tinte);
}

.hub-artikel__whatsapp:hover {
    background: var(--hub-whatsapp-tief);
    color: var(--hub-knopf-schrift);
}

.hub-artikel__weitere {
    display: grid;
    gap: var(--hub-gap-3);
}

/*
 * EINE REIHE VON KARTEN UNTER DEM ARTIKEL: so viele nebeneinander, wie bei 17rem Mindestbreite passen — auf dem
 * Schreibtisch alle vier in einer Reihe, auf dem Tablet zwei, auf dem Telefon eine. Jede Karte ist so hoch wie die
 * hoechste ihrer Reihe.
 */
.hub-artikel__weiterliste {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
    gap: var(--hub-gap-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.hub-artikel__weiterliste > li {
    display: grid;
}

.hub-artikel__weiterlink {
    display: grid;
    align-content: start;
    gap: 0.1rem;
    min-height: var(--hub-griff);
    padding: var(--hub-gap-2) var(--hub-gap-3);
    border: var(--hub-border) solid var(--hub-kante-griff);
    color: var(--hub-tinte);
    text-decoration: none;
    border-radius: var(--hub-radius-m);
    transition: background var(--hub-schnell), color var(--hub-schnell);
}

.hub-artikel__weiterlink:hover {
    background: var(--hub-tinte);
    color: var(--hub-grund-karte);
}

.hub-artikel__weitertitel {
    font-family: var(--hub-font-comic);
    font-weight: 700;
    line-height: 1.3;
}

.hub-artikel__weiterzeile {
    font-size: 0.85rem;
    line-height: 1.4;
    opacity: 0.85;
}

/*
 * DER KASTEN AUF DER SEITE EINES TISCHES IST DER FAKT SEINES ARTIKELS: dieselbe Akzentkante, derselbe Hauch Akzent und
 * dieselbe Schrift wie der Kasten „Schon gewusst?“ im Artikel (die Regeln stehen dort, als Gruppe), dazu die Quelle in
 * der Marke und ein leiser Knopf. Er stand mit einer Goldkante von vier Pixeln da — Gold ist in diesem Haus eine Linie
 * von hoechstens zwei — und trug nur den Titel als Link: Wer die Regeln las, erfuhr nicht, WORUM es im Artikel geht.
 * Der Knopf ist der Geist und nicht die Tuer: Die Wege an den Tisch stehen oben und bleiben die lauteren. Seine
 * Griffkante haelt auf dem Hauch 3,17:1.
 */
.hub-spielseite__magazin {
    gap: var(--hub-gap-2);
    margin-top: var(--hub-gap-4);
}

.hub-spielseite__magazinmarke {
    font-weight: 700;
}

.hub-spielseite__magazinlink {
    justify-self: start;
    margin-top: var(--hub-gap-1);
}
