/* Grundgeruest. Die Farb- und Schrift-Tokens (--paper, --ink, --accent,
   --font-body, --font-heading, ...) kommen aus themes.css — fuenf feste
   Sets, keine freie Kombination. Diese Datei setzt sie nur ein. */

:root {
  color-scheme: light dark;
}

* { box-sizing: border-box; }

/* **`hidden` gewinnt gegen jedes `display` dieser Datei** (Ybug 49, 51,
   52).
 *
 * Das Browser-Blatt sagt `[hidden] { display: none }`, und zwar mit dem
 * Gewicht eines Attributs. Jede Klassenregel, die einem Element ein
 * `display` gibt, sticht das aus — und dann steht ein Element da, das
 * `hidden` trägt. Dreimal ist genau das passiert, an drei
 * verschiedenen Stellen, und jedes Mal sah es aus wie ein
 * Darstellungsfehler und nicht wie eine Regel:
 *
 *   * die Rechtskarte stand leer auf jeder Seite (`.recht-karte`),
 *   * die Karte hinter einer Marke stand offen im Beitrag
 *     (`.marken-karte`),
 *   * die Menüoptionen brauchten dafür eine eigene Zeile
 *     (`.menue-optionen[hidden]`, weiter unten).
 *
 * **`!important` ist hier keine Notlösung, sondern die Aussage.**
 * `hidden` heißt „das ist gerade nicht da"; eine Formatierung, die das
 * überstimmt, ist immer ein Fehler. Die Regel steht am Anfang der
 * Datei, damit sie für alles gilt, was danach kommt.
 *
 * Wer ein Element ein- und ausblenden will, setzt und nimmt deshalb
 * `hidden` — und nicht `style.display`. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  font-family: var(--font-body, system-ui, sans-serif);
  color: var(--ink, #1b1b1b);
  background: var(--paper, #ffffff);
  line-height: 1.5;
}

h1, h2, h3, h4 {
  font-family: var(--font-heading, var(--font-body, system-ui, sans-serif));
}

/* Ohne diese Regel behaelt ein Link die Browser-Vorgabe (Blau, Magenta
   fuer besuchte Links) — das bricht mit jeder der fuenf gedeckten
   Paletten.

   Kein Unterstrich im Ruhezustand, auf ausdruecklichen Wunsch (User
   Findings.txt) — aber WCAG 1.4.1 verlangt dafuer irgendein Merkmal
   ausser Farbe, das nicht erst bei Hover/Fokus sichtbar wird (sonst
   hat ein Touchgeraet ohne Hover gar keinen Hinweis). Eine eigene
   Linkfarbe war der erste Versuch, scheiterte aber an der
   Kontrastrechnung: 4.5:1 gegen --paper (Textkontrast) UND 3:1 gegen
   --ink (Farbunterschied zum Fliesstext) gleichzeitig zu erreichen ist
   bei so dunklem --ink und so hellem --paper fuer 4 der 5 hellen
   Themes rechnerisch unmoeglich — die beiden Leuchtdichte-Fenster
   ueberlappen nicht (z. B. Wald: Kandidat muesste <=0.154 UND >=0.169
   sein). Kein Kalibrierungsproblem, eine echte Denkbarriere.
   Schriftschnitt statt Farbe loest das: permanent sichtbar, unabhaengig
   von Farbwahrnehmung, keine Kontrastrechnung notwendig. Ein Unterstrich
   kommt seither auch beim Hovern nicht mehr dazu — siehe die nächste
   Regel. */
/* **`:where(:visited)` und nicht `:visited`** (Ybug 54). Ein `a:visited`
   wiegt eine Klasse — und stach damit jede Klassenregel aus, die einem
   Link eine andere Farbe gibt. Gemessen am Hauptknopf: dessen Plus
   steht in `--accent-ink` auf `--accent`, und sobald der Weg zum
   Editor einmal besucht war, gewann die Linkfarbe. Das Plus stand dann
   in Akzentfarbe auf Akzentfarbe und war weg — „fehlt manchmal" heißt:
   fehlt, nachdem man einmal dort war. Dasselbe traf das Zeichen in der
   Kopfzeile, die Führung am Beitrag, die Spaltenköpfe und die
   Mailadresse in der Nutzertabelle.

   `:where()` bringt kein Gewicht mit. Die Regel wiegt damit einen
   Elementnamen, jede Klasse darüber gewinnt, und die Besuchtfarbe des
   Browsers ist trotzdem überschrieben — ein Autorenblatt sticht das
   Browserblatt unabhängig vom Gewicht. */
a, a:where(:visited) {
  color: var(--accent, #2f5d62);
  font-weight: 600;
  text-decoration: none;
}

/* **Auch beim Hovern keine Linie** — ausdrücklich so gewünscht
   (Ybug 2). Der Zeiger sagt ohnehin schon, dass hier etwas anzuklicken
   ist; die Linie kam obendrauf und war das, was die Seite unruhig
   machte. Stattdessen ein Farbzug: der Akzent wandert Richtung
   Nebentextfarbe, in jedem der fünf Themes ein sichtbarer Wechsel, und
   beide Enden sind gegen --paper gerechnet, die Mischung dazwischen
   also auch. Die Zeile davor trägt den vollen Wert für Browser ohne
   color-mix.

   Das dauerhafte Merkmal neben der Farbe bleibt der fette Schnitt
   (siehe oben) — WCAG 1.4.1 hängt am Ruhezustand, nicht am Hover, und
   der ändert sich hier nicht. */
a:hover {
  color: var(--muted, #5c584f);
  color: color-mix(in srgb, var(--accent, #2f5d62) 55%, var(--muted, #5c584f));
}

/* **Der Fokus ist keine Hover-Farbe.** WCAG 2.4.7 verlangt einen
   sichtbaren Fokus, und ein bloßer Farbwechsel erfüllt das nicht — wer
   mit der Tastatur geht, muss die Stelle finden, nicht erraten. Ein Ring
   in der Textfarbe trägt in jedem Theme, hell wie dunkel, ohne eine
   eigene Farbe zu brauchen. Er tritt an die Stelle des Unterstrichs,
   den der Fokus vorher mitbekam. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  border-radius: 2px;
}

main, .page {
  max-width: 32rem;
  margin: 0 auto;
  padding: 1.5rem 1rem;
}

/* **Platz unter dem letzten Eintrag** (AG-016). Unten links sitzt die
   Einstellungsleiste, unten rechts der Knopfstapel; beide sind
   `position: fixed` und liegen damit ueber dem Inhalt, egal wie weit
   man scrollt. Bei 1,5 rem Abstand nach unten lag der letzte Knopf
   einer Karte zur Haelfte unter dem Einstellungsknopf — am Telefon
   gemessen, wo die Verwaltung Karten statt einer Tabelle zeigt und die
   Handlungen deshalb ganz unten stehen.

   0,75 rem Abstand plus 2,75 rem Knopf ergeben 3,5 rem, die nie frei
   sind. Der Inhalt endet darueber.

   **Der Feed ist ausgenommen.** Er scrollt nicht die Seite, sondern
   einen eigenen Kasten in voller Hoehe (`.page-feed .feed`); ein
   Abstand am `main` verschoebe dort nur den Rahmen. */
body:not(.page-feed) main.page {
  padding-bottom: calc(1.5rem + 3.5rem);
}

/* Die Meldungen stehen seit dem 2026-09-06 nicht mehr als Streifen im
   Inhalt, sondern als Toast über der Seite — weiter unten in dieser
   Datei unter `.toasts`. */


/* **Der Beitrag steht mittig, nicht am Boden.** Vorher drückte
   `justify-content: flex-end` ihn nach unten, weil dort die
   Verfasserzeile und der Aktionsstreifen lagen und alles zusammen an
   der Unterkante stehen sollte. Die Aktionen sind in den Rundknopf
   gewandert; übrig bleibt der Beitrag mit einer Zeile darunter, und
   das gehört in die Mitte. */
/* **Unten bleibt Platz für die beiden festen Knöpfe.** Links sitzt die
   Einstellungsleiste, rechts der Rundknopf; beide liegen über dem Feed,
   beide sind rund 3 rem hoch. Ohne diesen Abstand läge die
   Verfasserzeile darunter — genau der Fehler, den die alte, fest
   positionierte Leiste hatte (FINDING-005): nicht angeschnitten,
   sondern unerreichbar.

   Ein Zahlenwert und kein Abstandshalter im Fluss: die beiden Knöpfe
   stehen außerhalb dieser Spalte, und was außerhalb steht, kann sich
   keinen Platz erdrücken. Die Zahl ist die Höhe des größeren der
   beiden (3,25 rem) plus sein Rand (0,75 rem) plus Luft. */
.feed-post {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1.25rem 1.25rem 4.75rem;
  position: relative;
}

/* --- Die Bühne: Beitrag und Führung in einer Reihe -------------------
 *
 * ASCII-BEWUSST: `beitrag-buehne` ist ein Klassenname.
 *
 * **Warum die Führung ein Nachbar ist und kein Rand.** Sie hing an der
 * rechten Fensterkante: bei 1280 Punkten stand sie bei x=1230, während
 * der Beitrag bei 856 endete — 374 Punkte daneben, in leerer Fläche.
 * Dort wird sie übersehen, und das ist keine Frage der Farbe: nichts
 * verband sie mit dem, was sie bedient. Als Flex-Nachbar hängt sie an
 * der Kante des Beitrags, gleich wie groß der gerade ist.
 *
 * **Die Bühne übernimmt die Rolle, die vorher die Karte hatte**:
 * `flex: 1 1 0` gibt ihr die definite Höhe, aus der die Karte über ihr
 * Verhältnis die Breite ableitet. Wer das hier löst, holt die Falle vom
 * 2026-09-06 zurück — die Warnung darüber bei `.post-card` gilt
 * unverändert, nur eine Ebene höher.
 */
.beitrag-buehne {
  flex: 1 1 0;
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

/* In der Reihe holt die Karte ihre Höhe von der Bühne und nicht mehr
   von der Spalte darüber. `flex: 0 1 auto` statt `1 1 0`: sie soll sich
   nicht in die Breite der Bühne strecken — erst dadurch kann die Breite
   der Höhe über das Verhältnis folgen. */
.beitrag-buehne > .post-card {
  flex: 0 1 auto;
  height: 100%;
  width: auto;
}

/* --- Der Rahmen um den Beitrag ----------------------------------------
 *
 * **Was er ist: die Kante des Beitrags.** Bis zum 2026-09-06 trug die
 * Section den Grund des Beitrags über den ganzen Schirm — die Farbe des
 * Autors lief bis an alle vier Ränder, und wo sein Werk aufhörte und
 * die Seite anfing, war nicht zu sehen (Ybug 6).
 *
 * **Warum er keine eigene Hintergrundfarbe hat.** Die Fläche malt ihren
 * Grund selbst, als Rechteck im SVG (config/canvas.py). Ein zweiter
 * Grund darunter wäre nur an den Stellen zu sehen, an denen etwas nicht
 * stimmt — und dort dann in der Farbe des Themes statt in der des
 * Beitrags.
 *
 * **Das Verhältnis ist Pflicht, nicht Kosmetik.** Es ist dasselbe wie
 * das viewBox der Fläche, und die Karte hält es nur, weil `flex: 1 1 0`
 * ihr eine definite Höhe gibt und `align-self: center` die Streckung
 * nimmt — erst dadurch kann `width: auto` der Höhe über das Verhältnis
 * folgen.
 *
 * Diese Falle stand am 2026-09-06 schon einmal, eine Ebene tiefer, und
 * die Messung von damals gilt weiter: Flex streckte die Breite auf den
 * ganzen Beitrag und schrumpfte die Höhe auf den Rest — zwei definite
 * Maße, zwischen die ein Verhältnis nicht mehr passt. Der Rahmen maß
 * 327x385 statt 0.562, die Fläche legte sich mit `xMidYMid meet` als
 * 217 Punkte breites Bild mittig hinein, und die Abspieler darüber
 * rechneten in Prozent des Rahmens: die gezeichnete Platte lag bei
 * x=102 mit 170 Punkten, der Abspieler bei x=59 mit 257. Er ragte auf
 * beiden Seiten hinaus. Wer hier `flex: 1 1 0` oder `align-self` löst,
 * holt genau das links.
 */
.post-card {
  flex: 1 1 0;
  min-height: 0;
  align-self: center;
  width: auto;
  max-width: 100%;
  aspect-ratio: 375 / 667;
  display: flex;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 14px;
  /* Die Fläche hat eckige Ecken; ohne das schaute ihr Grund an den vier
     Rundungen unter dem Rahmen hervor. */
  overflow: hidden;
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.1);
}

.post-card > .post-canvas,
.post-card > .post-canvas-wrap {
  width: 100%;
  height: 100%;
  min-height: 0;
  max-height: none;
  flex: 1 1 auto;
  border-radius: 0;
}

/* Ein Beitrag, der seinen eigenen Grund malt, malt auch seine eigene
   Lesefarbe. Beides kommt als Custom Property aus dem Template
   (Post.background_color / Post.ground_ink), beides aus der kuratierten
   Liste in static/palette.json.

   --accent wird hier mit ueberschrieben, nicht nur --ink: die Links
   darin (Melden, Ansehen) traegen sonst die Akzentfarbe des Themes, und
   die ist im Dunkelmodus hell — auf dem hellen Grund des Beitrags
   waere sie kaum zu sehen. Die Linkkonvention traegt ohnehin ueber den
   Schriftschnitt, nicht ueber die Farbe (siehe oben bei `a`), also
   kostet der Gleichzug nichts. */
.has-ground {
  background: var(--post-ground, var(--paper, #fff));
  color: var(--post-ink, var(--ink, #1b1b1b));
  --ink: var(--post-ink, #1b1b1b);
  --accent: var(--post-ink, #1b1b1b);
  /* Der Nebentext (Verfasser, Datum) darf leiser sein als der Beitrag,
     aber die Muted-Farbe des Themes ist im Dunkelmodus hell und faellt
     auf diesem Grund aus. Stattdessen die Lesefarbe, in den Grund
     hineingemischt: 78 % ergeben ueber alle sechs Gruende mindestens
     7.36:1 (schlechtester Fall Flieder), also weiterhin klar ueber AA.
     Die Zeile davor traegt den vollen Wert fuer Browser ohne
     color-mix — dort ist der Nebentext dann eben nicht leiser, und das
     ist der richtige Ausfall. */
  --muted: var(--post-ink, #1b1b1b);
  --muted: color-mix(in srgb, var(--post-ink, #1b1b1b) 78%, var(--post-ground, #fff));
}

.post-ground {
  padding: 1.25rem;
  border-radius: 12px;
  margin-bottom: 1rem;
}

/* Die Beitragsflaeche. Das Seitenverhaeltnis steht im viewBox, hier
   steht nur, wie viel Platz sie bekommt: so viel wie da ist, aber nie so
   viel, dass sie unten aus dem Bild laeuft — im Feed teilt sie sich den
   Bildschirm mit Verfasserzeile und Aktionsstreifen. `min-height: 0`
   ist der Zusatz, ohne den ein Flex-Kind seine Inhaltsgroesse nicht
   unterschreitet und den Rest hinausdraengt. */
.post-canvas {
  display: block;
  width: 100%;
  height: auto;
  max-height: 100%;
  min-height: 0;
  flex: 0 1 auto;
  border-radius: 12px;
}

/* Die zweite Ebene ueber der Flaeche: Video- und Ton-Abspieler. Sie
   koennen nicht in das SVG — `<video>` und `<audio>` gibt es dort nicht,
   und `<foreignObject>` ist ungleich unterstuetzt. Stattdessen HTML in
   Prozentangaben desselben Rahmens: die Flaeche skaliert ueber ihr
   viewBox, die Ebene ueber %, beide folgen damit derselben Groesse. */
.post-canvas-wrap {
  position: relative;
  display: block;
  width: 100%;
  max-height: 100%;
  min-height: 0;
  flex: 0 1 auto;
  /* Damit `max-height` an der Flaeche greift, muss der Rahmen dasselbe
     Verhaeltnis haben — sonst stuenden die Abspieler daneben statt
     darauf. Dieselben Zahlen wie das viewBox in config/canvas.py. */
  aspect-ratio: 375 / 667;
}

.post-canvas-wrap .post-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* **Eine Zeichenschicht über einem Abspieler nimmt keine Klicks an**
   (Ybug 55). Sie deckt den ganzen Rahmen ab; ein `<svg>` ist im
   HTML-Fluss ein Kasten und fängt auch dort ab, wo nichts gezeichnet
   ist. Der Abspieler darunter wäre damit nicht mehr zu bedienen.

   Nur die Schichten **über** der ersten: dort steht das Meiste, und
   ein Motiv zeigt beim Verweilen seinen Namen. Wer eine Ebene über
   einen Abspieler legt, verliert diesen Tooltip — und behält den
   Knopf. Das ist die richtige Richtung. */
.post-canvas-wrap .post-canvas ~ .post-canvas {
  pointer-events: none;
}

.post-canvas-overlay {
  position: absolute;
  inset: 0;
  /* Die Ebene selbst faengt nichts ab — nur ihre Kinder. Sonst laege
     eine unsichtbare Scheibe ueber dem ganzen Beitrag, und der
     Snap-Feed liesse sich mit dem Finger nicht mehr weiterziehen. */
  pointer-events: none;
  /* **Und sie stapelt nur in sich** (Ybug 55). Ihre Kinder trugen
     einen `z-index` aus der Dokumentordnung — bei einem Beitrag mit
     dreißig Ebenen also bis 29, und damit über der Rechtspille in der
     Kopfzeile (25). Ein Abspieler lag dann über dem Impressum. Mit
     `isolation` gilt jeder Wert darin nur innerhalb der Ebene, und die
     Ebene selbst liegt im Beitrag, wo sie hingehört. */
  isolation: isolate;
}

.post-overlay-media,
.post-overlay-audio {
  position: absolute;
  pointer-events: auto;
}

/* **Der Kasten trägt den Grund des Beitrags** (Ybug 96). Mit
   `preload="none"` hat ein Video vor dem ersten Druck kein Bild, und
   der Kasten stand als schwarzes Rechteck im Blatt.

   **Diese Zeile allein reicht nicht** — gemessen am 2026-09-12: der
   Abspieler malt sein Schwarz über den Hintergrund. Dagegen hilft nur
   ein Poster, und das baut der Server (config/canvas.py, `_poster`).
   Hier steht die Farbe trotzdem: sie trägt die vier abgerundeten Ecken
   und den Fall, dass das Poster einmal fehlt.

   Der erste Frame wäre die andere Lösung — er kostet eine Anfrage je
   Video und je Vorbeiscrollen, und genau die soll das
   `preload="none"` sparen. */
.post-overlay-media {
  object-fit: cover;
  border-radius: 12px;
  background: var(--post-ground, #17181a);
}

/* **Die drei Punkte an der Bedienleiste sind weg, das Vollbild steht
   da** (Ybug 97). `controlsList` hatte Herunterladen, Tempo und
   Übertragen schon aus dem Menü genommen (Ybug 85); übrig blieb das
   Vollbild, und weil der Kasten schmal ist, klappte Chrome es
   trotzdem in ein Menü. Ein Menü mit einem Eintrag ist ein Klick zu
   viel für das, was jeder an dieser Stelle sucht.

   Die beiden Regeln greifen in Chromes eigene Bedienleiste — ein
   Schattenbaum, an den nur diese `-webkit-`-Namen heranreichen. In
   Firefox und Safari gibt es sie nicht; dort bleibt die Leiste, wie
   der Browser sie zeichnet, und das ist der richtige Ausfall. */
.post-overlay-media::-webkit-media-controls-overflow-button {
  display: none !important;
}

.post-overlay-media::-webkit-media-controls-fullscreen-button {
  display: inline-flex !important;
}

/* Der Abspieler sitzt mittig auf seiner Platte. Die Platte ist im SVG
   gezeichnet und traegt Icon und Beschriftung; hier liegen nur die
   Bedienelemente darueber. */
/* **Keine erzwungene Hoehe mehr.** `height: 2rem` presste die
   Bedienleiste auf 32 Punkte; die Browser zeichnen sie aber in ihrer
   eigenen Groesse — Chrome misst 54 Punkte, und zwar auch dann, wenn das
   Element schmaler ist. Der Ueberschuss wurde nicht abgeschnitten,
   sondern ueber den Rand der Platte gemalt.

   `align-content: end` an einem Raster statt `align-items: flex-end` an
   einem Flexkasten: dort fiel das Element mit `height: auto` auf null
   zusammen, gemessen am 2026-09-06. Im Raster behaelt es seine
   Inhaltsgroesse und sitzt trotzdem unten. */
/* **Der Abspieler skaliert mit der Platte, weil er in Prozent
   desselben Rahmens gemessen ist** (Ybug 6).

   Vorher lag hier die Bedienleiste des Browsers. Die wird in seiner
   eigenen Größe gezeichnet — Chrome misst 54 Punkte, gleich wie klein
   das Element ist —, während die Platte mit dem viewBox skaliert: auf
   einer kleinen Platte legte sie sich über Icon und Titel, auf einer
   großen stand sie verloren darin. Der eigene Knopf hat dieses Problem
   nicht, sieht in jedem Browser gleich aus und trägt die Schleife mit
   Überblendung (static/musik.js).

   Die beiden Farben kommen aus dem style-Attribut, das der Server
   setzt — dieselben Werte, mit denen er die Platte zeichnet
   (config/canvas.py, MARK_STROKE und MARK_FILL). */
.post-overlay-audio {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-end;
  gap: 4%;
  padding: 0 6% 6%;
}

/* **Knopf links, Seeker daneben** (Ybug 55). Beide standen übereinander
   — der Knopf mittig auf der Platte, darunter ein Balken über die ganze
   Breite. Das war zweimal dieselbe Zeile Bedienung in zwei Zeilen Höhe,
   und der Balken sah aus wie ein Regler, ohne einer zu sein.

   `align-items: center`, damit der Seeker auf der Mitte des Knopfes
   liegt und nicht an seiner Unterkante. */
.ton-bedienung {
  display: flex;
  align-items: center;
  /* Enger als die vier Prozent von vorher: die Reihe trägt seit Ybug 98
     vier Glieder statt zwei. */
  gap: 3%;
  width: 100%;
  /* **Die Höhe steht hier und nicht am Knopf.** Der Knopf maß sich in
     Prozent der Platte; in einer Reihe, deren Höhe sich nach ihrem
     Inhalt richtet, ergibt eine Prozenthöhe nichts. Jetzt ist die Reihe
     das Maß, und der Knopf füllt sie. */
  height: 40%;
}

.ton-bedienung .ton-knopf {
  flex: 0 0 auto;
}

.ton-bedienung .ton-fortschritt {
  flex: 1 1 auto;
}

/* **Der Ton rechts: Schalter und Regler** (Ybug 98). Der Schalter
   trägt keinen gefüllten Kreis — der gehört dem Abspielknopf, und
   zwei gleich schwere Knöpfe in einer Reihe sagten, es gebe zwei
   Hauptsachen. Der Regler ist kurz und fest: die Stelle im Stück ist
   die Angabe, die Platz braucht, die Lautstärke stellt man einmal. */
.ton-schalter {
  flex: 0 0 auto;
  height: 60%;
  width: auto;
  aspect-ratio: 1;
  min-height: 0.9rem;
  padding: 0;
  border: none;
  background: none;
  color: var(--ton-strich, #5c584f);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.ton-schalter .ton-schalter-still,
.ton-schalter[aria-pressed="true"] .ton-schalter-laut {
  display: none;
}

.ton-schalter[aria-pressed="true"] .ton-schalter-still {
  display: inline-flex;
}

.ton-schalter .icon {
  width: 100%;
  height: 100%;
}

.ton-lautstaerke {
  flex: 0 0 20%;
  position: relative;
  height: 1.1rem;
  display: flex;
  align-items: center;
  cursor: pointer;
  touch-action: none;
}

.ton-lautstaerke::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 3px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ton-strich, #5c584f) 25%, transparent);
}

.ton-lautstaerke span {
  position: relative;
  display: block;
  height: 3px;
  width: 60%;
  border-radius: 999px;
  background: var(--ton-strich, #5c584f);
}

.ton-lautstaerke:focus-visible {
  outline: 3px solid var(--ton-strich, #5c584f);
  outline-offset: 2px;
  border-radius: 999px;
}

/* **Der wandernde Titel** (Ybug 98). Er steht gekürzt da; darunter
   liegt derselbe Titel in voller Länge und läuft beim Zeigen einmal
   durch. Weite und Dauer kommen vom Server — nur er weiß, wie weit
   der Titel hinausragt (config/canvas.py, `_platte_svg`).

   **Die Klasse und nicht `:hover`.** Die Platte ist gezeichnet und
   liegt unter der Bedienebene; sie nimmt selbst keine Zeigerereignisse
   an (`.post-canvas ~ .post-canvas`). Was der Zeiger trifft, ist der
   Abspieler darüber — static/musik.js setzt die Klasse von dort aus.

   Ohne Zeigegerät passiert nichts, und das ist in Ordnung: die
   gekürzte Fassung steht da, und der volle Titel steht im Ersatztext
   und in der Textliste. */
.platte-titel-lang {
  display: none;
}

.platte.zeigt .platte-titel-kurz {
  display: none;
}

.platte.zeigt .platte-titel-lang {
  display: block;
  animation: platte-lauf var(--ton-dauer, 6s) linear infinite alternate;
}

@keyframes platte-lauf {
  0%,
  15% {
    transform: translateX(0);
  }
  85%,
  100% {
    transform: translateX(var(--ton-lauf, 0));
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Wer Bewegung abbestellt hat, bekommt den vollen Titel ohne Lauf —
     er steht dann am Anfang und ist abgeschnitten wie vorher. */
  .platte.zeigt .platte-titel-lang {
    animation: none;
  }
}

/* **Ohne Skript bleibt die Leiste des Browsers.** Sie ist dann zu groß
   — aber sie ist da. static/musik.js nimmt ihr `controls` und holt den
   Knopf hervor. */
.post-overlay-audio audio {
  width: 100%;
}

.ton-knopf {
  /* Die Höhe kommt von der Reihe darum (`.ton-bedienung`), die Breite
     über das Verhältnis: so bleibt der Knopf rund und wächst mit der
     Platte. */
  height: 100%;
  width: auto;
  aspect-ratio: 1;
  min-height: 1.5rem;
  padding: 0;
  border: none;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--ton-strich, #5c584f);
  color: var(--ton-grund, #f2efe9);
  cursor: pointer;
}

/* --- Das i hinter dem Beitrag (Ybug 32) ---

   Der Ersatztext stand als grauer Kasten unter jedem Beitrag: dieselbe
   Auskunft ein zweites Mal, in schlechterer Form. Jetzt holt ihn dieser
   Knopf hervor.

   Er sitzt über dem Rundknopf, nicht daneben: unten rechts ist die Ecke
   der Bedienung, und zwei Kreise übereinander lesen sich als eine
   Reihe — zwei nebeneinander als zwei Absichten. */
.post-info {
  position: fixed;
  right: 1rem;
  /* Über dem Knopfstapel, der seinerseits über dem Fuß steht (b54). */
  bottom: calc(5.25rem + var(--fuss-hoehe));
  z-index: 30;
  width: 2.75rem;
  height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  background: var(--paper, #fff);
  color: var(--ink, #1b1b1b);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  cursor: pointer;
}

.post-info-karte {
  max-width: min(32rem, 90vw);
  padding: 1rem 1.25rem;
  border: none;
  border-radius: 12px;
  /* Der Grund des Beitrags, nicht der des Themes: die Karte zeigt
     seinen Inhalt. Dieselben zwei Werte wie überall, wo Text auf dem
     Grund eines Beitrags steht. */
  background: var(--post-ground, var(--paper, #fff));
  color: var(--post-ink, var(--ink, #1b1b1b));
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
}

.post-info-karte::backdrop {
  background: rgba(0, 0, 0, 0.4);
}

.post-info-text {
  margin: 0 0 0.75rem;
}

/* **Was ein Fenster tun lässt, steht rechts** (Ybug 50, 51). Die Regel
   gilt im ganzen Haus: die Rückfrage richtet ihre beiden Knöpfe so aus,
   die Vorschau der Verwaltung ihren einen, und hier das „Schließen"
   unter dem Ersatztext. Es stand links unter dem Absatz und sah damit
   aus wie die Fortsetzung des Textes statt wie die Handlung, die es
   ist. Rechts liegt es außerdem dort, wo der Daumen ohnehin ist. */
.post-info-karte form {
  display: flex;
  justify-content: flex-end;
}

/* --- Die Karte hinter einer Ort- oder Terminmarke (Ybug 24) ---

   Der Knopf selbst ist unsichtbar: gezeichnet ist die Marke im SVG
   darunter, hier liegt nur die Fläche, die den Finger annimmt. Sie ist
   so groß wie die Marke, und das sind vierzig Punkte im Bezugsrahmen —
   auf einem Telefon etwa dreißig, also über der Grenze, ab der ein Ziel
   sicher zu treffen ist. */
.post-marke {
  position: absolute;
  pointer-events: auto;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
}

.post-marke:focus-visible {
  outline: 3px solid var(--accent, #2f5d62);
  outline-offset: 2px;
}

/* --- Die Karte hinter einer Marke ------------------------------------
 *
 * ASCII-BEWUSST: `marken-karte`, `marken-titel`, `marken-block`,
 * `marken-uhr`, `marken-kalender` und `marken-abstand` sind
 * Klassennamen.
 *
 * **Sie steht mittig auf dem Schirm** (Ybug 51). Bis zum 2026-09-08 lag
 * sie über der Mitte des Beitrags: bei einer Marke am unteren Rand hing
 * sie halb außerhalb, und im Feed verdeckte sie den Beitrag, zu dem sie
 * gehört. Jetzt ist es ein `<dialog>` wie jedes andere Fenster im Haus
 * (templates/base.html, static/marken.js).
 *
 * **Titel oben mittig, Angaben darunter im Block, die Handlung mittig
 * darunter** (Ybug 56, 57, 110, 111). Der Ausgang gehört nicht zur
 * Karte: er steht als „Schließen" im Rahmen des Fensters
 * (templates/base.html).
 */
.marken-fenster[open] {
  width: min(24rem, calc(100vw - 2rem));
  max-height: 85vh;
  overflow-y: auto;
  padding: 1rem 1.25rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 14px;
  background: var(--paper, #fff);
  color: var(--ink, #1b1b1b);
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.28);
}

.marken-fenster::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

.marken-karte {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* Der Titel steht mittig und trägt die Überschriftenschrift: er ist
   der Name der Sache, nicht ihre erste Angabe. */
.marken-titel {
  margin: 0;
  text-align: center;
  font-family: var(--font-heading, sans-serif);
  font-weight: 700;
  font-size: 1.05rem;
}

/* **Der Titel steht auch beim Ort mittig** (Ybug 137). Er stand seit
   Ybug 93 links, unter der Überlegung, er sei die erste Zeile einer
   Anschrift — Bezeichnung, Straße, Ort —, und drei Zeilen, die
   zusammen gelesen werden, fingen an derselben Kante an.

   Seit der Kartenausschnitt darunter steht (Ybug 94), stimmt das
   nicht mehr: zwischen Titel und Anschrift liegt ein Bild über die
   volle Breite, die drei Zeilen stehen also gar nicht beieinander.
   Damit ist der Titel wieder das, was er beim Termin immer war — der
   Name der Sache über ihrem Bild.

   **Die Anschrift darunter bleibt links** (`.marken-block`): sie ist
   der Fall, für den Ybug 93 gilt, und sie ist es weiterhin. */

/* Der Kartenausschnitt des Ortes (Ybug 94). Er steht, wo beim Termin
   die Uhr steht, und nimmt die volle Breite des Fensters: ein Bild, das
   einen Ort zeigen soll, wird durch einen Rand nicht besser.

   `aspect-ratio` und nicht nur die Maße am `<img>`: das Bild kommt
   480x240, die Karte ist schmaler, und ohne das Verhältnis rechnete der
   Browser die Höhe erst aus, wenn das Bild da ist — das Fenster
   sprünge beim Nachrücken.

   `background` darunter, damit die Fläche in der Wartezeit ruhig
   bleibt statt weiß aufzublitzen. */
.marken-ausschnitt {
  margin: 0;
  border-radius: 0.6rem;
  overflow: hidden;
  background: color-mix(in srgb, var(--ink, #1b1b1b) 8%, transparent);
  aspect-ratio: 2 / 1;
}

.marken-ausschnitt img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Uhr und Kalenderblatt nebeneinander, mittig: sie sind ein Bild und
   keine Angabe. Die Angaben stehen darunter im Block. */
.marken-zeitbild {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

.marken-uhr {
  width: 4.5rem;
  height: 4.5rem;
  color: var(--ink, #1b1b1b);
}

/* Das Kalenderblatt: Monat auf einem Balken, darunter die Zahl groß und
   das Jahr klein. Dieselbe Anmutung wie ein Abreißkalender, ohne dass
   ein Bild dafür geladen werden müsste. */
.marken-kalender {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 4.5rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 8px;
  overflow: hidden;
  text-align: center;
  line-height: 1.1;
}

.marken-kalender-monat {
  padding: 0.15rem 0;
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.marken-kalender-tag {
  padding: 0.1rem 0;
  font-family: var(--font-heading, sans-serif);
  font-size: 1.7rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.marken-kalender-jahr {
  padding-bottom: 0.2rem;
  font-size: 0.75rem;
  color: var(--muted, #5c584f);
}

/* Der Block: Bezeichnung und Wert je Zeile, beide linksbündig. Ein
   Raster und keine Tabelle — es sind zwei Spalten und keine Daten, die
   jemand sortieren würde. */
.marken-block {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.6rem;
  margin: 0;
  text-align: left;
  font-size: 0.9rem;
}

.marken-block dt {
  margin: 0;
  color: var(--muted, #5c584f);
}

.marken-block dd {
  margin: 0;
}

/* Wie lange es her ist oder noch dauert: leise, und als letzte Zeile
   des Blocks (Ybug 94, 111). Es stand erst rechts, als wäre es ein Weg
   hinaus, dann mittig unter den Angaben — beides macht daraus eine
   eigene Sache. Es ist keine: „noch 2 Tage" ist dieselbe Auskunft wie
   „15.09.2026", nur von heute aus gerechnet, und schließt deshalb an
   die Uhrzeit an, wie die Uhrzeit an das Datum.

   Darum linksbündig an derselben Kante wie „Datum" und „Uhrzeit", und
   darum das Polster der Karte zurückgenommen: die 0.75rem zwischen
   ihren Teilen trennen hier zwei Dinge, die eines sind. Übrig bleiben
   die 0.15rem, mit denen auch die Zeilen des Blocks untereinander
   stehen. */
.marken-abstand {
  margin: -0.6rem 0 0;
  text-align: left;
  font-size: 0.85rem;
  color: var(--muted, #5c584f);
  font-variant-numeric: tabular-nums;
}

/* **Die Handlung der Karte steht mittig** (Ybug 110, 111). Sie stand
   rechts, unter der Regel „der Weg hinaus steht rechts" (Ybug 50,
   51) — und das war die falsche Regel: „Route dorthin" und „In den
   Kalender eintragen" sind kein Ausgang, sondern das eine, was sich
   mit dieser Karte tun lässt. Der Ausgang ist „Schließen" und steht
   darunter im Rahmen des Fensters (templates/base.html).

   Eine Handlung, die der ganzen Karte gilt, steht unter ihrer Mitte —
   und nicht in der Ecke, in der man den Ausgang sucht. */
.marken-weg {
  margin: 0;
  text-align: center;
}

/* **Zwischen der Handlung und dem Ausgang steht Luft** (Ybug 136). Die
   Knopfreihe des Fensters schloss unmittelbar an die Karte an: „In den
   Kalender eintragen" und „Schließen" standen 12 Punkte auseinander und
   lasen sich als ein Paar — dabei ist das eine das, wozu die Karte da
   ist, und das andere der Weg heraus.

   Der Abstand steht am Fenster und nicht an der Karte: die Karte weiß
   nichts davon, dass unter ihr noch etwas kommt, und ihr eigener
   Innenabstand (`.marken-karte { gap }`) gilt zwischen ihren Zeilen. */
.marken-fenster .rueckfrage-knoepfe {
  margin-top: 1.25rem;
}

/* --- Das Dokument über dem Beitrag -----------------------------------

   Die Schau deckt genau den Beitrag ab und nicht den Bildschirm: sie
   liegt in derselben Überlagerung wie die Abspieler und die Marken, also
   im Rahmen von 375 zu 667. Ein Vollbild über die ganze Seite hätte im
   Feed den nächsten Beitrag mit verdeckt und wäre nur über eine zweite
   Ebene wieder wegzubekommen.

   **Der Grund ist der des Beitrags** (Ybug 119). Er war fast schwarz,
   und das mit Absicht: was darauf liegt, ist meist ein weißes Blatt,
   und ein heller Grund ließe dessen Rand verschwinden. Der Preis war
   ein dunkler Balken über und unter dem Blatt, mitten in einem
   Beitrag, der seine eigene Farbe hat — die Schau deckt den Beitrag
   ab und soll nicht aussehen wie ein fremdes Fenster darüber.

   `--post-ground` steht am Rahmen, in den die Schau gehängt wird
   (config/canvas.py, static/dokument.js). Die Sorge um den Rand des
   Blattes bleibt berechtigt und wird jetzt dort gelöst, wo sie
   entsteht: das Blatt bekommt einen Schatten. */
.dokument-schau {
  position: absolute;
  inset: 0;
  z-index: 200;
  /* Die Überlagerung selbst fängt nichts ab (siehe `.post-canvas-overlay`);
     diese Ebene soll es. */
  pointer-events: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--post-ground, #f2efe9);
}

.dokument-seite {
  max-width: 100%;
  max-height: 100%;
  /* `contain` und nicht `cover`: bei einem Dokument ist der Rand Teil
     der Auskunft, und ein beschnittenes Blatt sähe aus wie ein Fehler. */
  object-fit: contain;
  /* Damit ein weißes Blatt auf einem hellen Grund eine Kante behält
     (Ybug 119) — der Schatten sagt, wo das Dokument aufhört. */
  box-shadow: 0 1px 12px rgba(23, 24, 26, 0.28);
}

/* Die Pfeile liegen über dem Blatt und nicht daneben — daneben wäre auf
   375 Punkten Breite der halbe Platz weg. Sie verschwinden am jeweiligen
   Ende: ein Pfeil, der nichts mehr tut, sagt das besser durch Fehlen als
   durch Grauwerden. */
.dokument-pfeil {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 2.2rem;
  height: 2.2rem;
  padding: 0;
  border: none;
  border-radius: 999px;
  /* **Eigene Farbe statt geerbter** (Ybug 119). Sie stand auf einem
     fast schwarzen Grund und konnte ihn erben; auf dem Grund des
     Beitrags kann der hell sein, und dann stünde dunkle Schrift auf
     dunklem Kreis. Kräftiger als die früheren 0,55 — auf hellem Grund
     muss sich das Stück abgrenzen. */
  background: rgba(23, 24, 26, 0.72);
  color: #f4f2ee;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
}

.dokument-pfeil.links {
  left: 0.4rem;
}

.dokument-pfeil.rechts {
  right: 0.4rem;
}

.dokument-blattzahl {
  position: absolute;
  bottom: 0.5rem;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  padding: 0.1rem 0.6rem;
  border-radius: 999px;
  /* Wie bei den Pfeilen: eigene Farbe, kräftig genug für einen hellen
     Grund (Ybug 119). */
  background: rgba(23, 24, 26, 0.72);
  color: #f4f2ee;
  font-size: 0.8rem;
}

.dokument-zu {
  position: absolute;
  top: 0.3rem;
  right: 0.45rem;
  padding: 0.1rem 0.4rem;
  border: none;
  border-radius: 999px;
  /* Wie bei den Pfeilen (Ybug 119). */
  background: rgba(23, 24, 26, 0.72);
  color: #f4f2ee;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
}

.dokument-pfeil:focus-visible,
.dokument-zu:focus-visible {
  outline: 3px solid #f4f2ee;
  outline-offset: 2px;
}

/* **Die kleine Gestalt: ein Kreis, nichts sonst** (Ybug 20, 22).

   Klein gezogen schnappt eine Abspielerplatte auf einen runden Knopf
   zusammen; `data-knopf` setzt der Server, wenn er sie so gezeichnet hat
   (config/canvas.py). Dann sitzt der Abspieler nicht mehr unten auf der
   Platte, sondern füllt sie — Polster, Fortschrittslinie und
   Beschriftung fallen weg, denn auf 64 Punkten ist dafür kein Platz. */
.post-overlay-audio[data-knopf] {
  justify-content: center;
  padding: 0;
  gap: 0;
}

/* **Heller Grund statt dunklem** (Ybug 169). Der Kreis war eine dunkle
   Scheibe mit hellem Zeichen und lag damit als Fleck auf dem Blatt —
   jetzt trägt er den hellen Grund der Marken, das Zeichen die
   Strichfarbe, und der Rand zieht ihn zusammen. Dieselben zwei Werte,
   die der Server ohnehin reicht (config/canvas.py). */
.post-overlay-audio[data-knopf] .ton-knopf {
  height: 100%;
  background: var(--ton-grund, #f2efe9);
  color: var(--ton-strich, #5c584f);
  border: 1px solid color-mix(in srgb, var(--ton-strich, #5c584f) 35%, transparent);
}

.post-overlay-audio[data-knopf] .ton-fortschritt {
  display: none;
}

/* Auf dem runden Knopf füllt die Bedienung die ganze Fläche — es ist
   nur noch der Knopf selbst darin. */
.post-overlay-audio[data-knopf] .ton-bedienung {
  height: 100%;
  justify-content: center;
  gap: 0;
  position: relative;
}

/* --- Der zugeschnappte Abspieler (Ybug 169) ---------------------------
 *
 * **Er klappt nicht auf.** Auf vierundsechzig Punkten ist für eine
 * Reihe aus vier Gliedern kein Platz; was bleibt, sind zwei Dinge:
 * abspielen und den Ton wegnehmen. Der Seeker fällt weg (oben), die
 * Lautstärke fährt auf Druck senkrecht über dem Knopf aus.
 * Die Farbe des Kreises steht oben bei `.ton-knopf`. */

/* Der Lautsprecher sitzt am Rand des Kreises, nicht daneben: zwei
   gleich grosse Zeichen nebeneinander sagten, es gebe zwei
   Hauptsachen. Dieselbe Ecke wie die Griffe im Editor. */
.post-overlay-audio[data-knopf] .ton-schalter {
  position: absolute;
  right: -6%;
  bottom: -6%;
  height: 42%;
  min-height: 0.8rem;
  border-radius: 999px;
  background: var(--ton-grund, #f2efe9);
  border: 1px solid color-mix(in srgb, var(--ton-strich, #5c584f) 35%, transparent);
  color: var(--ton-strich, #5c584f);
}

/* **Senkrecht über dem Lautsprecher, nicht über dem Abspielknopf**
   (Ybug 189). Er stand mittig über dem Kreis und damit weit weg von
   dem Zeichen, das ihn holt — die Hand ging unten rechts hinein und
   musste nach oben links. Jetzt wächst er aus dem Lautsprecher heraus:
   dieselbe rechte Kante, direkt darüber.

   Er ist da und nicht sichtbar — `visibility` statt `display`, damit
   die Masse stehen und der Balken nicht bei jedem Ausfahren neu
   rechnet. */
.post-overlay-audio[data-knopf] .ton-lautstaerke {
  position: absolute;
  right: -6%;
  left: auto;
  /* Knapp über dem Schalter: der sitzt auf `bottom: -6%` und ist 42%
     hoch, endet oben also bei 36%. Ohne Lücke dazwischen, damit der
     Zeiger vom einen zum anderen kommt, ohne dass er wieder zugeht. */
  bottom: 36%;
  transform: none;
  flex: none;
  width: 0.55rem;
  height: 3.5rem;
  padding: 0.3rem 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  border-radius: 999px;
  background: var(--ton-grund, #f2efe9);
  border: 1px solid color-mix(in srgb, var(--ton-strich, #5c584f) 35%, transparent);
  visibility: hidden;
  opacity: 0;
  transition: opacity 160ms ease;
}

/* **Drei Wege zeigen ihn** (Ybug 189): ein Druck auf den Lautsprecher
   (das Skript setzt `data-laut-offen`), der Zeiger auf dem Lautsprecher
   und der Zeiger auf dem Regler selbst. Der letzte hält ihn offen,
   während man zieht — ohne ihn ginge er in dem Augenblick zu, in dem
   die Hand ihn erreicht.

   `~` und nicht `+`: zwischen Schalter und Regler steht im Markup
   nichts, aber die Folge ist die einzige Zusage, auf die sich der
   Selektor stützen darf (config/canvas.py setzt sie). */
.post-overlay-audio[data-knopf][data-laut-offen] .ton-lautstaerke,
.post-overlay-audio[data-knopf] .ton-schalter:hover ~ .ton-lautstaerke,
.post-overlay-audio[data-knopf] .ton-schalter:focus-visible ~ .ton-lautstaerke,
.post-overlay-audio[data-knopf] .ton-lautstaerke:hover {
  visibility: visible;
  opacity: 1;
}

/* Die Spur läuft senkrecht durch die Mitte, der Balken wächst von
   unten. Ohne diese beiden Regeln gälten die waagerechten von oben. */
.post-overlay-audio[data-knopf] .ton-lautstaerke::before {
  left: 50%;
  right: auto;
  top: 0.3rem;
  bottom: 0.3rem;
  height: auto;
  width: 3px;
  transform: translateX(-50%);
}

.post-overlay-audio[data-knopf] .ton-lautstaerke span {
  width: 3px;
  height: 60%;
  margin: 0 auto;
}

/* Ein Video in Knopfgröße wird rund wie die anderen beiden. */
.post-overlay-media[data-knopf] {
  border-radius: 999px;
}

/* Ein Knopf, zwei Zeichen: welches gilt, sagt `aria-pressed` — dasselbe
   Attribut, das auch ein Vorleseprogramm auswertet. Eine Klasse daneben
   könnte davon abweichen. */
.ton-knopf .ton-knopf-pause,
.ton-knopf[aria-pressed="true"] .ton-knopf-start {
  display: none;
}

.ton-knopf[aria-pressed="true"] .ton-knopf-pause {
  display: inline-flex;
}

.ton-knopf .icon {
  width: 55%;
  height: 55%;
}

/* **Die Hülle um ein Zeichen ist selbst ein Flexkasten** (Ybug 109).
   Sie ist Flexelement des Knopfes und wird dadurch zum Block; das
   Zeichen darin blieb aber inline und saß auf einer Grundlinie, unter
   der noch Platz für Unterlängen steht. Gemessen am 2026-09-12: die
   Mitte des Zeichens lag 1,4 Punkte über der Mitte des Knopfes —
   wenig, und an einem runden Knopf von 31 Punkten trotzdem zu sehen.

   Zwei Flexkästen ineinander statt einem: der Knopf setzt die Hülle
   mittig, die Hülle das Zeichen. */
.ton-knopf-start,
.ton-knopf-pause,
.ton-schalter-laut,
.ton-schalter-still {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* **Der Ausgleich für das Dreieck ist weg** (Ybug 98, 109). Er stand
   hier als `translateX(8%)` und war einmal richtig: ein Dreieck, dessen
   Kasten mittig sitzt, sieht nach links verrutscht aus.

   Das Zeichen bringt diesen Ausgleich inzwischen selbst mit. Gemessen
   am 2026-09-12 im 24er-Kasten des Icons: der Pfad läuft von 5 bis 21,
   seine Mitte liegt also bei 13 und nicht bei 12 — eine Einheit nach
   rechts, und genau das ist die Verschiebung, die der Ausgleich
   vorhatte. Beides zusammen ergab 3,2 Punkte auf einem Knopf von 31,
   und das Dreieck stand sichtbar rechts.

   Das Pausezeichen brauchte nie etwas: zwei Balken sind um ihre
   eigene Mitte symmetrisch. */

/* Die Fortschrittslinie. Schmal und ohne Zahl: sie sagt „es läuft und
   wie weit", und mehr braucht ein Stück von dreißig Sekunden nicht. */
/* **Der Seeker ist ein Regler und kein Balken** (Ybug 55). Er zeigte
   nur an; wer an eine Stelle wollte, hatte keinen Weg dorthin. Jetzt
   nimmt er Klick, Zug und die Pfeiltasten (static/musik.js).

   Höher als die früheren drei Prozent: ein Ziel von zwei Punkten Höhe
   ist mit dem Finger nicht zu treffen. Die sichtbare Linie bleibt
   schmal — die Fläche darum ist Polster, das mit annimmt. */
.ton-fortschritt {
  position: relative;
  width: 100%;
  height: 1.1rem;
  display: flex;
  align-items: center;
  cursor: pointer;
  touch-action: none;
}

/* Die Rille: die sichtbare Linie, in ganzer Breite, mittig in der
   Fläche darum. */
.ton-fortschritt::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 3px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ton-strich, #5c584f) 25%, transparent);
}

.ton-fortschritt span {
  position: relative;
  display: block;
  height: 3px;
  width: 0;
  border-radius: 999px;
  background: var(--ton-strich, #5c584f);
}

.ton-fortschritt:focus-visible {
  outline: 3px solid var(--ton-strich, #5c584f);
  outline-offset: 2px;
  border-radius: 999px;
}

/* **Die Verfasserzeile steht mittig unter dem Beitrag.**

   Vorher teilte sie sich eine Zeile mit „Melden" und „Ansehen": links
   die Auskunft, rechts die Bedienung, und beide mussten sich um die
   Breite streiten — auf Englisch brach die Zeile um, und dann stimmten
   die Abstände nicht mehr. Die Bedienung liegt seit dem 2026-09-06 im
   Rundknopf unten rechts (config/wege.py), und was bleibt, gehört
   mittig unter das, worüber es Auskunft gibt (Ybug 6).

   Sie steht **außerhalb** des Rahmens und trägt deshalb die Farben der
   Seite, nicht die des Beitrags. */
.post-byline {
  margin: 0;
  flex: 0 0 auto;
  text-align: center;
  color: var(--muted, #5c584f);
}

/* **Datum und Zeichen der Art brechen zusammen um oder gar nicht**
   (b19). Das Zeichen stand als letztes Stück frei im Fluss, und auf
   375 Punkten rutschte es allein in eine zweite Zeile: die Zeile war
   48 Punkte hoch statt 24, und unter dem Beitrag stand eine
   Sprechblase ohne Satz. Dieselbe Sicherung wie beim Beziehungszeichen
   davor (`.life-area-mark`) — ein Zeichen ohne seine Angabe sagt
   nichts. */
.byline-schluss {
  white-space: nowrap;
}

/* Der Hinweis auf die Sprache der Beiträge, unter dem Feed.
 *
 * **Er ist alles, was von der alten Leiste übrig ist.** Sie trug bis
 * zum 2026-09-06 zusätzlich „Als Liste ansehen" und „Neuen Beitrag
 * verfassen" — beides steht jetzt im Rundknopf, und eine Karte für
 * einen einzelnen Satz wäre eine Karte zu viel. Er steht nur da, wenn
 * die Oberfläche nicht deutsch ist. */
.feed-note {
  flex: 0 0 auto;
  margin: 0 0.75rem 0.75rem;
  max-width: 32rem;
  align-self: center;
  font-size: 0.8rem;
  text-align: center;
  color: var(--muted, #5c584f);
}

/* --- Die Reiterleiste der Verwaltung -----------------------------------
 *
 * **Reiter statt einer Linkzeile** (Ybug 10). Fünf Wörter nebeneinander
 * über der Überschrift lasen sich wie Fließtext; wo man stand, sagte
 * allein ein Unterstrich — dasselbe Merkmal, das ein Link ohnehin beim
 * Hovern trug. Ein Reiter sagt es über seine Form.
 *
 * Die Leiste steht auf einer durchgehenden Linie, und der aktive Reiter
 * unterbricht sie: das ist es, was ihn als „vorne" lesbar macht,
 * unabhängig von der Farbe.
 *
 * Kein `overflow-x: auto` und keine Abkürzungen auf schmalen Schirmen:
 * fünf kurze Wörter brechen einfach um. Was scrollt, findet niemand
 * (siehe die Vorlagenzeile im Editor, FINDING-009).
 */
/* **Sie bleibt beim Rollen stehen** (Ybug 35). Der Tabellenkopf tut das
   schon; die Reiter darüber wanderten weg, und damit war die Ortsangabe
   verschwunden, die seit dem 2026-09-07 die einzige ist — eine
   Überschrift gibt es nicht mehr (templates/_admin_nav.html).

   `top: 0` bezieht sich auf `.site-content`, den einzigen Bereich, der
   scrollt. Der Grund ist gesetzt, weil eine haftende Leiste sonst die
   Zeilen durchscheinen lässt, die unter ihr durchlaufen. */
.admin-nav {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--paper, #fff);
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  /* Der Abstand nach unten gehört jetzt zur haftenden Leiste selbst,
     nicht in eine Lücke darunter: eine Fuge zwischen Leiste und
     Tabellenkopf ließe die oberste Zeile darin auftauchen. */
  padding-top: 0.75rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--line, #d9d9d9);
  font-size: 0.95rem;
}

/* Berührziel nach WCAG 2.5.8. Die Verwaltung wird am Telefon bedient —
   seit die Tabellen dort Karten sind, sogar öfter als vorher. */
.admin-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 2.5rem;
  padding: 0 0.9rem;
  color: var(--muted, #5c584f);
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  /* Der Reiter sitzt auf der Linie und deckt sie ab, sobald er vorne
     ist. Ein Punkt nach unten geschoben — ohne das bliebe zwischen
     Reiter und Linie eine Fuge stehen. */
  margin-bottom: -1px;
}

.admin-nav a:hover {
  color: var(--ink, #1b1b1b);
  background: var(--surface, #f0ede7);
}

/* Wo man steht, wird nicht verlinkt gelesen, sondern gelesen. Die Regel
   hängt am selben Attribut, das auch das Vorleseprogramm auswertet —
   eine eigene Klasse daneben könnte davon abweichen. */
.admin-nav a[aria-current="page"] {
  color: var(--ink, #1b1b1b);
  background: var(--paper, #fff);
  border-color: var(--line, #d9d9d9);
  /* Der aktive Reiter schneidet die Linie auf. */
  border-bottom: 1px solid var(--paper, #fff);
}

/* **`table-layout: fixed`, damit die Tabelle zwischen den Reitern nicht
   springt** (Ybug 35). Vorher rechnete der Browser jede Spalte aus
   ihrem Inhalt: dieselbe Spalte war in „Zur Prüfung" acht und in „Alle"
   vierzehn Zeichen breit, und die ganze Zeile verschob sich beim
   Wechsel der Sicht. Die Breiten stehen jetzt an der Spalte selbst
   (config/tabellen.py, `Spalte.breite`) und gelten in jeder Sicht. */
table.wide {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}
table.wide th, table.wide td {
  text-align: left;
  padding: 0.5rem;
  border-bottom: 1px solid var(--line, #d9d9d9);
  /* Bei festen Breiten muss langer Inhalt umbrechen dürfen, sonst
     schiebt ein Wort die Spalte doch wieder auf. */
  overflow-wrap: break-word;
}

/* Der Lebensbereich hinter einem Namen: Zeichen und Wort, und das Wort
   steht im Bild (Ybug 35, templates/posts/_display_phrase.html sagt,
   warum). Leiser als der Name davor — es ist die Beigabe. */
/* --- Das Zeichen des Lebensbereichs hinter einem Namen ---------------
 *
 * ASCII-BEWUSST: `life-area-mark` und `life-area-wort` sind
 * Klassennamen.
 *
 * **Es saß zu hoch, und `inline-flex` war der Grund** (Ybug 46). Ein
 * Inline-Flex-Kasten stellt sich nicht auf die Grundlinie des Textes um
 * ihn herum, sondern leiht sich die seines ersten Kindes — und das war
 * das Zeichen, dessen Unterkante dann als Grundlinie galt. Zeichen und
 * Wort standen damit rund drei Punkte über der Zeile, in der sie
 * stehen: "Ein Trost von Christian · Familie · 07.09.2026" lief
 * treppenförmig. Gemessen am 2026-09-07.
 *
 * Ein gewöhnlicher Inline-Kasten hat das Problem nicht: Zeichen und
 * Wort sitzen dann auf derselben Grundlinie wie der Name davor, und das
 * Zeichen bringt seine eigene Feinjustierung schon mit
 * (`.icon { vertical-align: -0.125em }`).
 *
 * `nowrap`, weil Zeichen und Wort zusammen eine Angabe sind — ein
 * Umbruch dazwischen ließe ein Zeichen allein am Zeilenende stehen. */
.life-area-mark {
  color: var(--muted, #5c584f);
  white-space: nowrap;
}

.life-area-mark .icon {
  margin-right: 0.2rem;
}

.life-area-wort {
  font-size: 0.85em;
}

/* **Das Zeichen der Beitragsart eröffnet die Verfasserzeile** (Ybug
 * 135). Es hing bis zum 2026-09-14 am Ende, hinter dem Datum, und nur
 * an zwei von vier Stellen. Jetzt steht es überall vorn — und trägt die
 * Art allein, sobald ein Titel die Artwendung aus dem Satz verdrängt
 * (posts/models.py, `display_phrase`).
 *
 * Dieselbe gedämpfte Farbe wie das Beziehungszeichen daneben: die
 * Verfasserzeile ist eine Angabe über den Beitrag und nicht sein
 * Inhalt. */
.kind-mark {
  color: var(--muted, #5c584f);
}


/* --- Die Führung am Beitrag ------------------------------------------
 *
 * ASCII-BEWUSST: `beitrag-fuehrung`, `fuehrung-glied`, `fuehrung-voll`
 * und `fuehrung-leer` sind Klassennamen.
 *
 * **Warum es sie gibt** (Ybug 45). Der Feed rastet ein und zeigt genau
 * einen Beitrag. Das ist die Absicht — ein Beitrag hat den Schirm für
 * sich —, und es hat einen Preis: nichts weist darauf hin, dass
 * darunter noch etwas kommt. Wer nicht von selbst wischt, sieht eine
 * Seite mit einem Beitrag.
 *
 * **Ein Komplex und keine drei Knöpfe.** Sie meinen dasselbe Ding, den
 * Beitrag daneben, und stehen deshalb in einer Pille mit einer Kante um
 * alle drei — dieselbe Form wie die Rechtspille oben rechts, nur
 * senkrecht. Drei einzelne Kreise wären drei Angebote; das hier ist
 * eines mit drei Richtungen.
 *
 * **Rechts und mittig, nicht unten.** Unten liegt der Rundknopf, und
 * links unten die Einstellungsleiste; die rechte Flanke ist die einzige
 * Kante, an der nichts steht. Mittig, weil beide Winkel gleich weit weg
 * sein sollen — oben und unten wäre einer der bequemere.
 *
 * **Dezent.** Nur eine Kante, kein Grund, gedeckte Farbe: sie gehört
 * zur Bedienung und nicht zum Beitrag. Unter dem Zeiger nimmt sie die
 * Farbe des Hauses an. Auf einem Berührschirm gibt es kein Verweilen,
 * deshalb steht sie dort ohne Zutun sichtbar da — sichtbar heißt aber
 * nicht laut.
 */
.beitrag-fuehrung {
  flex: 0 0 auto;
  align-self: center;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  background: var(--paper, #fff);
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);
  /* **`visible` und nicht `hidden`** (Ybug 165). Die Pille schnitt ab,
     was über sie hinausragt — richtig, solange nur Glieder darin
     standen, und im Weg, seit das (i) eine zweite Pille nach rechts
     aufklappt. Die runden Enden trägt jetzt das erste und das letzte
     Glied selbst (weiter unten); die Kante der Pille bleibt dieselbe. */
  overflow: visible;
}

/* Die Enden der Pille. Sie lagen im `overflow: hidden` und mussten
   nicht gesagt werden; jetzt schon — sonst stünde der Grund eines
   überfahrenen Gliedes eckig in einer runden Kante. */
.beitrag-fuehrung > :first-child,
.beitrag-fuehrung > :first-child > summary {
  border-start-start-radius: 999px;
  border-start-end-radius: 999px;
}

.beitrag-fuehrung > :last-child,
.beitrag-fuehrung > :last-child .fuehrung-glied {
  border-end-start-radius: 999px;
  border-end-end-radius: 999px;
}

.fuehrung-glied {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  padding: 0;
  background: none;
  border: none;
  color: var(--ink, #1b1b1b);
  cursor: pointer;
}

/* **Die Pille hat immer so viele Felder, wie sie Wege kennt** (Ybug
   109, b09). Am ersten Beitrag gibt es kein Zurück, am letzten kein
   Weiter, und der Winkel fehlte darum ganz — ein Knopf, der nichts
   tut, ist schlimmer als keiner. Die Pille wurde damit aber je Beitrag
   verschieden groß, und weil sie mittig an ihrer Flanke sitzt,
   wanderten beim Blättern alle übrigen Zeichen mit. Wer auf das
   Vollbild zielt, zielt beim nächsten Beitrag daneben.

   Das Feld bleibt also stehen und ist leer: **kein Zeichen, aber ein
   Platz.** Nichts zu sehen, nichts zu treffen, keine Ansage.
   `pointer-events` aus, damit es sich auch nicht anfühlt wie ein Ziel.

   **Und es fällt nicht weg** (Festlegung 2026-09-13). Ein Anlauf
   blendete es aus und hängte sein Maß als Rand an die Pille — das
   Zeichen blieb damit rechnerisch an seinem Platz, und die Pille zeigte
   nur, was es wirklich gibt. Gemeint war das nie: die Pille ist eine
   Form mit fester Zahl von Feldern, und ein Feld ohne Weg trägt eben
   kein Symbol. */
.fuehrung-leer {
  cursor: default;
  pointer-events: none;
}

/* Das Meldeformular ist nur die Hülle um seinen Knopf: es soll in der
   Pille kein eigener Kasten sein. */
.fuehrung-form {
  display: flex;
  margin: 0;
}

/* Die Trennlinie zwischen den Gliedern, nicht um sie: eine Kante je
   Glied ergäbe eine doppelte Linie in der Mitte. Das Formular zählt
   dabei mit — in der Pille steht es an der Stelle eines Gliedes.

   **Und das Glied nach dem Formular zählt ebenso** (Ybug 109). Es
   fehlte: sein Vorgänger ist das Formular und nicht ein Glied, und
   `+ .fuehrung-glied` griff damit nicht. Zwischen Löschen und dem
   Winkel nach unten stand als einziger Übergang der Pille keine
   Linie. */
.fuehrung-glied + .fuehrung-glied,
.fuehrung-form .fuehrung-glied,
.fuehrung-form + .fuehrung-glied {
  border-top: 1px solid var(--line, #d9d9d9);
}

.fuehrung-glied:hover,
.fuehrung-glied:focus-visible {
  color: var(--accent, #2f5d62);
  background: var(--surface, #f0ede7);
}

/* Das Vollbild ist der Zweck der Pille und trägt deshalb die Farbe des
   Hauses schon im Ruhezustand — die Winkel sind Bewegung, dies ist eine
   Handlung. */
.fuehrung-voll {
  color: var(--accent, #2f5d62);
}

/* **Ein Glied der Pille, das aufklappt** (Ybug 135). Das (i) öffnete
 * bis zum 2026-09-14 unmittelbar die Info-Karte; jetzt hängen drei Wege
 * daran — die Karte, das Blatt als PDF, für die Verwaltung die
 * Rohdateien.
 *
 * **Die Wege wachsen in der Pille und nicht daneben.** Ein Menü, das
 * über den Beitrag fiele, wäre ein zweiter Komplex auf einer Seite, die
 * genau einen hat (Ybug 45) — und die Pille trägt `overflow: hidden`,
 * damit ihre Glieder in den runden Kanten bleiben; was daneben läge,
 * wäre ohnehin abgeschnitten.
 *
 * Der Aufklapper übernimmt die Richtung der Pille: stehend an der
 * Flanke, quer unter dem Beitrag. Deshalb `flex-direction: inherit` und
 * keine eigene Festlegung — die Media Query unten dreht die Pille, und
 * beide drehen mit. */
/* **Der Zweig ist eine eigene Pille und fährt nach rechts auf** (Ybug
 * 165). Er stand als Fortsetzung in der Pille selbst: sie wuchs beim
 * Aufklappen nach unten und war dann nicht mehr die Pille, die man
 * kennt — drei Zeichen im Ruhezustand, sechs im offenen.
 *
 * Jetzt bleibt die Pille, wie sie ist, und neben dem (i) erscheint
 * eine zweite in derselben Form: gleiche Höhe, gleiche Kante, gleicher
 * Grund. Sie liegt an der Flanke des Beitrags und nicht darüber.
 */
.fuehrung-auf {
  position: relative;
  display: flex;
  flex-direction: inherit;
}

.fuehrung-zweig {
  position: absolute;
  inset-inline-start: calc(100% + 0.4rem);
  inset-block-start: 50%;
  transform: translateY(-50%);
  z-index: 5;
  display: flex;
  flex-direction: row;
  background: var(--paper, #fff);
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);
  overflow: hidden;
}

/* Das Dreieck, das der Browser einem `<summary>` voranstellt, gehört zu
   einer Aufklappzeile und nicht zu einem Zeichen in einer Pille. */
.fuehrung-auf > summary {
  list-style: none;
}

.fuehrung-auf > summary::-webkit-details-marker,
.fuehrung-auf > summary::marker {
  display: none;
  content: "";
}

/* Aufgeklappt trägt der Auslöser die Farbe des Hauses — dasselbe
   Signal wie am Rundknopf, nur ohne Fläche: die Pille ist die Fläche. */
.fuehrung-auf[open] > summary {
  color: var(--accent, #2f5d62);
}

/* Die Trennlinien der Pille gelten über die Verschachtelung hinweg
   weiter: `.fuehrung-glied + .fuehrung-glied` greift nur unter
   Geschwistern, und der Zweig ist keines. */
.fuehrung-auf + .fuehrung-glied,
.fuehrung-auf + .fuehrung-form .fuehrung-glied {
  border-top: 1px solid var(--line, #d9d9d9);
}

/* Im Zweig stehen die Zeichen nebeneinander: die Linie trennt links,
   nicht oben. */
.fuehrung-zweig > .fuehrung-glied + .fuehrung-glied {
  border-left: 1px solid var(--line, #d9d9d9);
}


/* **Auf engen Schirmen legt sich die Pille quer unter den Beitrag.**
 * Gemessen am 2026-09-07 bei 375 Punkten: der Beitrag ist dort 335
 * Punkte breit und lässt an der rechten Flanke 20 Punkte — die Pille
 * braucht 40 und lag damit 30 Punkte weit auf dem Beitrag. Genau das
 * soll nicht sein: der Rahmen liegt um die Fläche, und außerhalb steht
 * die Seite; was zur Bedienung gehört, hat im Bild nichts zu suchen.
 *
 * **Und sie steht unter der Verfasserzeile und nicht über ihr** (b08).
 * Genau das stand hier schon als Absicht, und die Reihenfolge im
 * Dokument sagte das Gegenteil: Beitrag, Pille, Zeile. Damit lag die
 * Zeile in der untersten Reihe der Seite — dort, wo der Rundknopf
 * schwebt, und der überdeckte ihr Ende (375 px: Zeile bis 347, Knopf ab
 * 321). Jetzt liest man von oben nach unten: der Beitrag, wer ihn
 * geschrieben hat, und dann die Wege zum nächsten.
 *
 * **`display: contents` und nicht ein zweiter Platz im Template.** Die
 * Zeile ist ein Geschwister der Bühne, die Pille steckt darin; über
 * zwei Flexbehälter hinweg ordnet `order` nicht. Die Bühne löst sich
 * hier deshalb auf, und ihre Kinder reihen sich mit der Zeile in
 * dieselbe Spalte — die Bühne hat in dieser Breite ohnehin keine
 * Aufgabe mehr, sie ist quer nur noch eine Spalte in einer Spalte.
 *
 * `min-height: 0` wandert dabei mit an die Karte: es stand an der
 * Bühne, und ohne es wüchse die Karte über ihren Anteil hinaus. Die
 * Warnung bei `.post-card` gilt unverändert.
 *
 * **Im Feed und im Vollbild dieselbe Reihenfolge.** Sie tragen
 * denselben Beitrag in derselben Karte; eine Seite, auf der die Zeile
 * über der Pille steht, und eine, auf der sie darunter steht, wären
 * zwei Darstellungen für eine Sache. */
@media (max-width: 48rem) {
  .beitrag-buehne {
    display: contents;
  }

  .beitrag-buehne > .post-card {
    flex: 1 1 0;
    min-height: 0;
    height: auto;
    max-width: 100%;
  }

  .beitrag-buehne > .beitrag-fuehrung {
    order: 1;
  }

  .beitrag-fuehrung {
    flex-direction: row;
  }

  .fuehrung-glied + .fuehrung-glied,
  .fuehrung-form .fuehrung-glied,
  .fuehrung-auf + .fuehrung-glied,
  .fuehrung-auf + .fuehrung-form .fuehrung-glied {
    border-top: none;
    border-left: 1px solid var(--line, #d9d9d9);
  }

  /* **Quer fährt der Zweig nach oben auf** (Ybug 165). Die Pille liegt
     hier unter dem Beitrag und füllt die Breite fast aus; nach rechts
     wäre aus dem Bild heraus. Über ihr ist Platz — dort steht der
     Beitrag, und der Zweig deckt für die Dauer des Griffs ein Stück
     davon ab. */
  .fuehrung-zweig {
    inset-inline-start: 50%;
    inset-block-start: auto;
    inset-block-end: calc(100% + 0.4rem);
    transform: translateX(-50%);
  }

}

/* --- Das Vollbild eines Beitrags -------------------------------------
 *
 * **Es ist dieselbe Karte wie im Feed, nur mit der ganzen Höhe.**
 * Derselbe Rahmen, dasselbe Verhältnis, dieselbe Verfasserzeile
 * darunter: der Sprung ins Vollbild soll eine Vergrößerung sein und
 * keine andere Darstellung. Ohne diese Regeln fiele die Fläche auf die
 * Breite der Seite zurück und stünde auf einem hohen Schirm klein in
 * der Mitte.
 *
 * Die Maße stehen bewusst neben denen des Feeds und nicht in einer
 * gemeinsamen Regel: der Feed hat eine Einrastung und mehrere Kinder,
 * das Vollbild hat eines. Eine Regel für beide hieße, an jeder
 * Änderung beide mitzudenken.
 */
.page-vollbild .site-content {
  overflow: hidden;
}

/* **Das schwebende Zeichen steht hier nicht** (b58, b38). Auf jeder
   anderen Seite ist es der Weg nach Hause; auf diesen beiden ist es das
   dritte Bedienelement auf einer Fläche, deren einziger Sinn ihre Größe
   ist — und es lag oben links darauf.

   Im Vollbild ist der Weg hinaus „Schließen" in der Pille, und der
   führt genauer zurück: an denselben Beitrag im Feed. Im Editor ist es
   „Verlassen" im Menü unten links, und das fragt nach, solange etwas
   nicht gesichert ist. Die beiden Knöpfe unten lassen beide Vorlagen
   ohnehin weg.

   **Das Impressum bleibt auf beiden.** Es ist die eine Ausnahme, und es
   steht im Fuß und nicht in der Kopfzeile (b17, b55). */
.page-vollbild .site-brand-zeichen,
.page-editor .site-brand-zeichen {
  display: none;
}

/* **Das Polster ist der Platz, den nichts mehr braucht** (b58). Unten
   standen 4,75 rem für den Rundknopf und die Einstellungsleiste, oben
   auf schmalen Schirmen 4 rem für das schwebende Zeichen. Beides ist
   weg, also gehört der Platz dem Beitrag: auf 375 × 812 wächst die
   Fläche von 333 × 587 auf 335 × 631, gemessen am 2026-09-13. Der Fuß
   mit dem Impressum braucht kein Polster — er ist ein Flexkind und
   nimmt seine Höhe selbst. */
.vollbild {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  height: 100%;
  max-width: none;
  margin: 0;
  padding: 1.25rem;
  position: relative;
}


/* **Der Einzug oben ist weg, weil das Zeichen weg ist** (b58). Hier
 * standen 4 rem Polster: eingezogen lag das schwebende Zeichen oben
 * links auf der Seite (8 Punkte vom Rand, 54 groß), auf 375 Punkten
 * begann der Beitrag 20 Punkte vom Rand, und beide überlappten sich in
 * der Ecke um 46 auf 41 Punkte. Im Feed ist das der Preis des
 * Einziehens und vom Leser selbst ausgelöst; hier war es der
 * Anfangszustand.
 *
 * Das Zeichen steht auf dieser Seite nicht mehr, und damit gibt es
 * nichts mehr auszuweichen. */

/* --- Die Stufen der Übersicht ----------------------------------------
 *
 * ASCII-BEWUSST: `stand-hoch` und `stand-mittel` sind Klassennamen.
 *
 * **Drei Stufen nach Dringlichkeit, und nur bei einer Zahl über null**
 * (Ybug 34, cases/views.py entscheidet, welche Zeile welche trägt).
 * Sechs gleich aussehende Zeilen sagen nicht, welche etwas von einem
 * will; sechs gefärbte sagen es auch nicht mehr.
 *
 * **Ein Balken und keine Ampelfläche.** Die Themes bringen kein
 * geprüftes Rot oder Grün mit, und eine Trauerseite soll nicht in
 * Signalfarben sprechen — die Zeile bleibt lesbar wie jede andere, und
 * die Farbe steht an ihrer Kante. Die Fläche dahinter ist ein Hauch
 * davon, gerade genug, um die Zeile im Block zu finden.
 *
 * **Die beiden Farben stehen hier und nicht in static/themes.css.**
 * Sie sind keine Themefarbe: „dringend" bedeutet in Wald dasselbe wie
 * in Nebel, und eine Farbe, die je Theme wechselt, müsste je Theme neu
 * geprüft werden. Beide tragen keinen Text, also gilt für sie die
 * Schwelle für grafische Objekte (WCAG 1.4.11, 3:1 gegen den Grund) —
 * gemessen gegen das hellste Papier (#fdfcfa) und den dunkelsten Grund
 * der fünf Themes.
 */
:root {
  --warnung: #a3271c;
  --achtung: #8a5a00;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-color-mode="light"]) {
    --warnung: #f2897c;
    --achtung: #e0a844;
  }
}

:root[data-color-mode="dark"] {
  --warnung: #f2897c;
  --achtung: #e0a844;
}

tr.stand-hoch {
  background: color-mix(in srgb, var(--warnung) 8%, transparent);
}

tr.stand-mittel {
  background: color-mix(in srgb, var(--achtung) 8%, transparent);
}

/* Der Balken sitzt an der ersten Zelle: ein `tr` trägt bei
   `border-collapse: collapse` keinen eigenen Rahmen, den man sähe. */
tr.stand-hoch td:first-child {
  box-shadow: inset 4px 0 0 var(--warnung);
}

tr.stand-mittel td:first-child {
  box-shadow: inset 4px 0 0 var(--achtung);
}

/* --- Der Spaltenkopf: Sortierweg und Auskunft ------------------------
 *
 * Der Titel selbst ist der Weg (templates/_spaltenkopf.html sagt,
 * warum), der Pfeil sagt nur, was gerade gilt.
 */
.spalte-weg {
  display: inline-flex;
  align-items: center;
  /* Eng, weil der Pfeil zum Wort gehört und weil jeder Punkt in einer
     Kopfzeile zählt, die nicht umbrechen darf. */
  gap: 0.15rem;
  color: inherit;
  min-height: 24px;
}

.spalte-weg:hover {
  color: var(--accent, #2f5d62);
}

.spalte-pfeil {
  font-size: 0.75em;
  opacity: 0.8;
}

/* Der Auskunftsknopf. Klein, aber ein volles Berührziel: er sitzt
   neben einem anderen Klickziel, und ein Fehlgriff sortiert dann statt
   zu erklären. */
/* **Die Beschriftung, die die Kartenzelle bekommt** (b63, b76). Sie
   wird von static/hinweise.js gebaut und steht danach auch dann noch im
   Markup, wenn jemand das Fenster wieder breit zieht -- dort ist der
   Tabellenkopf zurueck, und die Auskunft stuende zweimal da. */
.zelle-wort {
  display: none;
}

.spalte-info {
  padding: 0;
  width: 1.25rem;
  height: 1.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: 999px;
  color: var(--muted, #5c584f);
  vertical-align: middle;
}

.spalte-info:hover {
  color: var(--accent, #2f5d62);
  background: var(--surface, #f0ede7);
}

/* **Wo nichts geschrieben steht, steht das Zeichen trotzdem** (Ybug
   70), blass und ohne Knopf. Ein Strich in jeder zweiten Zeile machte
   aus der Spalte ein Flackern; dasselbe Zeichen in jeder Zeile macht
   daraus eine Spalte, die man senkrecht lesen kann. Die Blässe sagt
   „hier ist nichts zu holen" — dieselbe Regel wie bei
   `.zahlmarke-leer`. */
.spalte-info-leer {
  opacity: 0.4;
  cursor: default;
}

.spalte-info-leer:hover {
  color: var(--muted, #5c584f);
  background: none;
}

/* --- Die Handlungen an einem Beitrag ---------------------------------
 *
 * ASCII-BEWUSST: `handeln-knopf` ist ein Klassenname.
 *
 * **Zeichen statt Wörter, damit sie in eine Reihe passen** (Ybug 35):
 * vier Wörter brauchen 310 Punkte, vier Zeichen 140. Der Titel sagt,
 * was jedes bedeutet — sichtbar beim Verweilen, auf Berührung beim
 * Antippen (config/icons.py).
 *
 * **Es sind zwei, nicht mehr vier** (2026-09-10): Ansehen und Löschen.
 * Freigeben, Sperren und Anheften sind Stufen von Skalen geworden und
 * stehen bei dem Wert, den sie ändern. Was hier bleibt, sind
 * Handlungen und keine Zustände — ein Beitrag ist nicht „im Zustand
 * angesehen", und gelöscht ist er nicht mehr da.
 *
 * **In der Kartenform steht das Wort daneben.** Dort ist der Platz da,
 * und eine Karte, die vier Zeichen ohne Text zeigt, wäre ein Rätsel
 * mit vier Feldern.
 */
/* **Die Kante ist der volle Akzent, nicht `--line`** (2026-09-10).
   `--line` ist die Linie zwischen Tabellenzeilen — hell und
   zurückhaltend, weil sie trennen und nicht auffallen soll. An einem
   Knopf gelesen wirkt sie ausgegraut, und neben der Skala, deren
   Anfasser die volle Akzentkante trägt, sahen die Handlungen einer
   Zeile aus, als wären sie abgeschaltet.

   Ein gemischter Zwischenwert war der erste Versuch und half nicht:
   45 Prozent auf einem Theme, dessen Akzent schon ein warmes Grau ist,
   bleibt blass. Ein Knopf, der bedienbar ist, muss aussehen wie einer
   — die Abstufung zwischen Knöpfen trägt die Kantendicke und die
   Fläche, nicht die Helligkeit. Dieselbe Kante wie an `.skala-stufe`,
   damit eine Zeile ein Gewicht hat und nicht zwei. */
.handeln-knopf {
  list-style: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  /* **Er gibt nicht nach** (Ybug 127, 129, 131). Die Reihe steht auf
     `nowrap`, und ein Flexelement schrumpft von sich aus, wenn es eng
     wird. Die beiden Knöpfe in einer Hülle — der Aufklapper der
     Vorschau, das Formular des Löschens — blieben davon verschont; der
     Weg zum Editor liegt nackt in der Reihe und gab als einziger nach.
     Gemessen am 2026-09-12 bei 1680 Punkten Fensterbreite: 19,6 statt
     32 Punkte breit, also ein gequetschtes Oval zwischen zwei Kreisen.

     Zu eng wird es dadurch nicht: die Reihe braucht 90 Punkte in einer
     Zelle von 106. */
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  padding: 0;
  background: none;
  border: 1px solid var(--accent, #2f5d62);
  border-radius: var(--knopf-radius);
  color: var(--ink, #1b1b1b);
  /* **Aus einem Tag wird kein Gewicht** (b62). Die drei Wege der
     Handlungsspalte sind ein `<summary>`, ein `<a>` und ein
     `<button>`; die letzten beiden holten sich 600 von ihrer eigenen
     Grundregel, das `<summary>` nichts — in der Kartenform stand
     „Im Vollbild ansehen" mager neben zwei fetten Nachbarn. Die Zahl
     kommt aus der Knopfkonvention und steht hier nicht noch einmal. */
  font-weight: var(--knopf-gewicht);
  cursor: pointer;
}

.handeln-knopf::-webkit-details-marker,
.handeln-knopf::marker {
  display: none;
  content: "";
}

/* **Der Mülleimer fiel aus dem Rahmen** (Ybug 152). Die drei Zeichen
   der Reihe stehen in 1,1 rem, und das trägt bei zweien: die vier
   Eckwinkel der Lupe und der Stift lassen ringsum Luft. `trash-2`
   nutzt seine Fläche dagegen ganz aus — der Deckel ist die breiteste
   Linie im ganzen Satz und stiess im Kreis von 2 rem an die Kante.

   Die Größe steht deshalb am Kreis und nicht am einzelnen Aufruf: was
   hier hineingesetzt wird, soll gleich viel Luft haben, gleich welche
   Form es hat. 1 rem ist gemessen — darunter wirkt die Lupe verloren,
   darüber drückt der Deckel wieder an den Rand. */
.handeln-knopf .icon {
  width: 1rem;
  height: 1rem;
}

/* **Und der Mülleimer noch eine Spur kleiner** (Ybug 152, zweiter
   Anlauf). Gleicher Kasten heisst nicht gleich groß: `trash-2` zeichnet
   bis an seine Kanten, Lupe und Stift lassen ringsum Luft. Bei
   derselben Zahl wirkt er deshalb größer und drückt optisch an den
   Rand des Kreises — auch dort, wo er ihn rechnerisch nicht berührt.

   Der Ausgleich hängt am Namen des Zeichens (`data-icon`,
   config/icons.py) und nicht an der Fundstelle: derselbe Mülleimer
   steht in der Beitrags- und in der Nachrichtentabelle. */
.handeln-knopf .icon[data-icon="tool-delete"] {
  width: 0.88rem;
  height: 0.88rem;
}

.handeln-knopf:hover {
  border-color: var(--accent, #2f5d62);
  color: var(--accent, #2f5d62);
}

/* **`.handeln-ja` ist weg** (2026-09-10). Sie gab dem üblichen Weg
   Fläche, während die anderen nur eine Kante trugen — und der übliche
   Weg war das Freigeben, das seit dem Umbau eine Stufe der Statusskala
   ist. Übrig sind hier Ansehen, Anheften und Löschen; unter denen ist
   keiner der übliche, also trägt auch keiner Fläche. Dieselbe Ordnung
   führt die Skala weiter (`.skala-betont`). */

/* In der Tabelle bleibt das Wort weg — dort ist kein Platz, und der
   Titel trägt es. */
.handeln-wort {
  display: none;
}

/* Wie sie in der Kartenform aussehen — mit Wort —, steht dort, wo die
   Kartenform steht: weiter unten in dieser Datei. */

/* --- Der Kopierknopf -------------------------------------------------
 *
 * ASCII-BEWUSST: `kopieren` ist ein Klassenname.
 *
 * **Er erscheint bei Nähe** (Ybug 36, 37). Im Ruhezustand ist er
 * unsichtbar; wer mit dem Zeiger in die Zelle kommt, sieht ihn. Ein
 * Knopf, der immer dasteht, macht aus einer Tabelle mit zehn Spalten
 * eine mit zwanzig Zeichen — und diese Knöpfe sind Zubehör, nicht
 * Inhalt.
 *
 * **`visibility` und nicht `display`**: der Platz bleibt belegt, sonst
 * rückte die ganze Zelle beim Überfahren zur Seite.
 *
 * **Auf einem Berührungsbildschirm gibt es keine Nähe** — dort steht er
 * ständig. `hover: none` trifft genau die Geräte, bei denen ein
 * Erscheinen-bei-Nähe nie eintreten würde.
 */
.kopieren {
  padding: 0;
  width: 1.4rem;
  height: 1.4rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: 999px;
  color: var(--muted, #5c584f);
  vertical-align: middle;
  visibility: hidden;
}

td:hover .kopieren,
.kopieren:focus-visible,
p:hover .kopieren,
label:hover .kopieren,
.adresse-feld:hover .kopieren {
  visibility: visible;
}

.kopieren:hover {
  color: var(--accent, #2f5d62);
  background: var(--surface, #f0ede7);
}

@media (hover: none) {
  .kopieren {
    visibility: visible;
  }
}

/* **In der Adressspalte liegt er über der Zelle und nicht daneben**
   (Ybug 36.5). Daneben kostete er 27 Punkte, und die hatte die Spalte
   nicht: Adresse und Knopf brauchten 167 Punkte in 147, der Knopf fiel
   in eine zweite Zeile und machte jede Zeile der Tabelle 24 Punkte
   höher — gemessen am 2026-09-07. Über der Zelle kostet er nichts, und
   die Adresse bekommt die ganze Breite.

   Er verdeckt das Ende einer langen Adresse, aber erst, wenn der
   Zeiger in der Zelle steht — und wer den Zeiger dorthin bewegt, will
   die Adresse kopieren und nicht lesen. Der Grund darunter ist deshalb
   nicht durchsichtig, sonst stünde das Zeichen im Text. */
.zelle-adresse {
  position: relative;
}

.zelle-adresse .kopieren {
  position: absolute;
  top: 50%;
  right: 0.35rem;
  transform: translateY(-50%);
  background: var(--paper, #fff);
  box-shadow: 0 0 0.4rem 0.3rem var(--paper, #fff);
}

/* --- Das Adressfeld in den Einstellungen -----------------------------
 *
 * ASCII-BEWUSST: `adresse-feld` und `adresse-vorsatz` sind
 * Klassennamen.
 *
 * **Die Adresse steht vor dem Feld und nicht als Satz darunter** (Ybug
 * 37). Der Hinweis erklärte, was das Feld ist; jetzt ist es zu sehen.
 * Vorsatz und Feld sitzen in einer Zeile und lesen sich als eine
 * Adresse — deshalb keine Lücke zwischen ihnen und dieselbe
 * Grundlinie.
 *
 * Das Feld nimmt den Rest der Zeile: der Vorsatz ist so lang, wie der
 * Hostname es verlangt, und der steht nicht hier, sondern in den
 * Einstellungen.
 */
.adresse-feld {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}

.adresse-vorsatz {
  flex: 0 0 auto;
  color: var(--muted, #5c584f);
  white-space: nowrap;
}

.adresse-feld input {
  flex: 1 1 auto;
  min-width: 6rem;
}

/* **Die Adresse ist selbst der Weg ins Mailprogramm** (Ybug 36). Sie
   trug bis zum 2026-09-07 einen Umschlag davor; der kostete 19 Punkte
   und drängte den Kopierknopf in eine dritte Zeile. Sie bleibt leise
   wie ein Wort und wird erst unter dem Zeiger zur Farbe des Hauses —
   eine Tabelle mit dreißig blauen Adressen liest sich als Liste von
   Links und nicht als Liste von Menschen.

   **Etwas kleiner als der Rest der Zeile**, wie die Uhrzeit hinter
   einem Datum (`.zeit`): eine Adresse ist eine technische Angabe und
   keine Prosa. In voller Grösse brauchte "anna@example.org" 149 Punkte
   und brach in einer Spalte von 145 um — die eine umgebrochene Zeile
   machte jede Zeile der Tabelle 24 Punkte höher, in einer Tabelle mit
   dreissig Namen also 720. Gemessen am 2026-09-07.

   `anywhere`, weil eine lange Adresse sonst die Spalte aufsprengt:
   Adressen haben keine Leerzeichen, an denen ein Umbruch von sich aus
   ansetzt. */
/* **Eine Adresse bricht vor dem Klammeraffen und sonst nirgends**
   (Ybug 74). Hier stand `overflow-wrap: anywhere`: der Browser brach,
   wo die Zeile endete, und aus `anna@example.com` wurden
   `anna@example.c` und `om`. Wer die Spalte überfliegt, las an jeder
   Zeile eine andere Silbe.

   Die Naht setzt `config/adressen.py` als `<wbr>` — die einzige
   Stelle, an der die Adresse für einen Menschen dieselbe bleibt: links
   wer, rechts wo. `break-word` ist der Rückfall für den Rest: es
   bricht erst, wenn es sonst über den Rand liefe, und nicht schon bei
   der ersten Gelegenheit wie `anywhere`.

   **Zentriert, weil sie zweizeilig wird.** Zwei linksbündige Zeilen
   unterschiedlicher Länge lesen sich als abgeschnitten; um die Naht
   herum zentriert stehen sie als ein Gegenstand da. */
/* **Der Name steht über der Adresse** (b70). In der Nachrichtentabelle
   stand die Adresse allein in der ersten Zelle, und unter 72rem wird
   die erste Zelle zur Überschrift der Karte: „anna@example.com" groß,
   während überall sonst im Haus an dieser Stelle ein Mensch steht.

   Der Name trägt die Zeile, die Adresse steht als Weg darunter und
   leiser — sie wird gebraucht, wenn jemand antwortet, und nicht, um zu
   erkennen, wer geschrieben hat. */
.absender-name {
  display: block;
  text-align: center;
}

/* **Der Text der Nachricht ist der Inhalt dieser Tabelle** (b71). Er
   stand am kleinsten von allem in der Zeile — leiser als das Datum
   daneben —, während die Adresse als Überschrift der Karte obenauf lag.
   Er trägt deshalb die Lesegröße der Seite und nicht die Kleinschrift
   einer Tabellenangabe, und die Textfarbe statt der eines Weges: was
   dasteht, ist zu lesen und nicht anzuklicken. Der Weg dahinter — die
   Vorschau — bleibt, weil eine lange Nachricht die Zeile sonst
   seitenlang macht (Ybug 10). */
.nachricht-text {
  font-size: 1rem;
  font-weight: 400;
  color: var(--ink, #1b1b1b);
}

/* **Der Umschlag steht vor dem Wort** (Ybug 157). Offen heisst: an
   diesen Verwalter gerichtet; geschlossen: an jemand anderen, und dann
   steht es auch als Wort daneben. Aufmachen darf beides jeder
   Verwalter des Falls — das Zeichen sagt die Anschrift und keine
   Schranke.

   `align-items: center`, damit Zeichen und Wort auf einer Linie
   stehen, auch wenn der Betreff umbricht. */
.nachricht-umschlag {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
}

.nachricht-umschlag .icon {
  flex: 0 0 auto;
  color: var(--muted, #5c584f);
}

/* Der Betreff im Fenster: er steht über dem Text und trägt sein
   Gewicht, nicht seine Größe — die Nachricht bleibt das, was man
   liest. */
.vorschau-betreff {
  margin: 0 0 0.4rem;
  font-weight: 600;
}

.mail-adresse {
  display: block;
  color: var(--muted, #5c584f);
  font-size: 0.9rem;
  overflow-wrap: break-word;
  text-align: center;
  text-decoration: none;
}

.mail-adresse:hover,
.mail-adresse:focus-visible {
  color: var(--accent, #2f5d62);
  text-decoration: underline;
}

/* Eine Auswahl, die in einer Zelle steht: dieselbe Zurückhaltung wie
   ein Textfeld dort (siehe `.admin-titel-form input`). */
.inline-wahl {
  display: flex;
  align-items: center;
  gap: 0.3rem;
}

/* **Sie darf schrumpfen** (Ybug 36). Eine Auswahl ist so breit wie
   ihre breiteste Option, und "— keine Angabe" ist die breiteste von
   sechs: mit Zeichen davor brauchte die Zelle 158 Punkte in einer
   Spalte von 140 und schob die Nachbarspalte weg — gemessen am
   2026-09-07. `min-width: 0` hebt die Sperre auf, die ein Flex-Element
   von Natur aus hat; der Wert im Ruhezustand ist kurz (Vertraute,
   Familie, Freunde, Beruf, Freizeit), nur der Platzhalter der Altfälle
   wird beschnitten. */
.inline-wahl select {
  min-width: 0;
  padding: 0.2rem 0.25rem;
  background: none;
  border: none;
  border-bottom: 1px dashed var(--line, #d9d9d9);
  border-radius: 0;
  color: var(--ink, #1b1b1b);
  font-size: 0.9rem;
}

.inline-wahl select:hover {
  border-bottom-color: var(--accent, #2f5d62);
}

.inline-wahl select:focus {
  background: var(--paper, #fff);
  border: 1px solid var(--accent, #2f5d62);
  border-radius: 4px;
}

/* Die Uhrzeit hinter dem Datum. Eine eigene Zeile und leiser: gesucht
   wird meist der Tag, die Stunde entscheidet erst danach (Ybug 36). */
.zeit {
  display: block;
  color: var(--muted, #5c584f);
  font-size: 0.85em;
  font-variant-numeric: tabular-nums;
}

/* Mehrere Knoepfe in einer Zelle brauchen einen Abstand. Sie stehen in
   je eigenen Formularen — anders geht es nicht, jedes zeigt woandershin
   — und lagen deshalb ohne Zwischenraum aneinander: gemessen am
   2026-09-06 null Punkte zwischen "Freigeben" und "Ablehnen", die
   dunklen Flaechen beruehrten sich. `wrap`, weil sie je nach Breite
   neben- oder untereinander stehen und der Abstand in beiden
   Richtungen gebraucht wird. */
/* **Die Reihe steht in einer Hülle und nicht in der Zelle selbst.**
   `display: flex` an einem `td` nimmt der Zelle ihre Rolle in der
   Tabelle: der Browser erzeugt eine anonyme Zelle darum, und wo drei
   solche Zellen nebeneinanderstehen — Feedback, E-Mail bei Beitrag,
   Ändern in der Nutzertabelle — landen sie untereinander in einer.
   Die Zeile wurde damit 139 Punkte hoch statt 89, und die drei standen
   quer zur Kopfzeile; gemessen am 2026-09-07 (Ybug 36). In der
   Beitragstabelle fiel es nicht auf, weil es dort nur eine solche
   Zelle gibt. */
.handeln-reihe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
}

/* Die Handlungsspalte hält ihre Zeichen in einer Reihe: enger
   Abstand, kein Umbruch. Vier Knöpfe mit 0,35 rem Abstand brauchten
   147 Punkte in einer Zelle von 127 und brachen um — gemessen am
   2026-09-07.

   **Die Nutzertabelle trägt dieselbe Klasse** an ihren drei Schaltern
   (Feedback, E-Mail bei Beitrag, Ändern). Dort steht neben dem Zeichen
   noch der Wert — "Ja" oder "Nein" —, und der soll auf derselben Zeile
   bleiben wie der Knopf, der ihn umlegt. */
table.wide td.admin-handeln .handeln-reihe,
table.wide td.admin-stand .handeln-reihe {
  gap: 0.3rem;
  flex-wrap: nowrap;
}

/* Die Statusspalte hält ihre drei Zeichen in einer Zeile und den Stand
   darunter (Ybug 63). Ohne `nowrap` brach das dritte um — gemessen am
   2026-09-08 bei 1280 Punkten Fensterbreite: zwei Zeichen oben, eines
   darunter, und der Stand darunter noch einmal. Drei Zeichen, deren
   Anordnung je Zeile wechselt, lassen sich nicht überfliegen, und
   genau dafür stehen sie dort. */
table.wide td.admin-stand .handeln-reihe {
  justify-content: flex-start;
}

/* --- Die Verwaltungstabellen auf schmalen Schirmen -------------------
 *
 * **Warum sie unter 72rem zu Karten werden.** Die Beitragstabelle ist
 * 805 Punkte breit, die Nutzertabelle 719. Auf einem 375 Punkte breiten
 * Schirm ragten sie 446 beziehungsweise 360 Punkte hinaus — und seit der
 * Rahmen steht und `.site-content` quer abschneidet, laesst sich das
 * nicht mehr wegscrollen. "Freigeben", "Ablehnen", "Anheften" und
 * "Sperren" standen bei x=573 bis 813 und waren mit dem Finger schlicht
 * nicht erreichbar: ein Verwalter konnte am Telefon keinen Beitrag mehr
 * freigeben. Gemessen am 2026-09-06.
 *
 * **Die Schwelle lag bis zum 2026-09-07 bei 46rem, und das war zu
 * niedrig.** Zehn Spalten in 736 Punkten ergeben 65 Punkte je Spalte;
 * darin bricht „Freigegeben" mitten im Wort, und der Spaltenkopf
 * „Sichtbarkeit" stand zweizeilig da. Eine Tabelle, die ihre eigenen
 * Überschriften nicht in einer Zeile unterbringt, ist an dieser Breite
 * die falsche Form — dann ist die Karte die richtige.
 *
 * **72rem, weil die Nutzertabelle so viel braucht.** Ihre zehn Köpfe
 * kosten zusammen 1085 Punkte, „E-Mail bei Beitrag" allein 144 —
 * gemessen am 2026-09-07 bei 0,8 rem Kopfschrift. 72rem sind 1152
 * Punkte, und damit halten alle drei Tabellen.
 *
 * Gemessen wird an der breitesten der drei. Verschiedene Schwellen je
 * Tabelle wären genauer und würden dafür beim Wechsel des Reiters die
 * Form wechseln — dieselbe Unruhe, gegen die die festen Breiten
 * stehen.
 *
 * **Warum keine Huelle mit `overflow-x: auto`.** Das ist der uebliche
 * Griff und er kostet hier den haftenden Tabellenkopf: wer `overflow-x`
 * auf `auto` setzt, bekommt `overflow-y` gleich mit, die Huelle wird zum
 * naechsten Scrollvorfahren, und `position: sticky` am `th` haengt dann
 * an ihr statt an `.site-content`. Die Huelle ist so hoch wie ihr
 * Inhalt, scrollt senkrecht also nie — der Kopf bliebe nirgends stehen.
 *
 * **Was es kostet.** Mit `display: block` verliert die Tabelle ihre
 * Struktur fuer Vorleseprogramme; die Beschriftung kommt aus
 * `data-label` und steht damit nur im Bild. Der Tausch ist trotzdem
 * richtig: ein Knopf, den niemand mit dem Finger trifft, ist fuer den
 * Sehenden gar nicht da, waehrend ein Vorleseprogramm ihn auch heute
 * schon findet — abgeschnitten heisst sichtbar abgeschnitten, nicht aus
 * dem Baum entfernt. Ueber 72rem bleibt die Tabelle eine Tabelle. */
/* **Die Kartenkonvention** (2026-09-07). Wie eine Zeile aussieht, wenn
 * sie keine Zeile mehr sein kann — für alle Verwaltungstabellen
 * gleich:
 *
 *   1. **Die Karte trägt die Form des Hauses**: abgerundeter Rahmen,
 *      Papiergrund, ein Schatten. Dieselbe Sprache wie ein Menüeintrag
 *      (`.menue-option`) — eine dritte Form für dasselbe gäbe es sonst
 *      nirgends.
 *   2. **Die erste Zelle ist die Überschrift der Karte**, ohne
 *      Beschriftung. Sie sagt, um wen oder was es geht („Ein Gedanke
 *      von Christian", „Albers"); eine Beschriftung davor wäre die
 *      Auskunft, dass eine Überschrift eine Überschrift ist.
 *   3. **Beschriftung über dem Wert, nicht daneben.** Nebeneinander
 *      brauchte jede Angabe zwei Spalten, von denen keine breit genug
 *      war: „E-Mail bei Beitrag" und „anna@example.com" gerieten in
 *      derselben Zeile aneinander, und was zusammengehörte, stand
 *      untereinander. Übereinander bricht nichts, und die Beschriftung
 *      liest sich als das, was sie ist — die kleine Zeile darüber.
 *   4. **Eine Zelle mit Knöpfen ist eine Angabe wie jede andere**:
 *      Beschriftung darüber, darunter der Zustand und der Knopf, der
 *      ihn ändert. Drei solche Zellen über die ganze Kartenbreite —
 *      Feedback, E-Mail bei Beitrag, Ändern — ergaben drei Fußzeilen
 *      untereinander, und damit war die Karte wieder eine Liste.
 *   5. **Eine Karte ist ein Raster und keine Kette von Blöcken.** Zwei
 *      Spalten, wo der Platz reicht — sonst wäre eine Karte mit zehn
 *      Angaben zehn Zeilen hoch, und ein Fall mit dreißig Beiträgen
 *      nicht mehr zu überblicken. Was mehrzeilig ist, nimmt die ganze
 *      Breite.
 */
@media (max-width: 72rem) {
  table.wide,
  table.wide tbody,
  table.wide td {
    display: block;
    width: auto;
  }

  /* Der Kopf entfällt, seine Wörter stehen ab jetzt an den Zellen. */
  table.wide thead {
    display: none;
  }

  /* 1. und 5.: die Karte, und darin das Raster. **Zwei Spalten sind
     der Grundzustand, auch auf dem Telefon**: bei 375 Punkten bleiben
     je Spalte rund 160, und die längste Beschriftung („E-Mail bei
     Beitrag", 0,72 rem) braucht 100. Einspaltig wäre die Karte auf
     dem Gerät, auf dem sie am häufigsten gelesen wird, am längsten. */
  table.wide tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem 1rem;
    background: var(--paper, #fff);
    border: 1px solid var(--line, #d9d9d9);
    border-radius: 12px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
    padding: 0.9rem 1rem;
    margin-bottom: 0.75rem;
  }

  table.wide td {
    padding: 0;
    border-bottom: none;
    min-width: 0;
  }

  /* 3. Die Beschriftung über dem Wert. `attr()` und kein zweiter Text
     im Template: derselbe Satz stünde sonst zweimal da und liefe beim
     nächsten Übersetzen auseinander. */
  table.wide td[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 0.1rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--muted, #5c584f);
  }

  /* **Und sie traegt das `i` der Spalte** (b63, b76). Der Tabellenkopf
     ist hier ausgeblendet, und mit ihm war der Satz weg, der sagt, was
     in der Spalte steht -- auf dem Telefon, wo man ihn am ehesten
     braucht. static/hinweise.js schreibt die Beschriftung deshalb als
     Element und haengt den Knopf daneben; die Zelle traegt dann
     `data-wort`, und der erzeugte Inhalt tritt zurueck. Sonst stuende
     dasselbe Wort zweimal untereinander. */
  table.wide td[data-wort]::before {
    content: none;
  }

  table.wide td[data-wort] > .zelle-wort {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    margin-bottom: 0.1rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--muted, #5c584f);
  }

  /* Das Zeichen steht neben einem Wort von 0,72 rem und nicht neben
     einer Spaltenueberschrift -- in der Groesse des Kopfes waere es das
     Auffaelligste an der Karte. */
  table.wide td[data-wort] > .zelle-wort .spalte-info {
    width: 1.1rem;
    height: 1.1rem;
  }

  /* Die Knopfzelle ist selbst ein Flexkasten (siehe 4.): ihre
     Beschriftung nimmt darin die ganze Zeile, wie es das `::before`
     nebenan tut. */
  table.wide td.admin-actions[data-wort] > .zelle-wort {
    width: 100%;
  }

  /* 2. Die erste Zelle ist die Überschrift der Karte: ganze Breite,
     keine Beschriftung. */
  table.wide td:first-child {
    grid-column: 1 / -1;
    font-family: var(--font-heading, sans-serif);
    font-weight: 700;
    font-size: 1.05rem;
  }
  table.wide td:first-child[data-label]::before {
    display: none;
  }

  /* 4. Eine Zelle mit Knöpfen bleibt eine Zelle im Raster —
     Beschriftung darüber, darunter Zustand und Knopf. Linksbündig und
     nicht gespreizt: gespreizt schöbe es zwei Knöpfe an die
     gegenüberliegenden Ränder, als gehörten sie nicht zusammen. */
  table.wide td.admin-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
    gap: 0.35rem;
  }
  table.wide td.admin-actions[data-label]::before {
    width: 100%;
  }

  /* Als Karte wandert der Balken der Dringlichkeit an ihre linke
     Kante — dort, wo er auch in der Tabelle sitzt. Der Schatten an der
     ersten Zelle wäre mitten in der Karte. */
  tr.stand-hoch,
  tr.stand-mittel {
    border-left-width: 4px;
  }
  tr.stand-hoch {
    border-left-color: var(--warnung);
  }
  tr.stand-mittel {
    border-left-color: var(--achtung);
  }
  tr.stand-hoch td:first-child,
  tr.stand-mittel td:first-child {
    box-shadow: none;
  }

  /* **Die vier Handlungen tragen hier ihr Wort.** In der Tabelle sind
     sie Zeichen, weil vier Wörter 310 Punkte brauchen; in der Karte
     ist der Platz da, und vier Zeichen ohne Text wären ein Rätsel mit
     vier Feldern (Ybug 35). */
  .handeln-knopf {
    width: auto;
    height: auto;
    min-height: 2rem;
    padding: 0 0.7rem;
  }
  /* Mit Wort passen vier nicht mehr in eine Reihe — in der Karte
     dürfen sie umbrechen. */
  table.wide td.admin-handeln .handeln-reihe {
    flex-wrap: wrap;
  }
  .handeln-wort {
    display: inline;
    font-size: 0.85rem;
  }

  /* Was mehrzeilig ist, nimmt die ganze Breite: das Titelfeld (in
     einer Rasterspalte blieben kaum 100 Punkte für die Eingabe) und
     der Befund der Vorprüfung, der aus mehreren Sätzen besteht.

     **Die Vorschau gehört nicht dazu.** Sie ist ein Aufklapper von
     einem Wort Breite; über die ganze Karte gelegt riss sie das Raster
     auf, und „Gepinnt", „Ansehen" und „Prüfen" standen danach in drei
     eigenen Zeilen statt in einer Reihe. */
  table.wide td.admin-title,
  table.wide td.admin-ki {
    grid-column: 1 / -1;
  }
}

/* **Mehr Platz macht die Karte breiter, nicht länger.** Sonst wird aus
   einer Liste von Zeilen eine Liste von Listen: zehn Angaben
   untereinander, dreißigmal hintereinander. Die Spaltenzahl wächst
   deshalb mit dem Platz — zwei sind der Grundzustand, drei und vier
   kommen dazu, sobald eine Spalte über 180 Punkte breit bliebe. */
@media (min-width: 48rem) and (max-width: 72rem) {
  table.wide tr {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 60rem) and (max-width: 72rem) {
  table.wide tr {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Site brand — User Findings.txt: every page needs this top-left,
   name over claim. Plain text, not a link: this project has no single
   "home" that makes sense from every host (wir. vs. the public host),
   so it names the site rather than promising a destination. */

.logo-mark {
  display: block;
  flex-shrink: 0;
}

.site-brand-name {
  margin: 0;
  font-family: var(--font-heading, sans-serif);
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--ink, #1b1b1b);
}

.site-brand-claim {
  margin: 0;
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  color: var(--muted, #5c584f);
}

/* --- Der Beziehungswähler der Anmeldung ------------------------------
 *
 * ASCII-BEWUSST: `beziehung-feld`, `beziehung-schiene`, `beziehung-zelle`,
 * `beziehung-woerter`, `beziehung-winkel`, `ist-gewaehlt` und die
 * übrigen `beziehung-`Namen sind Klassennamen.
 *
 * **Drei Zeilen, und keine springt** (Ybug 66). Vorher wuchsen Wortzeile,
 * Zeichensuche und Motivgitter untereinander in die Seite: jeder Klick
 * verschob alles darunter, und die Vorschau wanderte aus dem Blick.
 * Jetzt hat jede Zeile eine feste Höhe und läuft seitlich weiter —
 * Zeichen, Wörter, Vorschau.
 *
 * `fieldset` und `legend`: es ist eine Gruppe aus Feldern mit einer
 * gemeinsamen Frage, und genau dafür gibt es die beiden.
 */
.beziehung-feld {
  border: none;
  padding: 0;
  margin: 0 0 1.25rem;
  max-width: 26rem;
  /* **Ein fieldset wächst von sich aus bis zu seinem Inhalt.** Seine
     Vorgabe für die Mindestbreite ist der Inhalt selbst, und damit
     sprengt eine Zeile mit zwanzig Pillen jede Breitenangabe daran — die
     Schiene läuft dann nicht seitlich, sie schiebt die ganze Seite
     auseinander. Ohne diese Null ist alles darunter Makulatur
     (gemessen, nicht vermutet). */
  min-width: 0;
}

.beziehung-legende {
  padding: 0;
  font-family: var(--font-heading, sans-serif);
  font-weight: 700;
  font-size: 1.05rem;
  margin-bottom: 0.6rem;
}

/* **Die Winkel liegen über der Zeile, sie stehen nicht daneben.** Vorher
   nahmen sie links und rechts Platz weg, und der fehlte den sechs
   Feldern — die mussten schmaler werden oder liefen aus dem Blick.
   Jetzt schwebt nur das Zeichen über dem Rand: kein Kasten, kein Grund,
   kein Rahmen. */
/* **Die Zeile ist eine Reihe: erst der Lauf, dann das Suchfeld.** Der
   Lauf trägt die Schiene und die zwei Winkel; das Feld steht dahinter
   und fällt weg, solange nicht gesucht wird. Ohne `min-width: 0`
   schiebt ein Flex-Element seinen Inhalt lieber aus der Zeile als zu
   schrumpfen. */
.beziehung-zeile {
  display: flex;
  align-items: flex-start;
  gap: 0.3rem;
  margin-bottom: 0.5rem;
}

/* **Die Winkel liegen an den Kanten des Laufs, nicht der Zeile.** Am
   Rand der Zeile stünde der rechte auf dem Suchfeld dahinter — und
   genau das war der Fehler, den drei Anläufe nicht losbekamen. Der
   Lauf endet vor dem Feld, also endet dort auch der Winkel. */
.beziehung-lauf {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
}

/* **Die Schiene läuft seitlich und bricht nicht um.** Ohne Scrollbalken:
   geschoben wird über die Winkel, und auf einem Berührschirm mit dem
   Finger. Ein sichtbarer Balken unter jeder der zwei Zeilen wäre zweimal
   Technik in einem Formular, das Trauernde ausfüllen. */
.beziehung-schiene {
  display: flex;
  align-items: flex-start;
  gap: 0.3rem;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding: 0.15rem 0;
}

.beziehung-schiene::-webkit-scrollbar {
  display: none;
}

/* **Das Schieben gleitet nicht, es springt.** Mit `scroll-behavior:
   smooth` wird jede gesetzte Position zu einer Animation — und eine
   Animation, die das Skript im selben Atemzug erneut setzt, endet
   irgendwo: das Suchfeld blieb auf halbem Weg stehen, gleich ob mit
   `behavior: auto` oder ohne (gemessen, nicht vermutet). Ein Sprung ist
   hier auch das Richtige — geschoben wird um eine Zeilenbreite, und
   dabei gibt es nichts zu verfolgen. */

/* **Die Zeichenzeile hält den Platz für den Namen in sich.** Seitliches
   Abschneiden schneidet auch senkrecht ab — der Name unter dem Feld wäre
   sonst weg. Der Platz steht immer frei, gleich ob gerade ein Name
   dasteht: so rücken die Zeilen darunter beim Überfahren nicht nach
   unten. */
.beziehung-schiene[data-beziehung-schiene="1"] {
  padding-bottom: 1.35rem;
}

/* Der Winkel: nur das Zeichen, über dem Rand der Zeile. Stumm gestellt,
   wenn nichts zu schieben ist — er verschwindet nicht, denn ein Knopf,
   der erst erscheint, verschiebt etwas. */
.beziehung-winkel {
  position: absolute;
  top: 0;
  z-index: 2;
  width: 1.8rem;
  height: 3.3rem;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* **Nur der Winkel, kein Kastenwerk.** Ein Knopf bringt von sich aus
     Rahmen, Radius und die Zeichnung des Betriebssystems mit — alles
     drei weg, sonst steht ein Rechteck über der Zeile. */
  appearance: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  color: var(--muted, #5c584f);
  cursor: pointer;
}

/* **Und ein Grund, der ausblendet statt zu decken.** Der Winkel liegt
   am Rand der Zeile, und dort läuft ein Zeichen unter ihm durch. Ein
   Verlauf in den Grund der Seite ist kein Kasten: die Zeile franst am
   Rand aus, und genau das sagt „hier geht es weiter". */
.beziehung-winkel[data-beziehung-winkel="-1"] {
  left: 0;
  background: linear-gradient(
    to right,
    var(--paper, #f6f4ef) 45%,
    transparent 100%
  );
}

.beziehung-winkel[data-beziehung-winkel="1"] {
  right: 0;
  background: linear-gradient(
    to left,
    var(--paper, #f6f4ef) 45%,
    transparent 100%
  );
}

/* Sie liegen über der Zeile und nicht daneben: draußen nahmen sie den
   Rand der Seite ein, und auf einem Telefon klebten sie am
   Schirmrand. */

/* **Jeder Winkel ist so hoch wie die Zeile, über der er liegt.** Die
   Zeichenzeile ist drei rem hoch, die Wortzeile knapp zweieinhalb — mit
   einer Höhe für beide saß der Winkel über den Pillen zu tief. */
.beziehung-winkel[data-beziehung-schiene-nr="2"] {
  height: 2.4rem;
}

.beziehung-winkel:hover {
  color: var(--accent, #2f5d62);
}

/* **Ein Winkel, der nichts zu schieben hat, steht nicht da.** Blass
   stehen zu lassen sah nach einem Fehler aus, sobald die Zeile gar
   nicht lief — und einen Sprung kostet es nicht: er liegt absolut über
   der Zeile und nimmt keinen Platz. */
.beziehung-winkel[disabled] {
  visibility: hidden;
}

/* **Alle sechs Felder stehen ohne Schieben da.** Sie teilen die Zeile
   unter sich auf, statt eine gerechnete Breite zu tragen: auf einem
   Telefon mit 320 Punkten wären sechs feste Felder eines zu viel, und
   ein Feld, das man erst heranschieben muss, findet niemand.
 *
 * `position: relative`, weil der Name darunter absolut sitzt: so kann er
 * breiter sein als das Feld, ohne die Zeile auseinanderzuschieben. */
.beziehung-zelle {
  position: relative;
  flex: 1 1 0;
  min-width: 2.4rem;
  max-width: 4rem;
  height: 3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 10px;
  background: var(--surface, #f0ede7);
  color: var(--ink, #1b1b1b);
  font: inherit;
  cursor: pointer;
}

/* **Im Suchmodus stehen die sechs Felder nicht da.** Sie standen eine
   Weile mit, damit der Weg zurück sichtbar bleibt — und haben damit
   dem Suchfeld den Platz genommen, um den sich drei Anordnungen
   gestritten haben (templates/accounts/_beziehung_picker.html). Der
   Ausgang liegt jetzt im linken Winkel, und der steht immer da
   (static/beziehung_picker.js).

   Verborgen, nicht entfernt: der Radioknopf des gewählten Bereichs
   liegt in einem der Felder und wird weiter abgeschickt. */
.beziehung-feld.zeigt-zeichenwahl .beziehung-schiene > .beziehung-zelle {
  display: none;
}

/* **Der Ausgangswinkel bekommt im Suchmodus eine eigene Spur.** Sonst
   liegt er dort dauerhaft über dem ersten Zeichen und deckt es zur
   Hälfte zu — bei zwei Treffern ist das eines von zwei (gemessen,
   nicht vermutet). Über den Zeichen zu liegen ist für einen Winkel
   richtig, solange er nur am Rand steht und dahinter etwas
   durchläuft; hier steht er ständig da, weil er der Weg zurück ist.

   Als Innenabstand der Schiene und nicht als Abstand der Gruppe: er
   liegt am Anfang des Laufs, und was darüber hinaus geschoben wird,
   zieht wie gewohnt unter dem Winkel durch. */
.beziehung-feld.zeigt-zeichenwahl .beziehung-schiene[data-beziehung-schiene="1"] {
  padding-left: 1.8rem;
}

/*
 * **Und die Gruppen tragen keine Mindestbreite.** Eine hatten sie: so
 * lag hinter zwei Treffern genug, um sie an den Anfang der Zeile zu
 * schieben. Sie war das Gegenteil einer Hilfe — in einer Zeile von 232
 * Punkten stand eine Gruppe von 288, und der leere Rest hinten drängte
 * die zwei Zeichen nach links aus dem Blick (gemessen, nicht
 * vermutet). Ohne sie ist die Gruppe so breit wie ihr Inhalt, und dann
 * gilt beides: ist sie breiter als die Zeile, lässt sich ihr Anfang an
 * den Rand schieben; ist sie schmäler, steht sie am Ende der Zeile
 * ohnehin ganz da (static/beziehung_picker.js). */

/* Enger im Suchmodus: sechs Felder, ein Suchfeld und die Treffer
   teilen sich die Zeile nicht mehr, sie reihen sich. */
.beziehung-feld.zeigt-zeichenwahl .beziehung-zelle {
  flex: 0 0 auto;
  width: 3.2rem;
}

/* Das Zeichen sitzt mittig im Feld — kein Rand, kein Versatz. Es ist
   das einzige, was in der Reihe stehen bleibt, wenn der Name verborgen
   ist, und es steht deshalb genau in der Mitte. */
.beziehung-zelle-zeichen {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.7rem;
  height: 1.7rem;
  flex: 0 0 auto;
}

.beziehung-zelle-zeichen .icon {
  display: block;
}

/* **Der Name steht mittig unter seinem Feld**, nicht links an der Zeile.
   Absolut gesetzt und ohne Zeigerfang: er darf über die Kanten des
   Feldes hinausragen, und er soll nichts abfangen, was auf das Feld
   gehört. Sichtbar ist er nur am gewählten und am überfahrenen — sonst
   stünden sechs Namen ineinander. */
.beziehung-zelle-name {
  position: absolute;
  top: calc(100% + 0.2rem);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: 0.78rem;
  line-height: 1.1;
  color: var(--muted, #5c584f);
  pointer-events: none;
  opacity: 0;
  transition: opacity 120ms ease;
}

/* Ohne Skript ist jeder Name sichtbar: dort ist er die einzige
   Beschriftung, und ein Feld mit einem Zeichen allein wäre ein Rätsel.
   Das Skript setzt `data-bereit` und übernimmt das Zeigen. */
.beziehung-feld:not([data-bereit]) .beziehung-zelle-name {
  position: static;
  transform: none;
  opacity: 1;
}

.beziehung-feld:not([data-bereit]) .beziehung-zelle {
  width: auto;
  max-width: none;
  height: auto;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.45rem 0.4rem;
}

.beziehung-zelle:hover .beziehung-zelle-name,
.beziehung-zelle:focus-within .beziehung-zelle-name,
.beziehung-zelle.ist-gewaehlt .beziehung-zelle-name {
  opacity: 1;
}

/* Der Radioknopf selbst ist unsichtbar — gezeichnet ist das Feld darum.
   `:has()` trägt in allen Browsern, die diese Seite bedient; fällt es
   aus, fehlt nur die Hervorhebung des Gewählten, und die Auswahl selbst
   bleibt bedienbar. */
/* **Trägt das sechste Feld ein eigenes Zeichen, ist es das gewählte.**
   Der Bereich bleibt darunter gewählt — er ordnet die Nutzertabelle —,
   aber sein Rahmen zeigte auf ein Zeichen, das gar nicht mehr erscheint.
   Diese Regel wiegt eine Klasse mehr als die darunter und nimmt ihn
   deshalb zurück. */
.beziehung-feld.eigen-zeichen label.beziehung-zelle:has(> input:checked) {
  border-color: var(--line, #d9d9d9);
  color: var(--ink, #1b1b1b);
  box-shadow: none;
}

.beziehung-zelle:has(> input:checked),
.beziehung-zelle.ist-gewaehlt {
  border-color: var(--accent, #2f5d62);
  color: var(--accent, #2f5d62);
  box-shadow: inset 0 0 0 1px var(--accent, #2f5d62);
}

.beziehung-zelle:has(> input:focus-visible),
.beziehung-zelle:focus-visible {
  outline: 3px solid var(--accent, #2f5d62);
  outline-offset: 2px;
}

/* **Das Plus und das Motiv liegen übereinander** und blenden sich ab.
   Zwei Ebenen an derselben Stelle, keine Bewegung des Feldes: der
   Wechsel soll auffallen wie ein Atemzug und nicht wie ein Karussell. */
.beziehung-wechsel {
  position: absolute;
  inset: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: opacity 700ms ease, transform 700ms ease;
}

.beziehung-wechsel-motiv {
  opacity: 0;
  transform: translateY(0.35rem);
}

.beziehung-eigenes.zeigt-motiv .beziehung-wechsel-motiv {
  opacity: 1;
  transform: none;
}

.beziehung-eigenes.zeigt-motiv [data-beziehung-wechsel-plus] {
  opacity: 0;
  transform: translateY(-0.35rem);
}

/* Wer Bewegung abbestellt hat, sieht nur das Plus. */
@media (prefers-reduced-motion: reduce) {
  .beziehung-wechsel {
    transition: none;
  }
  .beziehung-wechsel-motiv {
    display: none;
  }
  .beziehung-eigenes.zeigt-motiv [data-beziehung-wechsel-plus] {
    opacity: 1;
    transform: none;
  }
}

/* Das Suchfeld sitzt in derselben Zeile und in derselben Höhe wie die
   Felder daneben — es ist eine Zelle unter Zellen, nur eine breite.
   Die Lupe liegt darin am rechten Rand. */
/* **Der Ausgang aus der Suche.** Ein Knopf wie die Winkel gezeichnet,
   aber kein Winkel: er liegt nicht über der Zeile, sondern in ihr, und
   nimmt seinen Platz. Der Grund steht im Template — was dauerhaft
   dasteht, darf nichts dauerhaft zudecken. */
.beziehung-ausgang {
  flex: 0 0 auto;
  width: 1.8rem;
  height: 3rem;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  appearance: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  background: none;
  color: var(--muted, #5c584f);
  cursor: pointer;
}

.beziehung-ausgang:hover {
  color: var(--accent, #2f5d62);
}

/* **Das Suchfeld steht fest, weil es nicht mitläuft** — und es steht
   vor dem Lauf, denn im Suchmodus ist es der Anfang der Zeile. Drei
   Anordnungen davor sind im Template begründet
   (templates/accounts/_beziehung_picker.html).
 *
 * `position: relative` — die Lupe darin sitzt absolut. */
.beziehung-suchzelle {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  height: 3rem;
}

/* **Die Hausregel für Eingabefelder wiegt schwerer, als sie aussieht.**
   Sie setzt Breite, Rahmen und Radius für jedes Feld, das kein Häkchen
   und kein Radioknopf ist — und schließt beide über zwei Verneinungen
   aus, die zusammen so viel wiegen wie zwei Klassen. Sie steht weiter
   unten im Blatt, also gewinnt sie bei gleichem Gewicht. Deshalb steht
   hier ein Merkmalwähler dazu: er gibt das Gewicht, das nötig ist, und
   keines mehr (gemessen, nicht vermutet).

   Die Regel selbst nicht abschreiben — ein Test sucht ihre erste
   Fundstelle im Blatt, und ein Kommentar wäre dann die falsche. */
/* Innen bleibt nur der Platz für die Lupe. Links steht kein Winkel
   mehr im Feld — er hat seine eigene Spur davor. */
.beziehung-feld .beziehung-suchzelle input[type="search"] {
  width: 9rem;
  height: 2.4rem;
  padding: 0 1.9rem 0 0.6rem;
  font-size: 0.9rem;
}

.beziehung-lupe {
  position: absolute;
  right: 0.15rem;
  width: 1.5rem;
  height: 2.2rem;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: var(--muted, #5c584f);
  cursor: pointer;
}

.beziehung-lupe:hover {
  color: var(--accent, #2f5d62);
}

/* **Sie halten ihre volle Breite.** Als Flex-Element schrumpft eine
   Gruppe von sich aus auf den Platz, der übrig ist — die zwanzig Motive
   lagen dann übereinandergeschoben in einer Gruppe von 100 Punkten, und
   die Zeile ließ sich nicht bis zu ihnen schieben, weil sie gar nicht so
   lang war (gemessen, nicht vermutet). */
.beziehung-motive,
.beziehung-treffer {
  display: inline-flex;
  flex: 0 0 auto;
  gap: 0.3rem;
}

/* --- Die Wortzeile ---------------------------------------------------
 *
 * Pillen in einer Zeile, „Deine Eingabe" zuerst. Sie sind niedriger als
 * die Zeichenfelder: es sind Wörter, keine Bilder. */
/* Die Wortzeile hält ihre Höhe, auch wenn noch nichts gewählt ist:
   sonst rückte die Vorschau beim ersten Griff nach unten. Statt einer
   Leere steht dort der Satz, was zu tun ist. */
.beziehung-woerter {
  align-items: center;
  min-height: 2.4rem;
}

.beziehung-wortleer {
  flex: 0 0 auto;
  font-size: 0.88rem;
  color: var(--muted, #5c584f);
}

/* **Alle Pillen sind gleich hoch, auch die mit dem Feld darin.** Ohne
   feste Höhe ist die eine mit Eingabefeld um zwei Punkte höher, und
   die Zeile hüpft beim Aufmachen — genau das, was die drei Zeilen
   verhindern sollen. */
.beziehung-wortknopf {
  flex: 0 0 auto;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  padding: 0 0.7rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  background: var(--surface, #f0ede7);
  color: var(--ink, #1b1b1b);
  font: inherit;
  font-size: 0.88rem;
  white-space: nowrap;
  cursor: pointer;
}

.beziehung-wortknopf:hover,
.beziehung-wortknopf:focus-visible {
  border-color: var(--accent, #2f5d62);
  color: var(--accent, #2f5d62);
}

.beziehung-wortknopf.ist-gewaehlt {
  border-color: var(--accent, #2f5d62);
  color: var(--accent, #2f5d62);
  box-shadow: inset 0 0 0 1px var(--accent, #2f5d62);
}

/* **„Deine Eingabe" ist die Pille, die sich öffnet.** Sie steht zuerst
   und trägt gestrichelt: sie ist kein Wort, sondern ein Weg zu einem.
   Das Eingabefeld liegt darin und ist dasselbe, das ohne Skript unter
   der Zeile steht — deshalb bekommt es hier nur die Form der Pille und
   keinen eigenen Rahmen. */
.beziehung-wortknopf-eigen {
  border-style: dashed;
  color: var(--muted, #5c584f);
}

.beziehung-wortknopf-eigen.ist-offen {
  border-style: solid;
  color: var(--ink, #1b1b1b);
}

.beziehung-feld .beziehung-wortknopf-eigen input[type="text"] {
  width: 9rem;
  min-width: 0;
  height: 100%;
  margin: 0 -0.7rem;
  padding: 0 0.7rem;
  border: none;
  border-radius: 999px;
  background: none;
  color: var(--ink, #1b1b1b);
  font: inherit;
  font-size: 0.88rem;
}

/* Kein zweiter Rahmen im Rahmen — die Pille selbst zeigt den Fokus, und
   das Kreuz, das ein Suchfeld mitbringt, hat hier nichts zu tun. */
.beziehung-feld .beziehung-wortknopf-eigen input[type="text"]:focus {
  outline: none;
  box-shadow: none;
}

.beziehung-wortknopf-eigen:focus-within {
  border-style: solid;
  border-color: var(--accent, #2f5d62);
  box-shadow: inset 0 0 0 1px var(--accent, #2f5d62);
}

/* Ohne Skript steht das Textfeld für sich unter den Zeilen. Mit Skript
   wandert es in die Pille, und diese Hülle wird leer und verborgen. */
.beziehung-eigenwort {
  max-width: 26rem;
  margin-top: 0.5rem;
}

.beziehung-treffer-knopf {
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 8px;
  background: var(--surface, #f0ede7);
  color: var(--ink, #1b1b1b);
  cursor: pointer;
}

.beziehung-treffer-knopf:hover,
.beziehung-treffer-knopf:focus-visible {
  border-color: var(--accent, #2f5d62);
  color: var(--accent, #2f5d62);
}

/* **Ein gedrückter Absendeknopf sieht auch so aus** (Ybug 66,
   static/hinweise.js). Gesperrt ist er, damit ein zweiter Klick nicht
   einen zweiten Anmeldelink auslöst; ohne ein Zeichen dafür sähe es aus,
   als täte der erste nichts. Der Wartezeiger sagt „gleich", die
   Deckkraft „nicht mehr Deine Aufgabe". */
button[data-laeuft] {
  opacity: 0.6;
  cursor: progress;
}

/* --- Die Schrittleiste der Anmeldung ---------------------------------
 *
 * ASCII-BEWUSST: `schritte`, `schritt`, `schritt-punkt`,
 * `schritt-inhalt` und `schritt-titel` sind Klassennamen.
 *
 * **Alle Punkte von Anfang an, senkrecht, mit der Linie dazwischen**
 * (Ybug 66). Das ist der Sinn einer solchen Leiste: sie sagt, wie viel
 * noch kommt. „Nur der aktive Punkt" wäre ein Fortschrittsbalken, und
 * „wachsen lassen" nähme ihr genau diese Auskunft.
 *
 * **Sie zerlegt das Formular nicht in Seiten.** Alles steht auf einer;
 * die Leiste ist ein Umriss daneben. Erledigte tragen einen Haken, der
 * erreichte einen kräftigen Rand (static/schritte.js).
 *
 * Die Nummern zeichnet ein Zähler — dann stehen sie auch ohne Skript
 * richtig, und niemand pflegt sie von Hand.
 */
.schritte {
  counter-reset: schritt;
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 28rem;
}

.schritt {
  counter-increment: schritt;
  display: grid;
  /* Der Punkt ist so breit wie hoch; die Spalte daneben nimmt den Rest
     und darf schmal werden — `minmax(0, 1fr)` statt `1fr`, sonst
     sprengt eine lange Zeile darin die Spalte auf. */
  grid-template-columns: 1.6rem minmax(0, 1fr);
  gap: 0 0.8rem;
  position: relative;
  padding-bottom: 1.4rem;
}

.schritt:last-child {
  padding-bottom: 0;
}

/* **Die Linie hängt am Punkt und nicht am Eintrag.** Sie läuft von
   seiner Unterkante bis zum nächsten Punkt; beim letzten fehlt sie, denn
   danach kommt nichts. */
.schritt-punkt {
  grid-column: 1;
  width: 1.6rem;
  height: 1.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 50%;
  background: var(--surface, #f0ede7);
  color: var(--muted, #5c584f);
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1;
}

.schritt-punkt::before {
  content: counter(schritt);
}

.schritt:not(:last-child) .schritt-punkt::after {
  content: "";
  position: absolute;
  left: 0.8rem;
  top: 1.6rem;
  bottom: 0;
  width: 1px;
  background: var(--line, #d9d9d9);
}

.schritt-inhalt {
  grid-column: 2;
  min-width: 0;
}

/* Die Überschrift eines Punktes steht in der Größe des Textes und nicht
   in der einer Seitenüberschrift: sie beschriftet zwei Felder, sie
   kündigt keinen Abschnitt an. */
.schritt-titel {
  font-family: var(--font-heading, sans-serif);
  font-size: 0.95rem;
  font-weight: 700;
  margin: 0.15rem 0 0.4rem;
}

/* **Erledigt trägt einen Haken statt der Nummer.** Die Nummer hat ihre
   Aufgabe getan — sie sagte, an welcher Stelle man ist; der Haken sagt,
   dass die Stelle steht. */
.schritt[data-stand="erledigt"] .schritt-punkt {
  border-color: var(--accent, #2f5d62);
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #ffffff);
}

.schritt[data-stand="erledigt"] .schritt-punkt::before {
  content: "✓";
}

.schritt[data-stand="aktiv"] .schritt-punkt {
  border-color: var(--accent, #2f5d62);
  color: var(--accent, #2f5d62);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #2f5d62) 18%, transparent);
}

/* Offen bleibt blass — er ist noch nicht dran, und er soll den Blick
   nicht vom erreichten wegziehen. */
.schritt[data-stand="offen"] .schritt-punkt {
  opacity: 0.55;
}

/* **Auf dem Telefon rückt die Leiste zusammen.** Sie nimmt dort sonst
   knapp zweieinhalb rem von dreiundzwanzig, und die fehlen der Zeile
   mit den sechs Zeichen. Kleiner, aber immer noch ein Punkt mit einer
   Zahl darin. */
@media (max-width: 30rem) {
  .schritt {
    grid-template-columns: 1.3rem minmax(0, 1fr);
    gap: 0 0.5rem;
    padding-bottom: 1.1rem;
  }

  .schritt-punkt {
    width: 1.3rem;
    height: 1.3rem;
    font-size: 0.72rem;
  }

  .schritt:not(:last-child) .schritt-punkt::after {
    left: 0.65rem;
    top: 1.3rem;
  }
}

/* --- Zwei halbe Felder in einer Zeile --------------------------------
 *
 * Vorname und Nachname (Ybug 66). Zwei volle Felder untereinander
 * schoben die Frage nach der Beziehung und die Vorschau aus dem ersten
 * Blick, und ein Nachname braucht keine ganze Zeile. Umbrechend: auf
 * einem schmalen Schirm sind zwei halbe Felder zwei zu enge. */
.feldpaar {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.6rem;
  max-width: 26rem;
}

.feldpaar .field {
  flex: 1 1 8rem;
  min-width: 0;
}

/* --- Die Beziehungszelle der Nutzertabelle ---------------------------
 *
 * ASCII-BEWUSST: `beziehung-tabellenzelle`, `beziehung-wort` und
 * `beziehung-suchfeld` sind Klassennamen.
 *
 * **Drei Angaben in einer Zelle** (Ybug 65): Kategorie, eigenes Wort
 * und Zeichen. Sie stehen untereinander und nicht nebeneinander — in
 * zwölf Prozent Tabellenbreite ist für drei Felder in einer Reihe kein
 * Platz, und eine Zelle, die dreimal umbricht, ist unleserlicher als
 * eine, die drei Zeilen hat.
 */
.beziehung-tabellenzelle {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.3rem;
}

/* Das Zeichen steht über der Auswahl, mittig zur Zeile: es ist die
   Zusammenfassung der drei Angaben darunter. */
.beziehung-tabellenzelle .life-area-mark {
  min-height: 1.2rem;
}

.beziehung-tabellenzelle select,
.beziehung-tabellenzelle .beziehung-wort,
.beziehung-tabellenzelle .beziehung-suchfeld {
  width: 100%;
  padding: 0.2rem 0.35rem;
  font-size: 0.85rem;
}

/* Die Treffer stehen dicht: in einer Tabellenzelle zählt jede Zeile. */
.beziehung-tabellenzelle .beziehung-treffer {
  gap: 0.2rem;
  margin-top: 0;
}

.beziehung-tabellenzelle .beziehung-treffer-knopf {
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 6px;
}

/* **Die Vorschau sieht aus wie das, was sie zeigt.** Sie steht auf dem
   Grund der Seite und in der Größe der Verfasserzeile unter einem
   Beitrag — eine Vorschau in anderer Schrift ist keine. */
.beziehung-vorschau {
  max-width: 26rem;
  margin: 0.35rem 0 0;
  padding: 0.6rem 0.75rem;
  border: 1px dashed var(--line, #d9d9d9);
  border-radius: 8px;
  color: var(--muted, #5c584f);
  min-height: 2.6rem;
  display: flex;
  align-items: center;
}

/* **Name, Zeichen und Wort stehen auf einer Mittellinie.** Die drei
   haben verschiedene Größen — der Name fett, das Wort klein, das
   Zeichen quadratisch —, und an der Schriftlinie ausgerichtet hing das
   Zeichen tiefer als beides. Eine Reihe, in der eines von drei Teilen
   heraussteht, liest sich als Fehler.

   Nur hier und nicht an der Marke selbst: dieselbe Klasse steht unter
   jedem echten Beitrag, wo sie mitten im Satz sitzt und dort richtig an
   der Schriftlinie hängt. */
.beziehung-vorschau small {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}

.beziehung-vorschau .life-area-mark {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}

.beziehung-vorschau .life-area-wort {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Der Satz darüber sagt in Worten, was die Vorschau in Form zeigt — und
   ist damit zugleich das, was ein Screenreader statt der Vorschau
   bekommt (die ist `aria-hidden`). */
.beziehung-vorschau-hinweis {
  max-width: 26rem;
  margin: 1rem 0 0;
  font-size: 0.85rem;
  color: var(--muted, #5c584f);
}

/* Solange kein Vorname getippt ist, steht dort „Dein Vorname" — blass,
   damit es als Lücke und nicht als Name gelesen wird. */
.beziehung-platzhalter {
  font-weight: 400;
  opacity: 0.65;
}

form .field { margin-bottom: 1.25rem; }
label { display: block; font-weight: 600; margin-bottom: 0.25rem; }
/* Icons: Lucide-Striche aus static/icons.json ueber den {% icon %}-Tag
   (config/icons.py), kein Emoji. Sie tragen keine eigene Farbe —
   `currentColor` im Rumpf nimmt die Textfarbe des Elements daneben, also
   die des Themes in Hell wie in Dunkel. "monochrom, gedeckt, kein bunter
   Farbcode", SPEC.md Abschnitt 5. */
.icon {
  display: inline-block;
  vertical-align: -0.125em;
  flex-shrink: 0;
}

.field-hint {
  margin: 0.35rem 0 0;
  font-size: 0.85rem;
  color: var(--muted, #5c584f);
}

/* **Luft zwischen dem Hinweis und dem Knopf darunter** (Ybug 178). Der
   Hinweis gehört zum Feld darüber und trägt deshalb keinen Abstand nach
   unten; folgt ein Knopf, klebte der daran und las sich wie die dritte
   Zeile des Satzes. Der Nachbarselektor trifft genau diesen Fall und
   lässt jeden anderen Hinweis, wie er ist.

   Nur `button`: ein Knopf hinter einem Hinweis ist immer einer, und ein
   zweiter Selektor mit dem Klassennamen darin wäre die Stelle, die die
   Knopfkonvention sucht (config/tests_knoepfe.py). */
.field-hint + button {
  margin-top: 0.9rem;
}
/* Fehler am Feld. Nicht ueber Farbe getragen — die Themes bringen kein
   geprueftes Rot mit, und WCAG 2.2 verlangt ohnehin ein zweites Merkmal:
   fetter Schnitt plus Balken am Rand, in der Ink-Farbe, die in jedem
   Theme gegen Paper gerechnet ist. */
.field-error {
  margin: 0.35rem 0 0;
  padding-left: 0.6rem;
  border-left: 3px solid var(--ink, #2c2a26);
  font-weight: 600;
  color: var(--ink, #2c2a26);
}
/* **Nicht jedes `input` ist ein Feld.** Ein Kaestchen und ein Radioknopf
   zeichnet der Browser selbst, in einer Groesse, die zu seiner Schrift
   passt; Breite, Polsterung und Rahmen von hier sind darauf nicht
   gemuenzt. Ohne den Ausschluss wurde die Veroeffentlicht-Checkbox in
   den Einstellungen 343 Punkte breit und 13 hoch — ein unsichtbares Feld
   ueber die ganze Zeile, das seine Beschriftung in die naechste drueckte.
   Gemessen am 2026-09-06. */
input:not([type="checkbox"]):not([type="radio"]),
textarea,
select {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 4px;
  font: inherit;
}

input[type="checkbox"],
input[type="radio"] {
  width: auto;
  margin: 0;
  cursor: pointer;
}

/* Kaestchen und Beschriftung nebeneinander. `:has()` traegt in allen
   Browsern, die diese Seite bedient; faellt es aus, stehen beide immer
   noch nebeneinander — nur die Ausrichtung fehlt dann.

   **`flex-start` und nicht `center`** (Ybug 61). Ein Kästchen mit
   einem Wort daneben sieht mittig richtig aus; eines mit einem ganzen
   Satz, der über zwei Zeilen läuft, hängt dann in der Mitte des
   Absatzes statt bei dem Wort, zu dem es gehört. Der kleine Versatz am
   Kästchen holt es zurück auf die erste Zeile — ohne ihn stünde es an
   deren Oberkante und damit einen Hauch zu hoch.

   **Ein Satz gehört in eine Hülle.** Jedes Kind dieser Zeile ist ein
   Feld darin, und ein nackter Textknoten neben einem Link ergibt
   mehrere: „Ich habe die", „Nutzungsbedingungen", „gelesen und bin
   einverstanden." standen als drei Spalten nebeneinander. `.feld-satz`
   fasst den Satz zu einem Feld zusammen. */
.field label:has(> input[type="checkbox"]),
.field label:has(> input[type="radio"]) {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  cursor: pointer;
}

.field label:has(> input[type="checkbox"]) > input,
.field label:has(> input[type="radio"]) > input {
  margin-top: 0.2em;
}

/* Der Satz an einem Kästchen ist Fließtext und keine Feldbeschriftung.
   Ohne diese Zeile trüge er den fetten Schnitt von `label` — eine
   Einverständniserklärung in Fettschrift liest sich wie eine
   Anweisung. */
.feld-satz {
  font-weight: 400;
}
/* --- DIE KONVENTION FÜR AKTIONSKNÖPFE --------------------------------
 *
 * ASCII-BEWUSST: `knopf-haupt`, `knopf-gefahr`, `knopf-reihe` und die
 * `--knopf-`-Marken sind Bezeichner.
 *
 * **Das hier ist die eine Stelle** (b79). Sie sammelt elf Befunde, und
 * alle elf hatten denselben Grund: es gab keine Konvention, sondern
 * dreizehn Formulare, die jedes für sich entschieden, wie ein Knopf
 * aussieht. „Senden" trug 4 Punkte Rundung und „Anmelden" 999 (b30),
 * „Abbrechen" war im Editor gefüllt wie eine Bestätigung (b53), ein
 * Übernehmen-Knopf trug seine Betonung nicht (b11), zwei Blätter hatten
 * überhaupt kein Übernehmen (b12, b13). Wer das in dreizehn Dateien
 * richtet, richtet es beim nächsten Formular wieder.
 *
 * **Wer die Konvention ändert, ändert diesen Block und sonst nichts.**
 * Die Marken darunter tragen die Maße, die drei Rollenklassen die
 * Bedeutung. Kein Knopf im Haus setzt Polster, Rundung oder Farbe
 * selbst; wo doch, ist es ein Fehler und kein Sonderfall.
 *
 * DREI ROLLEN, UND NICHT MEHR
 *
 *   (ohne Klasse)    **Der leise Knopf.** Nur eine Kante auf dem Grund
 *                    des Hauses. Das ist die Grundform, weil sie der
 *                    häufigste Fall ist: Abbrechen, Schließen, Zurück,
 *                    jeder Knopf in einer Reihe von Gleichrangigen.
 *   `.knopf-haupt`   **Die Tat, um derer willen das Formular dasteht.**
 *                    Volle Fläche in der Akzentfarbe. Höchstens einer je
 *                    Formular und je Menü — zwei Hauptknöpfe sind zwei
 *                    Absichten, und dann fehlt die Entscheidung.
 *   `.knopf-gefahr`  **Was sich nicht zurücknehmen lässt.** Kante und
 *                    Schrift in der Warnfarbe, keine Fläche: er soll
 *                    erkennbar sein und nicht einladend. Er trägt immer
 *                    eine Rückfrage (`data-rueckfrage`).
 *
 * **Die Grundform war bis zum 2026-09-13 die gefüllte**, und daran hing
 * die halbe Unordnung: ein Knopf, der nichts von sich sagt, sah aus wie
 * die Hauptsache, und jeder zweite Knopf musste sich gegen seine eigene
 * Vorgabe wehren. Gemessen im Editor: „Abbrechen" und „Übernehmen"
 * hatten denselben Grund, dieselbe Schrift, dieselbe Rundung — die
 * Klasse `primary` daneben setzte nur noch einmal, was ohnehin galt.
 *
 * **Nicht jeder Knopf ist ein Aktionsknopf.** Ein Wähler ist keiner: das
 * Zeichen der Beziehung (`.beziehung-zelle`) und die Zielgruppe stehen
 * für einen Wert, den jemand aussucht, nicht für eine Tat — sie tragen
 * ihre eigene Form und fallen nicht unter diese Regeln. Dasselbe gilt
 * für die Stufen einer Skala (`.skala-stufe`, config/skalen.py), die
 * Menüeinträge (`.menue-option`) und die Zeichenknöpfe der Führung
 * (`.fuehrung-glied`): sie sind Formen mit eigener Zusage.
 *
 * EINE REIHE, ZWEI KNÖPFE
 * Der Ausgang links, die Tat rechts — dieselbe Ordnung wie in jeder
 * Rückfrage des Hauses. Beide gleich breit: zwei verschieden breite
 * Knöpfe lesen sich als zwei verschieden wichtige Dinge, und sie sind
 * die beiden Ausgänge desselben Formulars (`.knopf-reihe`).
 *
 * UND MANCHMAL NUR EINER
 * Nicht jedes Formular sammelt. Manche lösen beim Anklicken schon aus:
 * der Grund des Beitrags wechselt, sobald eine Farbe angetippt ist, und
 * die Datei ist genommen, sobald sie gewählt ist. Dann steht ein Knopf
 * da, er nimmt die halbe Breite und bleibt links — und **wie er heißt,
 * sagt die Lage:**
 *
 *   „Abbrechen"  solange nichts geschehen ist. Das Blatt geht zu, und
 *                nichts ist anders als vorher (der Dateiwähler).
 *   „Schließen"  wenn es schon geschehen ist. Die Farbe steht bereits;
 *                „Abbrechen" verspräche einen Rückweg, den es nicht
 *                gibt (der Grund des Beitrags).
 *
 * Das war b12 und b13 — zwei Blätter „ohne Übernehmen". Sie brauchen
 * keines: das Übernehmen ist der Klick auf die Sache selbst, und ein
 * zweiter Weg zu derselben Wirkung wäre einer zu viel. Was fehlte, war
 * die Regel, nach der man das entscheidet.
 */
:root {
  --knopf-radius: 999px;
  --knopf-polster: 0.6rem 1.2rem;
  --knopf-gewicht: 600;
  --knopf-abstand: 0.5rem;
}

button, .button {
  padding: var(--knopf-polster);
  border: 1px solid var(--line, #d9d9d9);
  border-radius: var(--knopf-radius);
  background: none;
  color: var(--ink, #1b1b1b);
  font: inherit;
  font-weight: var(--knopf-gewicht);
  cursor: pointer;
}

button:hover,
.button:hover {
  border-color: var(--accent, #2f5d62);
}

/* **Ein Link in Knopfform trägt keinen Unterstrich** (Ybug 192). Der
   Weg heraus aus der Vollansicht ist ein Link — er führt zurück in die
   Liste, und das ist ein Weg und keine Handlung —, sieht aber aus wie
   der Knopf im Fenster daneben. Die Linkfarbe und die Linie darunter
   wären die Reste der anderen Form. */
a.button {
  display: inline-block;
  color: var(--ink, #1b1b1b);
  text-decoration: none;
}

/* **Ein gesperrter Knopf sieht gesperrt aus** (b33). Die Regel stand
   nur an der Knopfreihe der Blaetter; ein Knopf, der allein unter einem
   Formular steht, blieb in voller Farbe stehen, obwohl er nichts tat —
   beim Senden einer Nachricht ohne gewaehlten Empfaenger war das der
   Fall (`data-braucht-wahl`, static/hinweise.js).

   Deckkraft und kein Grau: die Farbe sagt weiter, welche Rolle der
   Knopf hat, und der Zeiger sagt das Uebrige. Fuer die Tastatur und
   das Vorleseprogramm sagt es `disabled` selbst. */
button:disabled,
button:disabled:hover {
  opacity: 0.45;
  border-color: var(--line, #d9d9d9);
  cursor: not-allowed;
}

.knopf-haupt:disabled:hover {
  border-color: var(--accent, #2f5d62);
}

.knopf-haupt {
  background: var(--accent, #2f5d62);
  border-color: var(--accent, #2f5d62);
  /* Nicht "white" fest — der Kontrastpartner des Akzents ist je Theme
     verschieden; einige Helligkeiten brauchen dunklen Text auf hellem
     Akzent, keinen weissen auf dunklem. */
  color: var(--accent-ink, #ffffff);
}

.knopf-haupt:hover {
  border-color: var(--accent, #2f5d62);
  opacity: 0.92;
}

.knopf-gefahr {
  border-color: var(--warnung, #a3271c);
  color: var(--warnung, #a3271c);
}

.knopf-gefahr:hover {
  border-color: var(--warnung, #a3271c);
  background: color-mix(in srgb, var(--warnung, #a3271c) 8%, transparent);
}

.knopf-reihe {
  display: flex;
  justify-content: space-between;
  gap: var(--knopf-abstand);
}

/* Jeder nimmt seine Hälfte, die Schrift steht mittig darin. Halb und
   halb heißt auch: das Ziel ist groß genug für einen Daumen, ohne dass
   es gesagt werden müsste. Steht nur einer da, nimmt er die halbe
   Breite und bleibt links — der Ausgang wandert nicht, je nachdem, ob
   es daneben etwas zu übernehmen gibt. */
.knopf-reihe > button,
.knopf-reihe > .button {
  flex: 1 1 0;
  max-width: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}

/* Ein Knopf, der wie ein Link aussieht. Gebraucht, wo eine Handlung den
   Bestand aendert und deshalb ein POST-Formular braucht (Melden), aber
   neben echten Links steht und nicht wie ein Hauptknopf wirken soll.
   Traegt bewusst dieselben Merkmale wie a: fetter Schnitt statt Farbe,
   Unterstrich erst bei Hover/Fokus. */
.link-button {
  padding: 0;
  background: none;
  border: none;
  color: var(--accent, #2f5d62);
  font: inherit;
  font-weight: 600;
  text-decoration: none;
}

/* Denselben Farbzug wie ein echter Link, aus demselben Grund: keine
   Linie, auch nicht beim Hovern (Ybug 2). Der Fokusring kommt oben aus
   der gemeinsamen Regel für `button`. */
.link-button:hover {
  color: var(--muted, #5c584f);
  color: color-mix(in srgb, var(--accent, #2f5d62) 55%, var(--muted, #5c584f));
}

/* Einstellungsleiste: jederzeit erreichbar, aber unaufdringlich —
   trauma-informiertes Design, wenige Entscheidungen sichtbar auf einmal. */
.settings-bar {
  position: fixed;
  left: 0.75rem;
  /* Über dem Wort im Fuß und nicht darauf (b54, `--fuss-hoehe`). */
  bottom: calc(0.75rem + var(--fuss-hoehe));
  z-index: 20;
}

/* **Er trägt eine Fläche und ist nicht durchsichtig** (Ybug 208). Er
   hatte nur eine Kante, und über dem hellen Grund einer Gedenkseite
   fiel das nicht auf. Im Editor steht er auf der schwarzen
   Arbeitsfläche: dort sah man den Grund durch den Knopf hindurch, und
   ein Kreis aus einer dünnen Linie las sich wie ein Rest und nicht wie
   ein Knopf.

   Dieselben Werte wie am Auslöser des Stapels gegenüber
   (`.fab-toggle`) — die beiden stehen auf jeder Seite an denselben
   zwei Ecken und waren bis dahin unterschiedlich gebaut. */
.settings-toggle {
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border-radius: 999px;
  background: var(--paper, #fff);
  color: var(--ink, #1b1b1b);
  border: 1px solid var(--line, #d9d9d9);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1);
  font-size: 0.7rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* **Aufgeklappt kehrt er die Farben um** (Ybug 214) — wie jeder andere
   Rundknopf im Haus (`.fab[open] .fab-toggle`, `.editor-menu-fab.open`).
   Er war der einzige, der es nicht tat: sein Menü stand offen darüber
   und der Knopf sah aus wie im Ruhezustand.

   Am `aria-expanded` und nicht an einer eigenen Klasse: static/settings.js
   setzt es ohnehin, und ein zweiter Zustand für dieselbe Sache liefe
   irgendwann auseinander. */
.settings-toggle[aria-expanded="true"] {
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
  border-color: var(--accent, #2f5d62);
}

/* **Kein Kasten mehr um die Leiste.** Sie ist seit dem 2026-09-07 eine
   Reihe von Menüeinträgen wie jedes andere Menü im Haus (Ybug 34, 41);
   die Einträge tragen ihren eigenen Rahmen, und ein Kasten darum wäre
   ein Rahmen um Rahmen. Was hier bleibt, ist die Position: über dem
   Knopf, nach oben gestapelt, weil er unten links sitzt. */
.settings-panel {
  position: absolute;
  bottom: 3.25rem;
  left: 0;
}

/* Der Farbpunkt einer Theme-Option. **Die Farben stehen nicht hier**:
   das Element trägt `data-theme-probe`, und static/themes.css gibt ihm
   damit dieselben Werte, die die ganze Seite unter diesem Theme
   bekäme. Eine zweite Liste mit fünf Hexwerten liefe irgendwann
   auseinander. */
.theme-punkt {
  flex: 0 0 auto;
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 999px;
  background: var(--accent, #2f5d62);
  border: 1px solid var(--line, #d9d9d9);
}

/* Das Kürzel einer Sprachoption. Für eine Sprache gibt es kein
   Zeichen — eine Flagge benennt ein Land —, also steht hier das
   Kürzel und sonst nichts. */
.sprach-marke {
  flex: 0 0 auto;
  width: 1.1rem;
  text-align: center;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* Fehlerseiten (500.html u.ae.): der einladende Teil ist immer sichtbar,
   das Technische liegt hinter einem bewusst unauffaelligen Aufklapper —
   niemand in einem Trauermoment soll sich durch eine Fehlermeldung
   lesen muessen, die er nicht angefordert hat. */
.error-details {
  margin-top: 1.5rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 8px;
  padding: 0.5rem 0.75rem;
  background: var(--surface, #f5f5f5);
}

.error-details summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--muted, #5c584f);
}

.error-details p {
  margin: 0.5rem 0 0;
  font-size: 0.85rem;
  color: var(--muted, #5c584f);
}

/* Visually hidden but reachable by screen readers — used for the text
   half of an icon-only display (SPEC.md: Lebensbereich-Icons, Beitrags-
   Typ-Icons "visuell nur Icon, kein Text daneben, aber barrierefrei
   über verstecktes Text-Label"). The 1px-clip-rect technique, not
   display:none, so it still reaches the accessibility tree. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* **Auf dem Feed werden sie nicht mehr ausgeblendet.** Sie stehen seit
 * dem Umbau auf den stehenden Rahmen in der Kopfzeile, nicht im Fuss —
 * und die Kopfzeile steht auf dem Feed ohnehin. Sie kosten dort also
 * keine Beitragshoehe, sind ohne Scrollen erreichbar und erfuellen
 * damit "staendig verfuegbar" besser als jede Leiste im Inhalt.
 *
 * Die Ausblendung stammte aus der Zeit, als der Fuss im Fluss unter dem
 * Feed lag und ihm Hoehe nahm. Sie hat den Umbau ueberlebt und wurde
 * dabei zur Falle: die Leiste unter dem Feed, auf die sie verwies,
 * verschwand im Scrollbereich unter dem zweiten Beitrag — gemessen am
 * 2026-09-06, ein Klick auf "Impressum" traf den Beitrag. Beide Wege
 * zugleich zu, und das an den Pflichtlinks. */

/* Der Hinweis auf die Sprache der Beiträge in der Textliste. Er steht
 * nur da, wenn die Oberfläche nicht deutsch ist — und dann leiser als
 * der Text daneben, weil er eine Auskunft ist und kein Weg. Das
 * Gegenstück im Feed heißt `.feed-note` und steht weiter oben. */
.reading-note {
  margin: 0 0 1rem;
  max-width: 32rem;
  font-size: 0.8rem;
  color: var(--muted, #5c584f);
}

/* Die Startseite. Schmal gesetzt und ruhig: sie sagt einen Satz und
 * bietet einen Weg — und keinen zweiten. */
.landing {
  max-width: 32rem;
}
.landing-lead {
  max-width: 28rem;
}
/* Die Überschrift über dem Kontaktformular. Sie steht mit Abstand
 * darüber, weil unter dem Satz davor ein Themenwechsel liegt und keine
 * Fortsetzung — und leiser als eine gewöhnliche `h2`, damit sie neben
 * der Adresse in der Überschrift nicht als zweite Ansage auftritt. */
.landing-kontakt-titel {
  margin: 2rem 0 0.5rem;
  font-size: 1.05rem;
}
.landing-kontakt {
  margin: 0 0 1rem;
}

/* Die Rechtstexte. Schmaler Satzspiegel und Luft zwischen den
 * Abschnitten: sie sind lang, und lang gesetzte Zeilen liest niemand zu
 * Ende. Rund 70 Zeichen je Zeile ist das, was gut lesbar bleibt. */
.legal {
  max-width: 42rem;
}
.legal h2 {
  margin-top: 2rem;
  font-size: 1.15rem;
}
.legal p,
.legal li {
  line-height: 1.65;
}
.legal ul {
  padding-left: 1.2rem;
}
.legal li + li {
  margin-top: 0.4rem;
}

/* Fehlt eine Pflichtangabe, faellt es auf. Ein leeres Impressum sieht
 * aus wie ein kaputtes; ein Satz, der sagt, was fehlt, ist eine
 * Anweisung an den, der ausrollt. Kein Rot: die Farbe traegt hier keine
 * Bedeutung, die der Satz nicht schon traegt, und ein roter Kasten auf
 * einer Trauerseite schreit. */
.legal-missing {
  padding: 0.75rem 1rem;
  border: 1px solid var(--line, #d9d9d9);
  border-left: 3px solid var(--accent, #2f5d62);
  border-radius: 6px;
  background: var(--surface, #f0f0f0);
}
.legal-missing code {
  font-size: 0.9em;
}
/* --- Der starre Rahmen -------------------------------------------------
 *
 * **Die Seite scrollt nicht, der Inhalt scrollt.** Kopfzeile mit Zeichen
 * und Rechtslinks steht fest, die Einstellungsleiste steht fest, und
 * dazwischen liegt genau ein scrollender Bereich.
 *
 * Vorher war das Dokument selbst der Scrollbereich. Dadurch waren die
 * Pflichtlinks im Fuss erst nach dem Scrollen zu erreichen — auf einer
 * Seite, deren Impressum staendig verfuegbar sein muss, genau verkehrt.
 * Und auf dem Telefon wanderte die Kopfzeile beim Scrollen weg, obwohl
 * sie der einzige Weg zurueck ist.
 *
 * **`100svh` und nicht `100dvh`** (Ybug 203). `dvh` ist die *aktuelle*
 * Höhe und wächst, wenn die Adressleiste einfährt — auf einem Android-
 * Telefon meldete Chrome damit eine Höhe, die grösser war als das, was
 * am Ende zu sehen war, und der Fuss mit dem Impressum lag unter der
 * wieder ausgefahrenen Leiste. Erreichen liess er sich nicht: der
 * Körper scrollt nicht, gescrollt wird nur in `.site-content`.
 *
 * `svh` ist die kleine Fassung — die Höhe, die in jedem Zustand da ist.
 * Der Preis ist ein Streifen Luft, solange die Leiste eingefahren ist;
 * dafür steht das Impressum immer, und das ist auf dieser Seite keine
 * Geschmacksfrage. `vh` bleibt draussen: es rechnet mit der grossen
 * Fassung und schnitte unten immer ab.
 */
html {
  height: 100%;
}
body {
  height: 100svh;
  display: flex;
  flex-direction: column;
  /* Der Riegel. Was hier scrollen will, scrollt in .site-content oder
     gar nicht. */
  overflow: hidden;
}
.site-content {
  flex: 1;
  min-height: 0; /* ohne das waechst ein Flex-Kind ueber seinen Anteil hinaus */
  overflow-y: auto;
  overflow-x: hidden;
}

.site-brand {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 1rem;
  color: var(--ink, #1b1b1b);
  border-bottom: 1px solid var(--line, #d9d9d9);
}
/* **Zeichen und Schriftzug sind zwei Dinge, seit der Schriftzug die
   Adresse ist** (Ybug 34, 35). Vorher war beides ein Link nach Hause;
   jetzt führt das Zeichen heim, und die Stücke der Adresse daneben
   führen jedes woandershin. Ein Link, der drei Links enthält, geht
   nicht. */
.site-brand-home {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  color: inherit;
  min-width: 0;
}
/* Kein Unterstrich beim Hovern (Ybug 2) — das Zeichen färbt sich statt
   sich zu unterstreichen. Der Fokusring liegt am `<a>` selbst und kommt
   aus der gemeinsamen Regel weiter oben. */
/* Position, Maße und Rundung des Zeichens stehen weiter unten, im
   Abschnitt über die eingezogene Kopfzeile: sie gehören zu diesem
   Verhalten und nicht zur Kopfzeile an sich. */
.site-brand-zeichen {
  color: inherit;
  text-decoration: none;
  flex: 0 0 auto;
}
.site-brand-zeichen:hover {
  color: var(--accent, #2f5d62);
}
.site-brand-name,
.site-brand-claim {
  display: block;
}

/* --- Die eingezogene Kopfzeile ---------------------------------------
 *
 * ASCII-BEWUSST: `kopf` und `klein` sind Attributwerte und bleiben
 * ASCII wie jeder Bezeichner im Bestand.
 *
 * **Beim Scrollen nach unten zieht sich die Kopfzeile auf das Zeichen
 * zurück** (2026-09-07). Was bleibt, schwebt über der Seite: links das
 * Zeichen, rechts die Pille zu den Pflichttexten. Der Inhalt gewinnt
 * damit die Höhe der ganzen Leiste — auf einer Verwaltungstabelle drei
 * Zeilen, im Feed ein Stück Beitragsfläche.
 *
 * **Ausgelöst vom Scrollen und nicht von einer Uhr.** Beim Runterrollen
 * einziehen und beim Hochrollen zurückkommen ist der verbreitete
 * Mechanismus (Material Design, iOS); ein Header, der nach einer Zeit
 * von selbst einzieht, verändert die Oberfläche, während jemand liest —
 * genau darauf zielt WCAG 2.2.2. Der Auslöser ist so die eigene
 * Handlung, und das Verhalten ist nach zwei Sekunden gelernt.
 *
 * **Die Pille bleibt stehen, und das ist keine Kosmetik.** Ein
 * Impressum muss leicht erkennbar und ständig verfügbar sein; zwei
 * Schritte sind zulässig, aber der erste muss als Weg dorthin
 * erkennbar sein. Ein Zeichen ohne Wort ist es nicht — hinter dem
 * Zeichen versteckt wären es drei Schritte, von denen der erste nichts
 * verspricht.
 *
 * **Wieder auf** geht die Kopfzeile beim Scrollen nach oben, bei Hover
 * oder Fokus auf dem Zeichen und beim ersten Antippen (static/
 * hinweise.js). Sie schließt nicht von allein, während der Zeiger
 * darauf liegt — WCAG 1.4.13.
 */
/* **Zeichen und Pille schweben immer** — nicht erst im eingezogenen
   Zustand. Der Wechsel von `position: static` auf `fixed` ist die eine
   Eigenschaft, die sich nicht weich verändern lässt: beide sprangen an
   ihre neue Stelle, während die Leiste dahinter noch glitt. Jetzt
   ändern sich nur Werte, die ein Browser interpolieren kann — `top`,
   `left`, Maße, Farben, Deckkraft.

   Die Leiste hält dem Zeichen dafür Platz frei, damit die Adresse
   nicht darunter liegt. */
/* **Die Kopfzeile hat eine feste Höhe, und das ist die Voraussetzung
   dafür, dass die Schwebenden mittig sitzen.** Vorher richtete sie
   sich nach ihrem Inhalt, und der Abstand des Zeichens von oben war
   geraten: 0,7 rem bei 54 Punkten Zeichen in einer 65 Punkte hohen
   Leiste — es stand 5 Punkte zu tief. Jetzt steht die Höhe hier, und
   die Abstände werden aus ihr gerechnet. */
:root {
  --kopf-hoehe: 4.1rem;
}

/* **Das Zeichen schwebt, und seit b17 schwebt es allein.** Ihm
   gegenüber lag die Pille mit den Pflichttexten; sie steht jetzt als
   ein Wort im Fuß und hat mit der Kopfzeile nichts mehr zu tun. */
.site-brand-zeichen {
  position: fixed;
  z-index: 25;
}

/* Mittig: die halbe Differenz zwischen Leiste und Zeichen.

   **Das Zeichen sitzt immer in einem Quadrat.** Das Logo ist 42 mal 44
   Punkte groß — ein `border-radius: 999px` auf dieser Fläche ergibt
   ein Oval, und ein Oval mit Schatten sieht aus wie ein Versehen. Das
   Quadrat steht deshalb dauerhaft und ist im offenen Zustand nur
   unsichtbar: es hat dort keinen Grund und keinen Schatten. */
.site-brand-zeichen {
  top: calc((var(--kopf-hoehe) - 3.4rem) / 2);
  left: 1rem;
  width: 3.4rem;
  height: 3.4rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
}

.site-brand {
  /* Feste Höhe, weil die Schwebenden ihre Abstände daraus rechnen —
     und Platz links für das Zeichen: 1 rem Rand, 3,4 rem Zeichen,
     0,7 rem Abstand zur Adresse. */
  height: var(--kopf-hoehe);
  box-sizing: border-box;
  padding-left: 5.1rem;
}

/* Der eingezogene Zustand: die Leiste wird auf Höhe null gezogen, ihr
   Platz fällt dem Inhalt zu. */
body[data-kopf="klein"] .site-brand {
  height: 0;
  min-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-bottom-color: transparent;
  overflow: hidden;
}

/* **Die Deckkraft gehört an den Text und nicht an die Leiste.** Eine
   Deckkraft unter 1 gilt für den ganzen Teilbaum und macht daraus
   einen eigenen Stapelkontext: `opacity: 0` an der Leiste nahm das
   schwebende Zeichen und die Pille mit ins Unsichtbare, obwohl beide
   `position: fixed` tragen. Gemessen am 2026-09-07 — beide waren weg,
   sobald eingezogen wurde. */
body[data-kopf="klein"] .site-brand-text {
  opacity: 0;
}

body[data-kopf="klein"] .site-brand-zeichen {
  top: 0.5rem;
  left: 0.75rem;
  /* Ein eigener Grund, weil das Zeichen jetzt auf dem Inhalt liegt und
     nicht mehr auf der Leiste: auf einem Beitrag stünde es sonst in
     einem Bild. Das Quadrat dahinter steht schon (siehe oben) — hier
     wird es nur sichtbar. */
  background: var(--paper, #fff);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
}

/* **Der Weg zum Impressum bewegt sich beim Einziehen nicht mehr**
   (b17). Er stand als Pille in der Kopfzeile und musste mit ihr zum
   Kreis schrumpfen, damit er erreichbar blieb — das Wort verschwand
   dabei aus dem Bild, und was blieb, war ein Paragraphenzeichen. Im
   Fuß stellt sich die Frage nicht: die untere Kante zieht sich nicht
   ein, und das Wort steht jederzeit ausgeschrieben da. */

/* **Die Übergänge.** 0,28 Sekunden mit der Kurve, die überall dort
   sitzt, wo etwas ein- und ausfährt: schnell los, sanft an. Schneller
   wirkt hektisch, langsamer wie eine Verzögerung.

   Die Deckkraft der Leiste läuft kürzer: sie soll weg sein, bevor die
   Höhe null erreicht — sonst schiebt sich ein halber Schriftzug in die
   Kante. */
@media (prefers-reduced-motion: no-preference) {
  .site-brand {
    transition: height 0.28s cubic-bezier(0.4, 0, 0.2, 1),
      padding 0.28s cubic-bezier(0.4, 0, 0.2, 1);
  }

  /* **Der Text kommt erst, wenn Platz für ihn ist** (b73). Die Leiste
     wächst in 0,28 Sekunden, die Deckkraft lief in 0,18 — die Adresse
     war also schon da, während die Leiste noch halb so hoch war, und
     weil ihr Inhalt mittig sitzt und über die Kante beschnitten wird,
     stand sie oben und unten angeschnitten im Bild. Beim Einziehen ist
     die Reihenfolge richtig herum: erst weg, dann schmal. Die
     Verzögerung gilt deshalb nur für den Weg zurück — die Regel für
     den eingezogenen Zustand nimmt sie wieder heraus. */
  .site-brand-text {
    transition: opacity 0.18s ease 0.16s;
  }

  body[data-kopf="klein"] .site-brand-text {
    transition-delay: 0s;
  }

  .site-brand-zeichen {
    transition: top 0.28s cubic-bezier(0.4, 0, 0.2, 1),
      left 0.28s cubic-bezier(0.4, 0, 0.2, 1),
      right 0.28s cubic-bezier(0.4, 0, 0.2, 1),
      padding 0.28s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.28s ease,
      box-shadow 0.28s ease;
  }
}

/* **Was oben haftet, lässt dem Zeichen Platz.** Die Reiterleiste der
   Verwaltung sitzt auf `top: 0` und lag im eingezogenen Zustand unter
   dem Zeichen: „Übersicht" war links angeschnitten. Ein Einzug hält
   die Stelle frei — nur solange eingezogen ist, sonst stünde die
   Leiste dauernd eingerückt.

   **Rechts braucht sie den Einzug nicht mehr** (b17). Dort schwebte
   die Pille mit den Pflichttexten; sie steht jetzt im Fuß, und die
   Leiste bekommt ihre rechte Hälfte zurück. */
body[data-kopf="klein"] .admin-nav {
  padding-left: 3.25rem;
}

/* **Auf dem Telefon darf der Einzug keine Zeile kosten** (b73).
   Gemessen am 2026-09-13 auf 375 Punkten: offen standen die fünf
   Reiter auf zwei Zeilen und die Leiste war 95 Punkte hoch, eingezogen
   auf drei und 138 — der Einzug von 52 Punkten warf „Mitglieder" in
   eine neue Zeile. Das ist die Umkehrung dessen, wofür der eingezogene
   Kopf da ist: er soll Platz freigeben und nahm 43 Punkte. Und weil
   die Leiste oben haftet, wuchs sie über die Karte darunter, sobald
   jemand rollte.

   Zwei Griffe, beide nur hier unten: das schwebende Zeichen wird
   kleiner, und die Reiter tragen weniger Polster. Damit bleibt es in
   beiden Zuständen bei zwei Zeilen und 95 Punkten — die Leiste ändert
   ihre Höhe beim Rollen überhaupt nicht mehr, und das ist der
   eigentliche Gewinn: was nicht wächst, schiebt auch nichts.

   Der Einzug bleibt die Rechnung von oben — linker Rand plus Zeichen
   minus das Polster des ersten Reiters —, nur mit den kleineren
   Zahlen: 0,5 + 2,6 − 0,7 = 2,4 rem. */
@media (max-width: 30rem) {
  .admin-nav a {
    padding: 0 0.7rem;
  }

  body[data-kopf="klein"] .site-brand-zeichen {
    top: 0.4rem;
    left: 0.5rem;
    width: 2.6rem;
    height: 2.6rem;
  }

  /* Das Logo ist 42 auf 44 Punkte groß und säße sonst über der Kante
     seines Quadrats. Es hat eine `viewBox`, also skaliert es mit. */
  body[data-kopf="klein"] .site-brand-zeichen .logo-mark {
    width: 1.82rem;
    height: 1.9rem;
  }

  body[data-kopf="klein"] .admin-nav {
    padding-left: 2.4rem;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .site-brand {
    transition: height 0.18s ease, padding 0.18s ease;
  }
}

/* --- Die Adresse an der Stelle der Wortmarke -------------------------
 *
 * ASCII-BEWUSST: `adresse` ist ein Klassenname und bleibt ASCII wie
 * jeder Bezeichner im Bestand.
 *
 * **Der Name links ist die Adresse dieser Seite** (Ybug 34, 35). Er war
 * ein unveränderlicher Schriftzug, während die Überschrift darunter den
 * Namen des Verstorbenen zeigte — zwei Zeilen, von denen keine sagte,
 * wo man ist. Jetzt sagt es die obere, und die Überschrift ist weg.
 *
 * **Die Wortmarke bleibt die Wortmarke** — durchgehend, in einem
 * Schnitt: `wir.` und `/<slug>` sind so gesetzt wie der Hostname
 * zwischen ihnen. Zwei Gewichte in einer Adresse lasen sich als zwei
 * Dinge, und es ist eines. Die Abwandlung liegt darin, was dasteht,
 * nicht darin, wie es aussieht.
 */
.site-adresse {
  display: flex;
  max-width: 100%;
  overflow: hidden;
  font-family: var(--font-heading, sans-serif);
  font-weight: 700;
  font-size: 1.1rem;
}

/* **24 Punkte hoch, nicht 20.** WCAG 2.2 verlangt unter 2.5.8 ein
   Berührziel von mindestens 24x24. Die Kopfzeile wächst dadurch nicht
   — sie richtet sich nach dem 44 Punkte hohen Zeichen daneben. */
/* `font-weight` steht hier und nicht nur am Behälter: die allgemeine
   Regel für `a` setzt 600, und eine direkte Regel schlägt jede
   Vererbung — die Adresse stand dadurch einen Schritt leichter da als
   die Wortmarke, die sie ersetzt. */
.site-adresse a {
  color: var(--ink, #1b1b1b);
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  white-space: nowrap;
}

/* Kein Unterstrich beim Hovern, wie überall auf dieser Seite (Ybug 2)
   — das Stück färbt sich. Damit ist auch sichtbar, dass die Adresse
   aus mehreren Wegen besteht und nicht aus einem. */
.site-adresse a:hover {
  color: var(--accent, #2f5d62);
}

/* --- Der Fuß mit dem Impressum --------------------------------------
 *
 * ASCII-BEWUSST: `rechtsfuss` und `fuss-hoehe` sind Bezeichner.
 *
 * **Ein Wort, mittig, an der unteren Kante jeder Seite** (b17). Es
 * stand bis zum 2026-09-13 als Pille rechts in der Kopfzeile und nahm
 * dort den Platz der Adresse (b01, b06); es musste beim Einziehen der
 * Kopfzeile zu einem Kreis mit dem Paragraphenzeichen schrumpfen, um
 * erreichbar zu bleiben, und genau dann war es nicht mehr leicht
 * erkennbar.
 *
 * Unten stellt sich beides nicht: die Kante wechselt ihre Höhe nicht,
 * das Wort steht jederzeit ausgeschrieben da, und auch der Editor hat
 * sie — er trägt die beiden Knöpfe des Hauses nicht, aber die Mitte
 * unten ist bei ihm frei (b55).
 *
 * **Der Fuß ist ein Flexkind und schwebt nicht.** Wie die Kopfzeile
 * liegt er im Fluss von `body`; `.site-content` bekommt, was übrig
 * bleibt. Was schwebt — die Einstellungen links, der Knopfstapel
 * rechts —, rechnet seinen Abstand von unten aus `--fuss-hoehe` und
 * steht damit über dem Wort statt darauf (b54).
 */
:root {
  --fuss-hoehe: 2rem;
}

.site-fuss {
  flex: none;
  height: var(--fuss-hoehe);
  display: flex;
  align-items: center;
  justify-content: center;
  /* **Über den Schwebenden.** Das aufgeklappte Menü fährt nach oben in
     den Inhalt hinein und liegt dabei neben dem Knopfstapel; ohne die
     Stufe läge es darunter. */
  position: relative;
  z-index: 35;
}

.rechtsfuss {
  position: relative;
}

/* **Ein Wort und keine Fläche.** Jeder andere Auslöser im Haus ist ein
   Kreis mit einem Zeichen; dieser ist Schrift, weil ein Zeichen nicht
   sagt, dass dahinter das Impressum liegt. Leise gesetzt — er ist der
   Pflichtweg und nicht der Weg, den jemand sucht —, aber in der
   Textfarbe beim Überfahren und mit einem Berührziel von 24 Punkten,
   was WCAG 2.5.8 verlangt. */
.rechtsfuss-wort {
  list-style: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 24px;
  padding: 0 0.75rem;
  color: var(--muted, #5c584f);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  cursor: pointer;
}

.rechtsfuss-wort::-webkit-details-marker,
.rechtsfuss-wort::marker {
  display: none;
  content: "";
}

.rechtsfuss-wort:hover,
.rechtsfuss[open] .rechtsfuss-wort {
  color: var(--accent, #2f5d62);
}

/* **Nach oben aufklappend**, weil das Wort unten sitzt, und über dem
   Inhalt statt in ihm: der Fuß ist nur so hoch wie eine Zeile, und
   eine Liste, die ihn aufblähte, verschöbe die ganze Seite. Mittig
   über dem Wort, nicht an einer Kante ausgerichtet — das Wort steht in
   der Mitte, und ein Menü, das von dort nach einer Seite ausbricht,
   sieht aus, als gehörte es woandershin.

   **`column-reverse`, wie beim Rundknopf** (`.fab-actions`). Ein Menü,
   das nach oben aufgeht, stapelt sich von unten: der erste Weg liegt
   dem Auslöser am nächsten und damit dem Daumen. Mit `column` stand
   „Impressum" ganz oben und „Dienste" über dem Wort — der Weg, um
   dessentwillen das Wort dasteht, war der weiteste. */
.rechtsfuss-liste {
  position: absolute;
  bottom: calc(100% + 0.4rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 35;
  display: flex;
  flex-direction: column-reverse;
  gap: 0.35rem;
}

@media (max-width: 30rem) {
  /* **Der Anspruch bleibt stehen** (b06). Er war auf dem Telefon
     ausgeblendet, weil Adresse, Anspruch und die Rechtspille sich die
     Kopfzeile teilten und der Platz für drei nicht reichte. Die Pille
     steht seit b17 im Fuß; die Kopfzeile trägt jetzt zwei Zeilen, und
     beide passen. Die Adresse schrumpft dafür weiter einen Schritt. */
  .site-adresse {
    font-size: 1rem;
  }
}

/* **Auf breiten Schirmen steht das Wort wieder oben rechts**
   (Festlegung 2026-09-13). Der Fuß ist die Antwort auf einen engen
   Schirm: dort teilen sich Adresse, Anspruch und der Pflichtweg eine
   Zeile von 375 Punkten, und für drei reicht sie nicht (b01, b06).
   Diese Enge gibt es ab 48 rem nicht mehr — die Kopfzeile hat rechts
   Platz übrig, und dort sucht man ein Impressum zuerst.

   **Es bleibt dasselbe Wort und wird nicht wieder zur Pille.** Was b17
   entschieden hat, gilt weiter: ausgeschrieben, ohne Fläche, ohne
   Paragraphenzeichen. Es wechselt den Platz und nicht die Form, und der
   Fuß unten fällt dafür weg — zwei Wege zu einem Text wären zwei
   Stellen, an denen einer veraltet.

   Der Fuß schwebt dazu, statt im Fluss zu stehen: die Kopfzeile ist
   fertig gesetzt, und ein Kind mehr darin verschöbe Zeichen und
   Adresse. Dieselbe Lösung wie beim schwebenden Zeichen gegenüber. */
@media (min-width: 48rem) {
  .site-fuss {
    position: fixed;
    top: 0;
    right: 1rem;
    height: var(--kopf-hoehe);
    z-index: 25;
  }

  /* Und die Schwebenden unten brauchen den Ausgleich nicht mehr: der
     Fuß nimmt dort keinen Platz (b54 gilt nur, solange er unten
     steht). */
  :root {
    --fuss-hoehe: 0rem;
  }

  /* Das Menü klappt nach unten auf, wie jedes Menü unter einem Knopf
     im Kopf — und an der rechten Kante ausgerichtet statt mittig: das
     Wort steht am Rand, und ein Menü, das darüber hinausliefe, stünde
     halb außerhalb des Schirms. */
  .rechtsfuss-liste {
    top: calc(100% + 0.4rem);
    bottom: auto;
    left: auto;
    right: 0;
    transform: none;
    flex-direction: column;
  }
}

/* Die Fahrt kommt dann von oben. Sie hängt sonst am `data-fahrt` des
   Templates, und das kennt keine Bildschirmbreite — hier steht deshalb
   der eine Wert, der sich mit der Richtung ändert. Die Staffel bleibt,
   wie sie ist: der erste im Dokument liegt dem Wort am nächsten, oben
   wie unten. */
@media (min-width: 48rem) and (prefers-reduced-motion: no-preference) {
  .rechtsfuss-liste[data-fahrt="hoch-gestapelt"] > * {
    animation-name: menue-abfahren;
  }
}

/* --- Der Feed im starren Rahmen ---------------------------------------
 *
 * Er war frueher selbst der Scrollbereich mit eigener `100dvh`-Hoehe.
 * Das ist jetzt `.site-content`; der Feed fuellt ihn nur noch aus und
 * bringt die Einrastung mit. Zwei Scrollbereiche uebereinander hiessen
 * zwei Hoehen, die auseinanderlaufen — und genau daran zerbrach der
 * einrastende Feed schon einmal.
 */
/* **Auf dem Feed scrollt nicht .site-content, sondern .feed selbst.**
 * Der Grundsatz bleibt derselbe — ein Scrollbereich, und der Rahmen
 * darum steht —, nur liegt der Rahmen hier eine Ebene tiefer: unter dem
 * Feed steht die Leiste mit den seitenweiten Wegen, und die soll nicht
 * mitscrollen.
 *
 * `height: 100%` am Feed und die Einrastung an .site-content trugen
 * zusammen nicht: der Feed war 100% hoch und sein Inhalt bei zwei
 * Beitraegen doppelt so hoch, lief also ueber seinen eigenen Kasten
 * hinaus und malte ueber alles, was danach kam. Die Leiste lag
 * vollstaendig unter dem zweiten Beitrag. Gemessen am 2026-09-06:
 * Kasten 568, Inhalt 1135, Ueberdeckung 351x114.
 *
 * `min-height: 0` ist der Zusatz, ohne den ein Flex-Kind seine
 * Inhaltsgroesse nicht unterschreitet und die Spalte auseinanderdrueckt
 * statt zu scrollen. */
.page-feed .site-content {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.page-feed .feed {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}

/* **Der Wechsel gleitet, er schnappt nicht** (Ybug 58). Die beiden
   Winkel in der Führung sind Sprungmarken (templates/cases/feed.html);
   eine Sprungmarke springt, und der nächste Beitrag stand da, ohne dass
   etwas dazwischen zu sehen war — „zack", wie gemeldet. Mit
   `scroll-behavior` gleitet der Feed dorthin, und man sieht, in welche
   Richtung es ging.

   **Nur mit dem Finger bleibt es hart**, und das ist richtig: dort
   führt die Hand, und eine Bewegung, die ihr nachläuft, fühlt sich
   zäh an. Die Angabe gilt für Sprünge, nicht für das Wischen.

   Hinter `prefers-reduced-motion`: wer Bewegung abgeschaltet hat, will
   sie auch hier nicht. Ohne die Hülle wäre das eine
   Barriere und keine Zugabe. */
@media (prefers-reduced-motion: no-preference) {
  .page-feed .feed {
    scroll-behavior: smooth;
  }
}

/* Bis zum 2026-09-06 stand derselbe Satz Regeln ein zweites Mal weiter
 * oben, an `body.page-feed`, aus der Zeit vor dem stehenden Rahmen. Er
 * war doppelt und in Teilen tot: die Spalte und `overflow: hidden` traegt
 * `body` inzwischen fuer jede Seite, `.site-brand` hat `flex: none`, und
 * `body.page-feed > .messages` traf ueberhaupt nichts mehr — die
 * Meldungen liegen seit dem Umbau *in* `.site-content`. Weil
 * `body.page-feed .feed` spezifischer ist als `.page-feed .feed`, gewann
 * dabei die alte Fassung. Das ist die Art Doppelung, die erst auffaellt,
 * wenn eine der beiden Stellen geaendert wird und nichts passiert. */
.feed-post {
  height: 100%;
  scroll-snap-align: start;
}

/* Tabellenkoepfe bleiben stehen.
 *
 * Dieselbe Regel wie beim Rahmen, eine Ebene tiefer: was ordnet, bleibt;
 * was geordnet wird, scrollt. Wer in der Beitragsliste nach unten
 * scrollt, weiss sonst in der vierten Zeile nicht mehr, welche Spalte
 * „Sichtbarkeit" ist und welche „Status".
 *
 * `top: 0` bezieht sich auf `.site-content` — den einzigen Bereich, der
 * ueberhaupt scrollt. Der Hintergrund ist Pflicht und nicht Kosmetik:
 * eine haftende Zeile ohne eigenen Grund ist durchsichtig, und die
 * Zeilen wandern sichtbar darunter durch.
 */
table.wide thead th {
  position: sticky;
  /* **Unter der Reiterleiste und nicht unter ihr durch.** Sie haftet
     seit dem 2026-09-07 selbst auf `top: 0` (Ybug 35); der Kopf muss
     um ihre Höhe tiefer ansetzen, sonst verschwindet er darunter. Der
     Wert ist die Leiste: 2,5 rem Reiter, 0,75 rem Polster, ein Rand.

     **Bricht die Leiste auf zwei Zeilen um** — am Telefon möglich —,
     ist der Wert zu klein und die Leiste deckt den Kopf teilweise ab.
     Das ist die bessere von zwei unvollkommenen Lagen: sie hat den
     höheren `z-index`, und wo man steht, wiegt schwerer als die
     Spaltennamen. Genau zu rechnen bräuchte ein Skript, das die Höhe
     misst — für einen Fall, der nur in der schmalsten Breite eintritt. */
  top: 3.35rem;
  z-index: 1;
  background: var(--paper, #fff);
  /* `border-bottom` an einer haftenden Zelle wird beim Scrollen
     mitgenommen und verschwindet — ein Schatten bleibt. */
  border-bottom: none;
  box-shadow: inset 0 -1px 0 var(--line, #d9d9d9);
  /* **Ein Spaltenkopf bricht nicht um.** „Sichtbarkeit" in zwei
     Zeilen, „Eingegangen" mit dem Auskunftszeichen darunter — das war
     der Zustand am 2026-09-07, nachdem die Breiten fest wurden. Ein
     Kopf ist die Beschriftung einer Spalte und keine Prosa: er steht
     in einer Zeile, und wenn dafür der Platz fehlt, ist die Tabelle an
     dieser Breite die falsche Form (siehe die Kartenschwelle weiter
     oben). Die Schrift ist dafür zwei Schritte kleiner als im
     Zelltext: „Gemeldet" plus Auskunftszeichen brauchte in seiner
     Spalte mehr Platz, als sie hat, und lief in die Nachbarspalte. */
  white-space: nowrap;
  font-size: 0.8rem;
}

/* --- Hinweise als Toast ------------------------------------------------
 *
 * **Warum sie nicht mehr im Fluss stehen.** Bis zum 2026-09-06 war die
 * Meldung ein Streifen ganz oben im Inhalt: „Danke, der Beitrag ist
 * gemeldet." stand über dem Beitrag, in Surface-Farbe, ohne Rand — und
 * auf der Beitragsseite schob sie den Beitrag nach unten, sodass der
 * Leser nach dem Melden erst einmal scrollte und die Bestätigung dabei
 * aus dem Bild lief. Wer sie nicht im selben Moment las, hat sie nie
 * gesehen (Ybug 4).
 *
 * Ein Toast steht fest, überlagert nichts Wichtiges und geht von selbst.
 * `aria-live` am Behälter meldet ihn den Vorleseprogrammen, ohne den
 * Fokus zu stehlen — eine Bestätigung ist eine Auskunft, kein Eingriff.
 *
 * Er steht **oben** und nicht unten: unten links sitzt die
 * Einstellungsleiste, unten rechts der Rundknopf, und die Mitte
 * dazwischen ist am Telefon keine 6 rem breit.
 */
.toasts {
  position: fixed;
  top: 4.25rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: min(26rem, calc(100vw - 1.5rem));
  margin: 0;
  padding: 0;
  list-style: none;
  /* Der Behälter selbst fängt nichts ab — sonst läge eine unsichtbare
     Scheibe über der Seite, sobald kein Toast mehr da ist. */
  pointer-events: none;
}

/* **Der Grund ist dunkel und nicht `--surface`** (2026-09-07). Der
   Toast lag vorher in der Flächenfarbe der Seite, mit einem Rand darum
   — auf einem hellen Theme unterschied ihn vom Papier ein
   Zehntelschritt Helligkeit, und die Meldung, die eine Handlung
   bestätigt, sah aus wie ein Stück Seite.

   Genommen ist die Textfarbe als Fläche, wie bei der Auskunftsblase
   (`.icon-titel`): sie ist in jedem Theme und in beiden Modi geprüft —
   `--ink` auf `--paper` ist das Kontrastpaar, auf dem die ganze Seite
   steht, nur andersherum. Eine Signalfarbe kommt nicht in Frage: die
   Themes bringen kein geprüftes Rot oder Grün mit, und eine
   Trauerseite soll nicht in Ampelfarben sprechen.

   Der Balken links bleibt der Akzent — das eine Stück Farbe, an dem
   ein Toast auch dann als solcher erkennbar ist, wenn er in der Ecke
   nur angeschnitten ins Bild kommt. */
.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.75rem 0.9rem;
  background: var(--ink, #1b1b1b);
  color: var(--paper, #fff);
  border-left: 4px solid var(--accent, #2f5d62);
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
  font-size: 0.95rem;
}

.toast p {
  margin: 0;
  flex: 1;
  min-width: 0;
}

/* Auf dunklem Grund: das Kreuz trägt die Papierfarbe, leicht gedämpft.
   `--muted` wäre hier falsch — es ist für Text auf Papier geprüft, und
   der Grund ist genau der andere. */
.toast-close {
  flex: 0 0 auto;
  padding: 0;
  width: 1.75rem;
  height: 1.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--paper, #fff);
  opacity: 0.75;
  border-radius: 999px;
}

.toast-close:hover {
  opacity: 1;
}

/* Das Verschwinden. `visibility` mit dazu, damit der Toast nach dem
   Ausblenden nichts mehr abfängt — `opacity: 0` allein bleibt
   anklickbar. */
.toast[data-schliessend="true"] {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s ease, visibility 0s linear 0.4s;
}

@media (prefers-reduced-motion: reduce) {
  .toast[data-schliessend="true"] {
    transition: none;
  }
}

/* --- Das Menü: die Form jedes aufklappenden Menüs ----------------------
 *
 * ASCII-BEWUSST: `menue`, `gewaehlt`, `hinweis` sind Klassennamen und
 * bleiben ASCII wie jeder Bezeichner im Bestand. Die Prosa hier trägt
 * volle Umlaute.
 *
 * **Ein Eintrag sieht überall gleich aus** — Symbol, fetter Titel,
 * erklärende Unterschrift, in einem abgerundeten Rahmen mit dem Grund
 * des Themes. Vorbild ist das Editor-Menü unten links; seit dem
 * 2026-09-07 ist es nicht mehr die Ausnahme, sondern die Regel für
 * jeden Rundknopf im Haus (Ybug 39).
 *
 * **Warum die Unterschrift keine Zierde ist.** Ein Menüeintrag sagt
 * sonst nur, wohin er führt, und nicht, was dort geschieht:
 * „Verwerfen" allein ist eine Drohung, „Verwerfen — zurück zum letzten
 * Stand" eine Auskunft. Wo ein Eintrag einen Zustand hat, steht der
 * Zustand darunter, und man sieht ihn ohne aufzuklappen.
 *
 * **Die Klassen stehen hier und nicht in editor.css**, obwohl das
 * Editor-Menü die Vorlage war: der Editor lädt beide Dateien
 * (templates/posts/editor.html), und dieselbe Form an zwei Stellen zu
 * pflegen heißt, dass sie irgendwann an einer davon abweicht.
 */
.menue-option {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* **Breit genug für die Unterschrift** (AG-017). 13rem liessen dem
     Text 156 Punkte, und damit endete fast jede Unterschrift im Haus
     in drei Auslassungspunkten: „Alle Beitraege als Text, bar…",
     „Was Du geschrieben hast, mit S…". Der Kasten oben sagt, die
     Unterschrift sei keine Zierde, sondern die Auskunft — eine
     abgeschnittene Auskunft ist keine. */
  width: 16rem;
  max-width: min(24rem, 90vw);
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 12px;
  background: var(--paper, #fff);
  color: var(--ink, #1b1b1b);
  font: inherit;
  text-align: left;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  cursor: pointer;
}

/* **Der Kopf der zweiten Stufe ist eine kleine Pille** (Ybug 106, 120,
 * 148). Er trug anfangs `.menue-option` wie die Einträge darunter und
 * sah damit aus wie eine Wahl, war aber die Überschrift darüber; seit
 * Ybug 106 war er eine nackte Überschrift ohne Grund und ohne Kante.
 *
 * Das war die halbe Strecke: ohne Fläche stand er über den Einträgen
 * in der Luft, und **auf der Gedenkseite stand er ganz ohne Form** —
 * die Regel lag in `frontend/src/editor.css`, das nur der Editor lädt,
 * während die Einstellungsleiste dieselbe Klasse baut
 * (static/settings.js, Ybug 120). Ein Browser-Knopf mit Systemschrift
 * mitten im Menü.
 *
 * Jetzt trägt er den Grund des Themes, eine Kante und den vollen
 * Radius: eine Pille, so breit wie ihr Inhalt. Sie ist kleiner und
 * leiser als die Einträge — sie konkurriert nicht mit ihnen, aber sie
 * steht auf derselben Fläche. Der doppelte Winkel davor sagt, was ein
 * Druck tut: eine Stufe zurück.
 *
 * Sie steht hier und nicht im Blatt des Editors: die Form gilt für
 * jedes zweistufige Menü im Haus — Werkzeugkranz, Einstellungsleiste,
 * und was künftig dazukommt. */
.menue-kopf {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  align-self: flex-start;
  max-width: min(24rem, 90vw);
  margin-bottom: 0.15rem;
  padding: 0.25rem 0.7rem 0.25rem 0.5rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  background: var(--surface, #f0ede7);
  color: var(--muted, #5c584f);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-align: left;
  cursor: pointer;
}

.menue-kopf:hover,
.menue-kopf:focus-visible {
  color: var(--ink, #1b1b1b);
}

/* Das Zeichen schrumpft nicht: ein halber Winkel sagt nichts. */
.menue-kopf .icon {
  flex: 0 0 auto;
}

.menue-kopf-wort {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Ein Eintrag kann ein Link sein — dann trägt er die Farbe des Textes
   und nicht die der Links: er ist ein Menüeintrag und sieht aus wie
   einer. */
a.menue-option,
a.menue-option:visited {
  color: var(--ink, #1b1b1b);
  text-decoration: none;
}

.menue-option:disabled {
  opacity: 0.45;
  cursor: default;
}

/* Das Symbol steht links und schrumpft nicht: es ist die Marke des
   Eintrags, und ein halbes Symbol ist keine. */
.menue-option .icon {
  flex: 0 0 auto;
}

.menue-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.menue-name {
  font-weight: 600;
  font-size: 0.85rem;
}

/* **Die Unterschrift bricht um, statt zu enden** (AG-017). Sie stand
   auf einer Zeile mit `text-overflow: ellipsis`; was nicht hinpasste,
   war weg — und weil sie in jeder Sprache anders lang ist, traf es
   auf Englisch andere Eintraege als auf Deutsch. Zwei Zeilen kosten
   den Kasten wenige Punkte Hoehe und geben den Satz zurueck. */
.menue-hinweis {
  font-size: 0.72rem;
  opacity: 0.75;
  white-space: normal;
  line-height: 1.25;
}

/* **Die gewählte Option trägt den Akzent.** Sie ist kein anderer
   Eintrag, nur der, der gerade gilt — deshalb dieselbe Form und nur
   ein anderer Grund. `aria-checked` und die Klasse hängen zusammen,
   damit Bild und Auskunft nicht auseinanderlaufen können. */
.menue-option.gewaehlt,
.menue-option[aria-checked="true"],
.menue-option[aria-current="true"] {
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
  border-color: var(--accent, #2f5d62);
}

.menue-option:hover,
.menue-option:focus-visible {
  border-color: var(--accent, #2f5d62);
}

/* Eine Gruppe von Optionen — gestapelt, enger als die Menüeinträge
   selbst: sie gehören zusammen und sind eine Wahl unter Gleichen. */
.menue-optionen {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

/* **`display` schlägt `hidden`, und das ist eine Falle.** Das
   `hidden`-Attribut ist im Stilblatt des Browsers nur ein
   `display: none` mit der Stärke eines UA-Selektors; jede eigene
   Regel mit `display` gewinnt dagegen. Die Einstellungsleiste stand
   deshalb offen da, obwohl das Skript sie versteckt hatte — gemessen
   am 2026-09-07 im Browser, nicht im Test: eine Suite ohne Layout
   sieht das nicht. */
.menue-optionen[hidden] {
  display: none;
}

/* --- Der Titel eines Symbols auf Berührung -----------------------------
 *
 * Mit Zeiger zeigt der Browser das `<title>` im SVG selbst als Tooltip.
 * Auf einem Berührungsbildschirm gibt es kein Verweilen, und diese
 * Blase tritt an seine Stelle (static/hinweise.js).
 *
 * Sie liegt über allem außer der Rückfrage: eine Auskunft darf einen
 * Dialog nicht überlagern, aber wohl den Rundknopf, an dem die meisten
 * dieser Symbole sitzen.
 */
.icon-titel {
  position: fixed;
  z-index: 45;
  max-width: min(18rem, calc(100vw - 1rem));
  white-space: normal;
  padding: 0.3rem 0.55rem;
  background: var(--ink, #1b1b1b);
  color: var(--paper, #fff);
  border-radius: 6px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
  font-size: 0.85rem;
  line-height: 1.3;
  /* Sie fängt nichts ab: wer nach dem Antippen weitertippt, trifft das,
     was darunter liegt, und nicht die Blase. */
  pointer-events: none;
}

/* --- Der Rundknopf unten rechts ---------------------------------------
 *
 * **Ein Ort für die Wege einer Seite.** Vorher trug jede Seite ihre
 * eigene Leiste: der Feed eine Karte unten rechts, die Liste einen Link
 * unter der Aufzählung, die Verwaltung einen abgesetzten Eintrag in der
 * Navigationszeile, und die Rechtstexte gar nichts — von dort führte
 * überhaupt kein Weg links (Ybug 3, 6, 7, 9).
 *
 * Ein `<details>` und kein Skriptknopf: Auf- und Zuklappen, Tastatur und
 * Vorleseprogramm bringt der Browser mit. Was das Skript ergänzt
 * (static/hinweise.js), ist Zubehör — Schließen beim Klick daneben und
 * mit Escape. Fällt es aus, klappt der Knopf trotzdem.
 *
 * Er sitzt rechts, weil links die Einstellungsleiste sitzt.
 */

/* --- Das Fenster für die Rechtstexte --------------------------------
 *
 * ASCII-BEWUSST: `recht-karte` und `dienste-liste` sind Klassennamen.
 *
 * **Aus der Pille ein Fenster, über die Adresse eine Seite** (Ybug 44).
 * Es ist ein Blatt Papier über der Seite: derselbe Grund, dieselbe
 * Rundung, derselbe Schatten wie eine Karte — und ein Text darin, der
 * dieselben Maße hat wie auf seiner Seite (`.legal` an der Fläche).
 *
 * **Hoch, aber nicht randlos.** Die Datenschutzerklärung ist lang; das
 * Fenster nimmt bis zu 85 Prozent der Höhe und rollt darin. Randlos
 * wäre es eine Seite, und dann hätte die Unterscheidung keinen Sinn
 * mehr.
 */
/* **Die Maße gelten in jedem Zustand**, das Aussehen erst im offenen. */
.recht-karte {
  width: min(42rem, calc(100vw - 2rem));
  max-height: 85vh;
}

/* **`[open]` am Selektor, und das ist keine Feinheit** (Ybug 49, 52).
   Ein `<dialog>` ist geschlossen unsichtbar, weil das Blatt des Browsers
   `dialog:not([open]) { display: none }` sagt — ein `display: flex` von
   hier sticht das aus, denn ein Autorenblatt wiegt schwerer. Die Folge
   war doppelt: das leere Fenster stand auf **jeder** Seite oben in der
   Mitte, ein Kasten mit einem Kreuz und ohne Inhalt, den niemand
   wegbekam. Und das Schließen sah aus, als täte es nichts — `close()`
   nahm das `open` weg, das Fenster blieb stehen und sprang nur an den
   Seitenanfang.

   Dieselbe Falle gilt für jeden `<dialog>` im Haus: wer ihm `display`
   gibt, gibt es dem offenen. */
.recht-karte[open] {
  padding: 0;
  background: var(--paper, #fff);
  color: var(--ink, #1b1b1b);
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 14px;
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.28);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.recht-karte::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

/* Der Knopf zum Schließen liegt oben rechts und haftet dort: bei einem
   Text von zwölf Bildschirmhöhen ist der Weg nach oben sonst weit. */
.recht-karte-kopf {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  justify-content: flex-end;
  margin: 0;
  padding: 0.5rem 0.5rem 0;
  background: var(--paper, #fff);
}

.recht-karte-zu {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  padding: 0;
  background: none;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  color: var(--ink, #1b1b1b);
  cursor: pointer;
}

.recht-karte-zu:hover {
  border-color: var(--accent, #2f5d62);
  color: var(--accent, #2f5d62);
}

.recht-karte-flaeche {
  overflow-y: auto;
  padding: 0 1.25rem 1.25rem;
}

/* Die erste Überschrift im Fenster braucht keinen Abstand nach oben —
   darüber steht schon der Kopf mit dem Knopf.

   **Und sie muss auf ein Telefon passen** (Ybug 203).
   „Datenschutzerklärung" und „Nutzungsbedingungen" sind ein Wort von
   zwanzig Zeichen; bei fester Größe standen sie über den Rand hinaus.
   Die Größe folgt der Breite, und wo auch das nicht reicht, wird das
   Wort umgebrochen statt abgeschnitten. */
.recht-karte-flaeche > h1:first-child {
  margin-top: 0;
  font-size: clamp(1.3rem, 6.5vw, 2rem);
  overflow-wrap: anywhere;
  hyphens: auto;
}

/* --- Die Liste der Dienste ------------------------------------------
 *
 * Ein Zeichen, ein fetter Name, ein Satz — dieselbe Ordnung wie in
 * einem Menüeintrag, nur als Text und nicht als Knopf: hier wird
 * nichts angeklickt, hier wird gelesen. */
.dienste-liste {
  list-style: none;
  margin: 0.75rem 0 1.25rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}

.dienste-zeile {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}

.dienste-zeile > .icon {
  flex: 0 0 auto;
  margin-top: 0.15rem;
  color: var(--muted, #5c584f);
}

.dienste-text strong {
  display: block;
}

/* --- Wie ein Menü aufgeht --------------------------------------------
 *
 * ASCII-BEWUSST: `data-fahrt` ist ein Attributname.
 *
 * **Jedes Menü im Haus fährt auf, statt zu erscheinen.** Die Einträge
 * kommen einer nach dem anderen aus der Richtung, in der der Knopf
 * liegt, der sie geöffnet hat. Das erzählt zwei Dinge ohne ein Wort:
 * woher die Liste kommt, und dass sie sich dorthin auch wieder
 * zurückzieht.
 *
 * Angefangen hat es beim Werkzeugkranz des Editors (Ybug 47), wo sich
 * der Kranz bei einem neuen Beitrag von selbst vorstellt — elf Einträge,
 * die schlagartig dastehen, sind ein Sprung. Danach fehlte die Bewegung
 * überall sonst, und deshalb steht sie jetzt hier, beim Menüstandard,
 * und nicht im Editor.
 *
 * **Getragen und nicht flott.** Je Eintrag 0,6 Sekunden, versetzt um
 * 70 Millisekunden; bei elf Einträgen steht alles nach etwa 1,2
 * Sekunden. Das ist langsamer, als eine Bedienbewegung sein müsste, und
 * genau richtig für eine Gedenkseite: hier wird nichts weggeschnappt.
 *
 * Die Kurve ist ein weiches Ausrollen: schnell los, langsam an. Eine
 * Bewegung, die am Ende bremst, sieht aus, als käme sie an; eine
 * gleichmäßige sieht aus, als würde sie abgeschnitten.
 *
 * **Drei Richtungen, weil es drei Bauarten gibt.** Der Wert von
 * `data-fahrt` sagt, welche gilt:
 *
 *   `hoch`            Der Knopf liegt unten, die Einträge stehen in
 *                     Leserichtung — der unterste ist der letzte im
 *                     Dokument und fährt zuerst. Deshalb wird von
 *                     hinten gezählt (`nth-last-child`). So arbeiten
 *                     die Einstellungsleiste und die Listen des
 *                     Editors.
 *   `hoch-gestapelt`  Dasselbe Bild, andere Quelle: der Rundknopf
 *                     stapelt seine Wege mit `column-reverse`, damit
 *                     der erste Weg dem Daumen am nächsten liegt. Dort
 *                     ist der erste im Dokument der unterste, also wird
 *                     von vorn gezählt.
 *   `runter`          Die Rechtspille oben rechts klappt nach unten
 *                     auf. Die Einträge kommen von oben, und der erste
 *                     im Dokument liegt der Pille am nächsten.
 *
 * **Die Staffel geht nur bis zur zehnten Stufe.** Was darüber
 * hinausgeht, fährt mit ihr zusammen — eine Liste mit mehr als zehn
 * Einträgen rollt ohnehin, und eine Staffel, die zwei Sekunden dauert,
 * wäre keine Erklärung mehr, sondern eine Wartezeit.
 */
@keyframes menue-auffahren {
  from {
    opacity: 0;
    transform: translateY(1.1rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes menue-abfahren {
  from {
    opacity: 0;
    transform: translateY(-1.1rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* **Ohne diese Hülle wäre die Bewegung ein Fehler und kein Schmuck.**
   `both` als Füllmodus hält den Anfangszustand fest, und der ist
   durchsichtig: wer Animationen abgeschaltet hat, sähe ein leeres
   Menü. */
@media (prefers-reduced-motion: no-preference) {
  [data-fahrt] > * {
    animation-duration: 0.6s;
    animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
    animation-fill-mode: both;
  }

  [data-fahrt="hoch"] > *,
  [data-fahrt="hoch-gestapelt"] > * {
    animation-name: menue-auffahren;
  }

  [data-fahrt="runter"] > * {
    animation-name: menue-abfahren;
  }

  /* Die Staffel, von hinten gezählt: der Eintrag am Knopf zuerst. */
  [data-fahrt="hoch"] > *:nth-last-child(1) {
    animation-delay: 0s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(2) {
    animation-delay: 0.07s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(3) {
    animation-delay: 0.14s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(4) {
    animation-delay: 0.21s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(5) {
    animation-delay: 0.28s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(6) {
    animation-delay: 0.35s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(7) {
    animation-delay: 0.42s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(8) {
    animation-delay: 0.49s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(9) {
    animation-delay: 0.56s;
  }
  [data-fahrt="hoch"] > *:nth-last-child(n + 10) {
    animation-delay: 0.63s;
  }

  /* Und von vorn gezählt, für den gestapelten Rundknopf und die Pille,
     die nach unten aufklappt. */
  [data-fahrt="hoch-gestapelt"] > *:nth-child(1),
  [data-fahrt="runter"] > *:nth-child(1) {
    animation-delay: 0s;
  }
  [data-fahrt="hoch-gestapelt"] > *:nth-child(2),
  [data-fahrt="runter"] > *:nth-child(2) {
    animation-delay: 0.07s;
  }
  [data-fahrt="hoch-gestapelt"] > *:nth-child(3),
  [data-fahrt="runter"] > *:nth-child(3) {
    animation-delay: 0.14s;
  }
  [data-fahrt="hoch-gestapelt"] > *:nth-child(4),
  [data-fahrt="runter"] > *:nth-child(4) {
    animation-delay: 0.21s;
  }
  [data-fahrt="hoch-gestapelt"] > *:nth-child(5),
  [data-fahrt="runter"] > *:nth-child(5) {
    animation-delay: 0.28s;
  }
  [data-fahrt="hoch-gestapelt"] > *:nth-child(6),
  [data-fahrt="runter"] > *:nth-child(6) {
    animation-delay: 0.35s;
  }
  [data-fahrt="hoch-gestapelt"] > *:nth-child(7),
  [data-fahrt="runter"] > *:nth-child(7) {
    animation-delay: 0.42s;
  }
  [data-fahrt="hoch-gestapelt"] > *:nth-child(n + 8),
  [data-fahrt="runter"] > *:nth-child(n + 8) {
    animation-delay: 0.49s;
  }
}

/* --- Der Stapel unten rechts -----------------------------------------
 *
 * ASCII-BEWUSST: `knopfstapel`, `hauptknopf` und `hauptknopf-wort` sind
 * Klassennamen.
 *
 * **Zwei Knöpfe, ungleich** (Ybug 47). Unten die Hauptaktion, groß und
 * in Akzentfarbe; darüber, kleiner und nur mit einer Kante, das Menü
 * der übrigen Wege. Zwei gleich große Kreise wären zwei Hauptaktionen —
 * und damit eine Entscheidung, die niemand erklärt hat. Die Rangfolge
 * liest man an der Form, nicht an der Beschriftung.
 *
 * Der Stapel liegt an der Stelle, an der vorher der einzelne Knopf lag:
 * eine Handlung, die auf jeder Seite gleich liegt, muss man nicht auf
 * jeder Seite suchen.
 */
.knopfstapel {
  position: fixed;
  right: 0.75rem;
  /* **Über dem Wort im Fuß** (b54). „Neuer Beitrag" wächst als Pille
     nach links bis in die Mitte der Zeile — genau dorthin, wo das
     Impressum steht. Der Stapel rückt deshalb um die Fußhöhe hoch,
     und zwar immer: eine Überlappung, die nur manchmal auftritt, ist
     schwerer zu sehen als eine, die immer da ist. */
  bottom: calc(0.75rem + var(--fuss-hoehe));
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
}

/* --- Die Schwebenden rücken zum Inhalt (Ybug 195) ----------------------
 *
 * **Die Ecke ist der falsche Platz, wenn der Inhalt in der Mitte
 * steht.** Beim Besucher ist die Seite ein Blatt im Hochformat: auf
 * 1680 Punkten Breite lag es zwischen 597 und 1019, der Rundknopf bei
 * 1646 — einen halben Bildschirm daneben, und die Einstellungsleiste
 * ebenso weit auf der anderen Seite. Dieselbe Überlegung wie bei der
 * Führungspille am Beitrag (`.beitrag-buehne`): was etwas bedient,
 * gehört an dessen Kante.
 *
 * **In der Verwaltung bleibt alles, wo es war.** Dort füllen Tabellen
 * den Schirm, und die Ecke *ist* die Kante des Inhalts. Welche Seite
 * des Hauses gerade läuft, sagt die Körperklasse (config/context.py,
 * `koerper_klasse`).
 *
 * **Die Breite des Blattes steht nirgends als Zahl** — sie folgt der
 * Höhe über das Verhältnis 375:667 (`.post-card`). Hier wird sie aus
 * der Fensterhöhe nachgerechnet, ohne Abzug für Verfasserzeile und
 * Abstände: großzügig ist die sichere Richtung, denn ein zu großes Maß
 * schiebt die Knöpfe nach außen, ein zu kleines unter das Blatt.
 * Gemessen auf 1680x949: Blatt im Vollbild 492 Punkte, gerechnet 497.
 *
 * Die 16rem darin fangen die Seiten ohne Blatt auf — Anmeldung, Liste
 * und die Formulare stehen in einer Spalte von 32rem. Das äußere
 * `max()` gilt dem Telefon: dort ist zwischen Blatt und Fensterkante
 * nichts, und es bleibt beim gewöhnlichen Abstand.
 */
body.ist-besucher {
  --blatt-breite: calc(
    (100svh - var(--kopf-hoehe) - var(--fuss-hoehe)) * 375 / 667
  );
  --knopf-seite: max(
    0.75rem,
    calc(50vw - max(16rem, var(--blatt-breite) / 2) - 4.25rem)
  );
}

body.ist-besucher .knopfstapel {
  right: var(--knopf-seite);
}

body.ist-besucher .settings-bar {
  left: var(--knopf-seite);
}

/* Das i über dem Rundknopf ist der schmalere Kreis; der Versatz hält
   die beiden auf derselben Mitte. */
body.ist-besucher .post-info {
  right: calc(var(--knopf-seite) + 0.375rem);
}

/* --- Die Knöpfe der Seite im Editor (Ybug 225, 204) -------------------
 *
 * **Sie stehen dort, und sie stehen über den eigenen.** Der Editor
 * liess sie ganz weg (Ybug 39): unten links und unten rechts sitzen
 * seine eigenen Knöpfe, und die Einstellungsleiste samt Rundknopf lagen
 * genau darunter. Der Befund war richtig, die Lösung zu grob — wer im
 * Editor die Schrift größer stellen oder zur Gedenkseite gehen wollte,
 * musste den Beitrag dafür verlassen.
 *
 * **Gestapelt wie auf der Gedenkseite** (Ybug 204): dort sitzt der
 * kleinere Knopf mit den drei Punkten über dem großen mit dem Plus, an
 * derselben Kante ausgerichtet — schräg darüber, weil er schmaler ist.
 * Genau diese Anordnung gilt hier: links die Einstellungen über dem
 * Menü des Beitrags, rechts die Wege über dem Werkzeugkranz. Ein erster
 * Anlauf stellte sie unter die Kopfzeile; das war ein zweiter Ort für
 * dieselbe Sache.
 *
 * Die Rechnung: 1 rem Abstand des Editorknopfs vom unteren Rand,
 * 3,25 rem seine Höhe, 0,6 rem Luft. Ohne Zuschlag für den Fuß — die
 * Arbeitsfläche des Editors reicht unter ihm hindurch bis an den
 * Fensterboden, ihre Knöpfe rechnen also von derselben Kante wie diese
 * hier. Gemessen auf 315 x 910: Editorknopf ab 842, diese Leiste bis
 * 832.
 */
/* **Und seit Ybug 218 stehen sie darunter statt darüber.** Die Reihe
 * des Editors ist auf 5,6 rem gestiegen; im Streifen darunter liegen
 * jetzt diese beiden und ganz unten das Impressum. Die 2,4 rem sind
 * die Zeile des Impressums plus Luft — gemessen auf 1155x941: der
 * Streifen zwischen Blattkante und Fensterboden ist 101 Punkte hoch,
 * die Leiste steht darin von 38 bis 82.
 *
 * Die Rechnung von Ybug 204 und 225 gilt damit nicht mehr; sie stand
 * hier und ist ersetzt, nicht bloß überschrieben — sonst rechnet sie
 * beim nächsten Umbau jemand nach und findet eine andere Lage vor. */
body.page-editor .settings-bar,
body.page-editor .knopfstapel {
  /* **3,2 rem und nicht 2,4** (Ybug 218, Nachtrag). Mit 2,4 blieben
     neun Punkte zwischen der Unterkante der Knöpfe und dem Wort
     „Impressum" darunter — zu wenig, um es ruhig zu lesen. Jetzt sind
     es 22. */
  bottom: 3.2rem;
}

/* **Das Impressum steht im Editor unten mittig** (Ybug 218). Überall
 * sonst ist der Fuß ein Flexkind am Ende der Seite; hier liegt die
 * Arbeitsfläche als festes Feld darüber, und der Fuß rutschte in den
 * leeren Seitenfluss — auf einem breiten Schirm stand „Impressum"
 * deshalb oben rechts neben dem Blatt, gemessen auf 1155x941 bei 875
 * Punkten über dem Rand.
 *
 * Er weicht hier bewusst von der Regel der übrigen Seiten ab und von
 * der Unterscheidung quer/längs: der Editor hat nur diesen einen Ort
 * dafür. Mittig über die ganze Breite, und weil das Blatt selbst
 * mittig steht, sitzt das Wort damit unter dem Blatt. */
body.page-editor .site-fuss {
  position: fixed;
  left: 0;
  right: 0;
  /* `top: auto` ausdrücklich: eine Regel weiter oben setzt `inset`, und
     mit `top: 0` und `bottom: 0` zugleich spannt sich der Fuß über das
     ganze Fenster — das Wort stand dann in der Bildmitte, gemessen bei
     458 Punkten über dem Rand. */
  top: auto;
  bottom: 0;
  height: auto;
  padding-block: 0.3rem;
}

/* **Und das Menü klappt hier nach oben auf** (Ybug 218). Ab 48 rem
 * schwebt der Fuß sonst oben rechts, und sein Menü geht nach unten —
 * die Regel dafür gilt nach Bildschirmbreite und weiß nichts davon,
 * dass er im Editor unten steht. Gemessen: die Liste begann 31 Punkte
 * unter dem Wort und endete 236 Punkte unter dem Fensterboden, also
 * vollständig ausserhalb.
 *
 * Damit gilt hier wieder, was ohne die Breitenregel ohnehin gälte:
 * nach oben, mittig, und `column-reverse`, damit der erste Weg dem
 * Wort am nächsten liegt. */
body.page-editor .rechtsfuss-liste {
  top: auto;
  bottom: calc(100% + 0.4rem);
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  flex-direction: column-reverse;
}

@media (prefers-reduced-motion: no-preference) {
  /* Die Fahrt kommt dann wieder von unten. */
  body.page-editor .rechtsfuss-liste[data-fahrt="hoch-gestapelt"] > * {
    animation-name: menue-auffahren;
  }
}

/* An derselben Kante wie der Knopf darunter (`.editor-menu-cluster`
   und `.editor-fab-cluster` in frontend/src/editor.css stehen beide
   1 rem vom Rand).
 *
 * **Und das ist die Kante des Blattes, nicht die des Fensters** (Ybug
 * 207). Bis zum 2026-09-14 stand hier `left: 1rem`, und quer stimmte
 * das auch: das Blatt füllt dort die Breite, seine Kante ist die des
 * Fensters. Längs ist es 26 rem breit und steht mittig (`.editor-frame`,
 * `max-width: 26rem` in frontend/src/editor.css) — die beiden Knöpfe
 * blieben aussen am Fenster hängen, gemessen auf 1680x949: der
 * Menüknopf des Editors bei 648, die Einstellungsleiste bei 16. Über
 * 600 Punkte leere Fläche dazwischen, und nichts verband sie mit dem,
 * was sie bedienen.
 *
 * 12 rem ist die halbe Blattbreite abzüglich der 1 rem Abstand. Die 26
 * stehen damit an zwei Stellen; eine gemeinsame Variable ginge nicht,
 * weil die eine Datei gebaut wird und die andere nicht.
 *
 * `max()` statt einer Medienabfrage: unter 26 rem Fensterbreite ist die
 * Rechnung kleiner als 1 rem, und es gilt wieder genau das, was quer
 * schon galt. */
body.page-editor .settings-bar {
  left: max(1rem, calc(50% - 12rem));
}

body.page-editor .knopfstapel {
  right: max(1rem, calc(50% - 12rem));
}

/* **Und sie treten weg, solange ein Blatt des Editors offen steht**
 * (Ybug 216). Das Blatt legt sich über die untere Hälfte der
 * Arbeitsfläche — Text, Grund, Ort, Datum, Musik —, und genau dort
 * liegen diese beiden. Sie standen auf seinen Reglern: der Knopf der
 * Einstellungen auf der Schieberegler-Zeile, der Rundknopf an deren
 * rechtem Ende.
 *
 * **Weg und nicht darunter.** Das Blatt verdunkelt die Fläche hinter
 * sich (`.editor-form-overlay`); ein Knopf, der dort durchscheint, ist
 * weder zu lesen noch zu treffen, lädt aber zum Danebengreifen ein. Und
 * zu bedienen gibt es hier nichts: wer einen Text setzt, wechselt nicht
 * das Theme.
 *
 * **`:has()` und kein Zustand am Körper.** Das Blatt ist ein Element
 * der Insel; ob es steht, weiß das Markup selbst. Ein Schalter, den die
 * Insel zusätzlich am `body` setzen müsste, wäre eine zweite Wahrheit
 * über dieselbe Sache — und die eine, die hängen bleibt, wenn ein
 * Renderpfad sie vergisst.
 *
 * **Und das Impressum tritt mit weg** (Ybug 218, Nachtrag). Seit es
 * unten mittig steht, liegt es unter der Kante des Blattes: das Wort
 * stand halb verdeckt da, oben abgeschnitten. Ein Pflichttext, der zur
 * Hälfte zu lesen ist, ist schlechter als einer, der wartet.
 *
 * **Dass er dabei verschwindet, ist keine Lücke in der Verfügbarkeit.**
 * Das Blatt ist ein Zwischenschritt beim Setzen eines Objekts und
 * schliesst sich mit einem Druck; danach steht das Wort wieder da. Kein
 * Weg der Seite hängt daran, und jedes andere Fenster des Hauses
 * verdeckt es ebenso, solange es offensteht. */
body.page-editor:has(.editor-form-overlay) .settings-bar,
body.page-editor:has(.editor-form-overlay) .knopfstapel,
body.page-editor:has(.editor-form-overlay) .site-fuss {
  display: none;
}


/* **Der Hauptknopf.** Ein Kreis mit dem Plus, aus dem eine Pille
 * herauswächst, solange das Wort gebraucht wird. Kein zweites Format:
 * es ist derselbe Kreis, nur mit Text daneben — deshalb ist die
 * Rundung 999px und die Höhe fest, und die Breite folgt dem Inhalt.
 *
 * Das Plus gehört hierher und nirgendwo sonst: es steht für „einen
 * neuen Beitrag anlegen", und der Auslöser des Menüs daneben trägt
 * deshalb die drei Punkte (Ybug 34, 39). Die Regel ist damit nicht
 * aufgehoben, sie steht nur an der richtigen Stelle. */
.hauptknopf {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 3.5rem;
  padding: 0 1.05rem;
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
  border-radius: 999px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.22);
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}

/* Ohne Wort ist die Pille ein Kreis. Die Breite kommt dann aus der
   Höhe, nicht aus dem Text — sonst bliebe die Polsterung als Oval
   stehen. */
.hauptknopf:not([data-werben]) {
  width: 3.5rem;
  padding: 0;
  justify-content: center;
}

.hauptknopf:not([data-werben]) .hauptknopf-wort {
  display: none;
}

.hauptknopf:hover,
.hauptknopf:focus-visible {
  color: var(--accent-ink, #fff);
  opacity: 0.92;
}

/* Der Auslöser des Menüs ist kleiner als die Hauptaktion und trägt
   keine Fläche: eine Kante auf dem Grund des Hauses. Dieselbe Ordnung
   wie bei den Knöpfen mit Wörtern (`.knopf-haupt`) und bei den
   Handlungen am Beitrag (`.handeln-knopf`). */
.fab-toggle {
  width: 2.6rem;
  height: 2.6rem;
  background: var(--paper, #fff);
  color: var(--ink, #1b1b1b);
  border: 1px solid var(--line, #d9d9d9);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1);
}

/* Aufgeklappt kehrt er die Farben um — dasselbe Signal wie vorher, nur
   in die andere Richtung, weil der geschlossene Knopf jetzt hell ist. */
.fab[open] .fab-toggle {
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
  border-color: var(--accent, #2f5d62);
}

/* Der Aufklapper selbst braucht keine eigene Verankerung mehr — er
   sitzt im Stapel. Relativ bleibt er, weil die Einträge darüber
   absolut an ihm hängen. */
.fab {
  position: relative;
}

/* Das Dreieck, das der Browser einem `<summary>` voranstellt, gehört zu
   einer Aufklappzeile und nicht zu einem runden Knopf. */
.fab-toggle {
  list-style: none;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.fab-toggle::-webkit-details-marker,
.fab-toggle::marker {
  display: none;
  content: "";
}

@media (prefers-reduced-motion: no-preference) {
  .fab-toggle {
    transition: background-color 0.15s ease, color 0.15s ease;
  }
}

/* Die gestapelten Kreise stehen **über** dem Knopf und nehmen dem
   Inhalt darunter keinen Platz: absolut positioniert, von unten her
   gestapelt, damit der erste Eintrag der ist, der dem Daumen am
   nächsten liegt. */
.fab-actions {
  position: absolute;
  right: 0;
  bottom: 3.1rem;
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-end;
  gap: 0.6rem;
}

/* Die Einträge selbst tragen `.menue-option` — die Form steht weiter
   oben in dieser Datei und gilt für jedes Menü im Haus. Hier bleibt
   nur, was am Rundknopf anders ist: die Einträge richten sich an
   seinem rechten Rand aus. */
.fab-actions .menue-option {
  align-self: stretch;
}

/* --- Die Rückfrage vor einer Meldung -----------------------------------
 *
 * Melden ist nicht rückgängig zu machen und geht an Menschen, die
 * gerade trauern. Ein Fehlgriff mit dem Daumen soll deshalb nicht schon
 * die Meldung sein (Ybug 4).
 *
 * `<dialog>` und kein nachgebauter Kasten: Fokusfalle, Escape und die
 * Rolle bringt der Browser mit. Ohne Skript wird das Formular direkt
 * abgeschickt — die Rückfrage ist eine Sicherung, kein Tor.
 */
.rueckfrage {
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 10px;
  padding: 1.25rem;
  max-width: min(24rem, calc(100vw - 2rem));
  background: var(--paper, #fff);
  color: var(--ink, #1b1b1b);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
}

.rueckfrage::backdrop {
  background: rgba(0, 0, 0, 0.4);
}

.rueckfrage h2 {
  margin: 0 0 0.5rem;
  font-size: 1.1rem;
}

.rueckfrage p {
  margin: 0 0 1.25rem;
}

.rueckfrage-knoepfe {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  justify-content: flex-end;
}

/* Der abratende Knopf trägt keine Fläche: was hier zurückführt, soll
   nicht wie die Hauptsache aussehen, und was meldet, nicht wie ein
   Versehen. */
.rueckfrage-abbrechen {
  background: none;
  border: 1px solid var(--line, #d9d9d9);
  color: var(--ink, #1b1b1b);
}

/* **Der Leerzustand des Feeds** (b27). Er war ein Satz auf halber
   Höhe, ohne Rahmen und ohne Angebot — er sah aus wie ein Beitrag, der
   nicht geladen hat.

   Jetzt steht er mittig in einer Fläche, die so hoch ist wie ein
   Beitrag, mit dem Zeichen der Seite darüber: er nimmt den Platz ein,
   an dem sonst etwas stünde. Ohne Kante und ohne Grund — was hier
   fehlt, soll ruhig fehlen und nicht als Kasten dastehen. Der Weg zum
   Schreiben liegt im Knopf unten rechts (config/wege.py, `haupttat`). */
.feed-leer {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
  min-height: 12rem;
  padding: 1.5rem;
  text-align: center;
  color: var(--muted, #5c584f);
}

.feed-leer p {
  margin: 0;
  max-width: 22rem;
}

/* **Wer die Nachricht liest, mit Namen** (b31, templates/contact/
   send_message.html). Eine Liste und kein Satz mit Kommas: sie liest
   sich schneller und trägt drei Namen so gut wie zehn. Ohne Punkte —
   es ist eine Aufzählung von Menschen und keine Aufgabenliste. */
.verwalterliste {
  list-style: none;
  margin: 0.35rem 0 1.25rem;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.1rem;
  color: var(--ink, #1b1b1b);
}

/* **Die Runde ist eine Wahl und kein Satz** (b33). Ein Feldrahmen und
   keine Kante: die Frage steht als `<legend>` darueber, und ein Kasten
   um drei Namen waere ein Rahmen um das, was ohnehin zusammensteht. */
.verwalterwahl {
  margin: 0 0 1rem;
  padding: 0;
  border: none;
}

.verwalterwahl > legend {
  padding: 0;
  margin-bottom: 0.15rem;
  font-weight: 600;
  color: var(--ink, #1b1b1b);
}

/* Das Kaestchen gehoert zum Namen und nicht in eine eigene Spalte: das
   ganze Stueck ist der Anfasser, auch das Beziehungswort daneben.
   Beruehrziel nach WCAG 2.5.8 — die Seite wird am Telefon bedient. */
.verwalterwahl-zeile {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 2.5rem;
  cursor: pointer;
}

/* **Die Empfaenger in der Verwaltungstabelle** (b35). Untereinander
   und nicht mit Komma: in einer Zelle von 16 Prozent bricht ein Satz
   mit Kommas an der falschen Stelle um, und drei Namen lesen sich
   ohnehin als Liste. */
.empfaengerliste {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* --- Die Textliste ----------------------------------------------------
 *
 * Die barrierefreie Fassung des Feeds: chronologisch, als Text, mit der
 * Tastatur zu bedienen.
 */
/* **Sie ist die Überschrift der Seite** (b24). Darüber stand bis zum
   2026-09-13 der Name des Verstorbenen, und der steht schon in der
   Adresse in der Kopfzeile. Was bleibt, sagt, was diese Seite ist —
   also ist es die Überschrift und kein Zusatz zu ihr.

   Sie trägt trotzdem kein Überschriftengewicht: die Beiträge sind der
   Inhalt, und eine Ansage in Versalhöhe über einer Liste von
   Erinnerungen wäre lauter als alles darunter. Größe und Farbe bleiben
   die des Satzes, der sie vorher war. */
.list-lead {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1rem;
  font-size: 1rem;
  font-weight: 400;
  color: var(--muted, #5c584f);
}

/* **Karten statt einer nummerierten Aufzählung.** Die Zahlen davor
 * lasen sich als Rangfolge, die es nicht gibt (Ybug 7). Dezent heißt
 * hier: eine Linie und Luft, keine Fläche und kein Schatten — die
 * Beiträge sollen sich voneinander abheben, nicht von der Seite. */
.post-list {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.post-list-item {
  padding: 1rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 10px;
}

.post-list-who {
  margin: 0 0 0.4rem;
  font-weight: 600;
}

/* **Der Weg ins Vollbild, mit Zeichen** (Ybug 48). Der Link trug hier
   keines seiner beiden Merkmale: die Überschrift ist ohnehin fett, und
   die Akzentfarbe steht in einigen Themes nur einen Hauch neben der
   Textfarbe (#8a4a2f gegen #3a2418, gemessen am 2026-09-08). Die Lupe
   dahinter ist das, was ihn erkennbar macht — dasselbe Zeichen wie in
   der Führung am Beitrag.

   Ein Abstand davor, und kein Umbruch dazwischen: das Zeichen gehört
   zum Satz und soll nicht allein in der nächsten Zeile stehen. */
.post-list-weg {
  white-space: normal;
}

/* **Ein Wort, das ein Weg ist, trägt sein Zeichen** (Ybug 48, b60).
   Dieses Haus unterstreicht keinen Link (Ybug 2), und die Akzentfarbe
   liegt in manchem Theme nur einen Hauch neben der Textfarbe — beide
   Merkmale, an denen man einen Link erkennt, fallen damit weg. Das
   Zeichen ist das dritte, und es trägt allein.

   `.weg-wort` steht neben `.post-list-weg`, weil beide dasselbe meinen:
   das eine in einer Karte, das andere in einer Tabellenzelle. */
.post-list-weg .icon,
.weg-wort .icon {
  margin-left: 0.35rem;
  vertical-align: -0.1em;
}

.post-list-text {
  white-space: normal;
}

.post-list-when {
  margin: 0.5rem 0 0;
  color: var(--muted, #5c584f);
}

/* --- Die Verwaltung: breite Seite, echte Tabellen ----------------------
 *
 * **Warum sie breiter ist als der Rest.** `main.page` misst 32 rem —
 * richtig für einen Beitrag, den jemand liest, falsch für eine Tabelle
 * mit neun Spalten. Die Beitragstabelle stand darin auf 512 Punkten und
 * schob ihre Knöpfe in schmale Säulen; die Breite daneben blieb leer
 * (Ybug 10).
 *
 * 74 rem und nicht `none`: eine Tabelle, die über einen breiten Schirm
 * läuft, zwingt den Blick von der ersten Spalte bis zur letzten quer
 * über den ganzen Tisch, und die Zeile darunter findet dann niemand
 * mehr.
 */
.page-breit {
  max-width: 74rem;
}

/* Ein Formular bleibt schmal, auch auf einer breiten Seite. */
.form-schmal {
  max-width: 32rem;
}

/* Die Filterleiste über einer Tabelle. Sie steht zwischen Überschrift
   und Tabelle — nach dem, was hier steht, und vor dem, wovon sie einen
   Teil zeigt. */
.admin-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.9rem;
  margin-bottom: 1rem;
  font-size: 0.9rem;
}

.admin-filter a {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 24px;
  padding: 0.15rem 0.6rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  color: var(--muted, #5c584f);
}

/* Die Anzahl hinter dem Namen. Leiser als er: sie ist die Beigabe, der
   Name ist der Weg (Ybug 35). */
.admin-filter-zahl {
  opacity: 0.7;
  font-variant-numeric: tabular-nums;
}

.admin-filter a:hover {
  color: var(--ink, #1b1b1b);
}

/* Die gewählte Sicht trägt Fläche, nicht nur Farbe: welcher Ausschnitt
   gerade gilt, muss auf einen Blick zu sehen sein — sonst sucht jemand
   eine Zeile, die es in dieser Sicht gar nicht gibt. */
.admin-filter a[aria-current="true"] {
  background: var(--accent, #2f5d62);
  border-color: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
}

/* --- Das Suchfeld über einer Tabelle ---------------------------------
 *
 * Es steht, wo sonst die Filterleiste steht, und aus demselben Grund:
 * es bestimmt, welche Zeilen darunter stehen. Die Zustimmungstabelle
 * hat keine Sichten — dort ist die Suche das einzige Werkzeug, und
 * deshalb sieht sie auch wie eines aus und nicht wie ein Feld, das
 * zurücktritt (anders als das Titelfeld in einer Zelle).
 *
 * Die Breite ist begrenzt: ein Feld über die ganze Tabellenbreite
 * verspricht einen Satz, wo zwei Wörter hingehören. */
.tabelle-suche {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.tabelle-suche input[type="search"] {
  flex: 1 1 14rem;
  max-width: 24rem;
  width: auto;
  padding: 0.3rem 0.5rem;
  font: inherit;
  font-size: 0.9rem;
}

.tabelle-suche button {
  padding: 0.3rem 0.8rem;
  font: inherit;
  font-size: 0.9rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  background: none;
  color: var(--muted, #5c584f);
  cursor: pointer;
}

.tabelle-suche button:hover {
  border-color: var(--accent, #2f5d62);
  color: var(--ink, #1b1b1b);
}

.tabelle-suche a {
  font-size: 0.85rem;
  color: var(--muted, #5c584f);
}

.tabelle-suche-weg {
  margin-left: auto;
}

/* Der gekürzte Fingerabdruck in der Zelle. Feste Zeichenbreite, damit
   sich zwei Zeilen untereinander vergleichen lassen, ohne sie zu
   lesen — genau dafür steht er da. */
.zelle-abdruck {
  font-size: 0.85em;
  letter-spacing: 0.02em;
}

/* --- Der Beleg einer Zustimmung --------------------------------------
 *
 * Die Angaben oben als Definitionsliste: links die Sorte, rechts der
 * Wert. Sie sind der Kopf des Belegs und stehen deshalb enger und
 * leiser als der Vertragstext darunter, der die Hauptsache ist. */
.beleg-angaben {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.2rem 0.8rem;
  margin: 0 0 1.5rem;
  font-size: 0.9rem;
}

.beleg-angaben dt {
  color: var(--muted, #5c584f);
}

.beleg-angaben dd {
  margin: 0;
}

/* Der Fingerabdruck ist 64 Zeichen lang und muss auf ein Telefon
   passen: er bricht überall um, statt die Spalte zu sprengen. */
.beleg-abdruck {
  font-size: 0.8em;
  overflow-wrap: anywhere;
}

/* Der gespeicherte Text setzt sich vom Kopf ab — eine Kante links,
   damit sichtbar bleibt, wo der Beleg aufhört und das Zitat anfängt. */
.beleg-text {
  border-left: 2px solid var(--line, #d9d9d9);
  padding-left: 1rem;
}

/* Die vier Rechtstexte stehen im Beleg hintereinander, jeder mit
   seiner eigenen Überschrift. Eine leise Kante zwischen ihnen sagt, wo
   der nächste anfängt — vier `h1` in Folge sähen sonst aus wie ein
   Text mit vier Kapiteln. */
.beleg-text .beleg-recht + .beleg-recht {
  border-top: 1px dashed var(--line, #d9d9d9);
  margin-top: 2rem;
  padding-top: 2rem;
}

/* Auf der Seite mit allen Texten steht einer unter dem anderen. Die
   Trennlinie darüber sagt, wo der nächste anfängt — bei drei Fassungen
   hintereinander sieht man sonst eine lange Wand. */
.beleg-fassung + .beleg-fassung {
  border-top: 1px solid var(--line, #d9d9d9);
  padding-top: 2rem;
  margin-top: 2rem;
}

/* Zahlen rechtsbündig: so stehen die Stellen untereinander und lassen
   sich vergleichen, ohne sie zu lesen. */
.spalte-zahl {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Das Titelfeld mit Direktspeicherung. Feld und Knopf in einer Zeile,
   und der Stand daneben — „Speichert …" erscheint dort für einen
   Moment, das Ergebnis sagt der Toast (static/verwaltung.js). */
.admin-titel-form,
.beziehung-wort-form {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* **Zeichen und Wort der Beziehung stehen nebeneinander** (Ybug 73).
   Sie standen untereinander: das Wort las sich als eigene Angabe unter
   dem Zeichen statt als seine zweite Hälfte, und die Zeile wurde
   doppelt so hoch wie jede andere der Tabelle.

   `min-width: 0` am Formular, sonst unterschreitet es die
   Mindestbreite seines Feldes nicht und drückt die Nachbarspalte weg —
   dieselbe Sperre wie bei `.inline-wahl select`. */
.beziehung-reihe {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.beziehung-reihe .beziehung-wort-form {
  min-width: 0;
}

/* --- Ein Feld, das in einer Tabelle steht ----------------------------
 *
 * **Es tritt zurück, bis man es anfasst** (2026-09-07). Die allgemeine
 * Feldregel gibt jedem `input` einen weißen Grund, einen vollen Rahmen
 * und volle Breite — richtig für ein Formular, falsch in einer Zelle:
 * das Titelfeld war der auffälligste Gegenstand der ganzen Karte,
 * obwohl es die nachrangigste Angabe darin trägt. Ein weißer Kasten
 * neben grauem Text liest sich als das Wichtigste.
 *
 * Im Ruhezustand ist es deshalb ein Text mit einer leisen Kante
 * darunter. Beim Hovern zeigt sich, dass es ein Feld ist; im Fokus
 * wird es eines, mit Rahmen und Grund. Dieselbe Form für jedes Feld,
 * das direkt in einer Tabelle oder Karte steht — die Nutzertabelle
 * bekommt eines für den Lebensbereich (Ybug 36).
 */
.admin-titel-form input[type="text"],
.beziehung-wort-form input[type="text"] {
  min-width: 6rem;
  padding: 0.25rem 0.35rem;
  background: none;
  border: none;
  border-bottom: 1px dashed var(--line, #d9d9d9);
  border-radius: 0;
  color: var(--ink, #1b1b1b);
}

.admin-titel-form input[type="text"]::placeholder,
.beziehung-wort-form input[type="text"]::placeholder {
  color: var(--muted, #5c584f);
  opacity: 0.7;
  font-style: italic;
}

.admin-titel-form input[type="text"]:hover,
.beziehung-wort-form input[type="text"]:hover {
  border-bottom-color: var(--accent, #2f5d62);
}

/* **Im Fokus wächst es über die Spalte** (Ybug 101). Ein
   Beziehungswort oder ein Titel ist länger als die Zelle, in der er
   steht; wer ihn ändert, hatte ein Feld von sechs Zeichen vor sich
   und musste darin scrollen. Die Spalte breiter zu machen ginge zu
   Lasten aller Zeilen, in denen dasselbe Wort nur gelesen wird.

   Das Formular behält seine gemessene Größe als Platzhalter
   (static/verwaltung.js setzt sie), das Feld legt sich als eigene
   Fläche darüber — mittig, nach beiden Seiten. Die Zeile bleibt
   dabei, wo sie ist; nichts rutscht.

   Auf einer Karte (unter 72 rem) gilt die Regel nicht: dort hat das
   Feld ohnehin die ganze Breite. */
@media (min-width: 72rem) {
  .feld-weit {
    position: relative;
  }

  .feld-weit input[type="text"] {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: max(100%, 22rem);
    max-width: 60vw;
    z-index: 20;
    background: var(--paper, #fff);
    box-shadow: 0 2px 10px rgb(0 0 0 / 18%);
  }
}

/* Im Fokus ist es ein Feld: voller Rahmen, Papiergrund. Der Fokusring
   kommt aus der gemeinsamen Regel weiter oben und bleibt. */
.admin-titel-form input[type="text"]:focus,
.beziehung-wort-form input[type="text"]:focus {
  background: var(--paper, #fff);
  border: 1px solid var(--accent, #2f5d62);
  border-radius: 4px;
}

.admin-titel-stand {
  font-size: 0.8rem;
  color: var(--muted, #5c584f);
  white-space: nowrap;
}

/* **`.knopf-haupt` gibt es nicht mehr** (b79). Sie sagte „nur eine
   Kante, keine Fläche" — und genau das ist seit dem 2026-09-13 die
   Grundform jedes Knopfes (siehe „Die Konvention für Aktionsknöpfe"
   weiter oben). Eine Klasse, die die Vorgabe wiederholt, ist eine
   Klasse, die nichts tut; betont wird jetzt mit `.knopf-haupt`, und
   wer nichts sagt, ist leise. */

/* --- Die Vorschau in einer Tabellenzeile -------------------------------
 *
 * **Ohne sie stand in der Tabelle nur, von wem der Beitrag ist** — und
 * danach lässt sich nicht entscheiden, ob er freigegeben wird (Ybug 10).
 *
 * Ein `<details>`: ohne Skript klappt der Text in der Zelle auf, mit
 * Skript hebt static/verwaltung.js ihn in einen Dialog über der Seite.
 * Derselbe Inhalt, nur die bessere Form, wenn ein Skript da ist.
 */
/* Ohne das Dreieck des Browsers: in einer Tabellenzelle liest es sich
   als Sortierpfeil, und die Zeile wird dadurch nur unruhig. Was hier
   steht, ist ein Weg zum Inhalt — also sieht es aus wie einer. */
/* **`:not(.handeln-knopf)`, weil ein Handlungsknopf wie einer aussieht,
   gleich aus welchem Tag er gemacht ist** (b62). In der Handlungsspalte
   stehen drei Wege nebeneinander — Ansehen, Bearbeiten, Löschen —, und
   sie sind ein `<summary>`, ein `<a>` und ein `<button>`. Alle drei
   tragen `.handeln-knopf`; diese Regel hier schlug ihn beim ersten
   trotzdem, weil sie später steht und ein Tag im Selektor mehr wiegt
   als eine Klasse allein. Gemessen am 2026-09-13 in der Kartenform:
   „Im Vollbild ansehen" 24 Punkte hoch und in der Akzentfarbe, die
   beiden daneben 32 Punkte hoch und in der Textfarbe.

   Zurückgesetzt wird nichts — das wäre dieselbe Zahl ein zweites Mal.
   Die Regel gilt einfach nur dort, wo sie gemeint ist: an einem
   Aufklapper, der ein Wort im Fließtext ist. */
.vorschau > summary:not(.handeln-knopf) {
  cursor: pointer;
  color: var(--accent, #2f5d62);
  font-weight: 600;
  list-style: none;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

.vorschau > summary::-webkit-details-marker,
.vorschau > summary::marker {
  display: none;
  content: "";
}

.vorschau > summary:not(.handeln-knopf):hover {
  color: var(--muted, #5c584f);
  color: color-mix(in srgb, var(--accent, #2f5d62) 55%, var(--muted, #5c584f));
}

.vorschau-inhalt {
  margin-top: 0.5rem;
  padding: 0.75rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 8px;
  background: var(--surface, #f0ede7);
  max-width: 28rem;
}

.vorschau-kopf {
  margin: 0 0 0.5rem;
  font-size: 0.85rem;
  color: var(--muted, #5c584f);
}

.vorschau-text {
  white-space: normal;
}

/* Im Dialog braucht der Inhalt keinen zweiten Kasten — der Dialog ist
   schon einer. */
.vorschau-dialog .vorschau-inhalt {
  margin-top: 0;
  /* Abstand zu den Knöpfen darunter — ohne ihn schiebt sich der
     Schließen-Knopf in die letzte Textzeile. */
  margin-bottom: 1.25rem;
  border: none;
  background: none;
  padding: 0;
  max-width: none;
}

/* **Das Fenster rollt nicht** (Ybug 64). Es rollte, und damit stand der
   Knopf „Schließen" unter dem Rand: wer eine Vorschau ansah, musste
   erst scrollen, um sie wieder zuzumachen. Eine Vorschau ist ein Blick
   und keine Seite.
 *
 * Statt zu rollen, wird die Fläche kleiner. Der Beitrag hat ein festes
 * Verhältnis (375 zu 667); im Fenster gibt die Höhe das Maß, und die
 * Breite folgt daraus. Was übrig bleibt, ist Rand.
 *
 * `[open]` am Selektor, weil hier ein `display` steht — der Grund
 * dafür steht am Anfang dieser Datei und bei `.recht-karte`. */
.vorschau-dialog {
  width: min(34rem, calc(100vw - 2rem));
  max-height: 90dvh;
}

.vorschau-dialog[open] {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Die Fläche nimmt, was übrig ist, und gibt nichts weiter: `min-height`
   ist der Zusatz, ohne den ein Flex-Kind seine Inhaltsgröße nicht
   unterschreitet und den Knopf darunter hinausdrängt. */
.vorschau-dialog [data-vorschau-ziel] {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
}

/* **Das Log rollt, die Vorschau nicht** (Ybug 72). Beide liegen im
   selben Fenster, aber sie sind nicht dieselbe Sache: die Vorschau ist
   ein Blick auf eine Fläche, die als Ganzes kleiner werden kann; das
   Log ist eine Liste, die mit jedem Eintrag länger wird. Sie lässt sich
   nicht kleiner rechnen, und ohne diese Regel hing sie an der Regel für
   die Vorschau vorbei: das Ziel wuchs über die 90 dvh des Fensters
   hinaus, `overflow: hidden` am Fenster schnitt ab, und die untersten
   Einträge samt Schreibfeld waren nicht mehr erreichbar.

   `min-height: 0`, sonst unterschreitet das Flex-Kind seine
   Inhaltsgröße nicht und drängt den Schließen-Knopf hinaus. */
.vorschau-dialog [data-log-ziel] {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* **Und das Fenster hat eine feste Höhe** (Ybug 130). Es hatte nur
   eine Obergrenze, also richtete es sich nach der Zahl der Einträge:
   bei zweien ein Streifen mit einem Schreibfeld, bei zwölfen ein
   Fenster über den halben Schirm. Wer die Tabelle durchgeht und ein
   Log nach dem anderen aufmacht, bekommt bei jedem eine andere
   Gestalt — und der Knopf „Schließen“ steht jedes Mal woanders.

   Die Höhe gilt nur, wo ein Log darin liegt: die Vorschau daneben
   zeigt einen Beitrag mit festem Verhältnis, und der soll weiter die
   Höhe bestimmen (Ybug 64).

   `dvh` und nicht `vh`: auf einem Telefon wandert die Adresszeile,
   und mit `vh` wüchse das Fenster beim Rollen über den Schirm. */
.vorschau-dialog:has([data-log-ziel])[open] {
  height: min(32rem, 90dvh);
}

/* Der Beitrag bemisst sich im Fenster an der Höhe: seine Breite fällt
   aus dem Verhältnis, und er steht mittig. Ohne `width: auto` gälte die
   Breite des Fensters, und die Höhe liefe darüber hinaus.
 *
 * **Gerechnet wird über die Breite und nicht über die Höhe.** Zwei
 * Versuche davor gingen schief, und beide aus demselben Grund: das
 * Verhältnis rückwärts zu lesen. `height: 100%` fiel auf null zusammen
 * — die Höhe des Fensters richtet sich nach seinem Inhalt, und der
 * Inhalt richtete sich nach der Höhe des Fensters. `height: 70dvh` mit
 * `width: auto` gab eine Fläche von 0 zu 490 Punkten: ein Flexkind mit
 * `margin: 0 auto` streckt sich nicht, und die Breite aus dem
 * Verhältnis kam nicht. Beides gemessen am 2026-09-08.
 *
 * Jetzt steht die Breite da, und `aspect-ratio` macht daraus die Höhe
 * — die Richtung, für die es gedacht ist. Die Breite ist die kleinere
 * von zwei Angaben: was das Fenster hergibt, und was bei 70 Prozent
 * Fensterhöhe noch hineinpasst (375 zu 667, dieselben Zahlen wie das
 * viewBox in config/canvas.py). Die 30 Prozent Rest tragen die Zeile
 * darüber und den Knopf darunter.
 *
 * **Und das Maß sitzt an `.post-card` und nicht an der Fläche darin.**
 * Die Karte ist die Hülle, die der Feed mitbringt: sie trägt das
 * Verhältnis, und `flex: 1 1 0` holt ihre Höhe dort aus einer Spalte
 * mit fester Höhe. Im Fenster gibt es die nicht — die Basis 0 machte
 * daraus null, und die Fläche darin folgte mit 100 Prozent von null.
 * Auch das gemessen, am dritten Versuch. */
.vorschau-dialog .post-card {
  flex: 0 0 auto;
  width: min(100%, calc(70dvh * 375 / 667));
  height: auto;
  margin: 0 auto;
}

/* Der Knopf bleibt, wo er ist. */
.vorschau-dialog .rueckfrage-knoepfe {
  flex: none;
}

/* --- Was die Verwaltung im Vorschaufenster sonst noch sieht
 *     (Ybug 167, 181)
 *
 * Das Fenster zeigte das Blatt und sonst nichts; wer entschied, musste
 * für die Beschreibung und die Prüfung zurück in die Zeile.
 *
 * **Das Blatt bleibt trotzdem das Vollbild.** Der erste Versuch stellte
 * die Texte ausgeschrieben darunter — und schob die Fläche auf
 * Briefmarkengrösse zusammen (Ybug 181). Jetzt steht eine Pille an der
 * rechten Seite: fünf Zeichen, drei davon zeigen ihren Wert auf Klick
 * (static/hinweise.js, `data-titel-fest`).
 *
 * Die Bühne ist der Bezugsrahmen: das Blatt in der Mitte, die Pille
 * daneben, und beides zusammen so breit wie vorher das Blatt allein. */
.flaeche-buehne {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 0;
}

/* Das Blatt lässt der Pille ihren Platz. Ohne diese Zeile rechnete es
   weiter mit der vollen Breite des Fensters (`.vorschau-dialog
   .post-card`), und die Pille stünde über dem Rand. */
.vorschau-dialog .flaeche-buehne .post-card {
  width: min(calc(100% - 3.4rem), calc(70dvh * 375 / 667));
}

/* Senkrecht, rechts vom Blatt, und sie trägt den Grund des Hauses und
   nicht den des Beitrags: sie gehört zum Fenster, nicht zur Fläche. */
.flaeche-pille {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.35rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  background: var(--surface, #f0ede7);
}

.flaeche-marke {
  width: 2.1rem;
  height: 2.1rem;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 999px;
  background: none;
  color: var(--ink, #1b1b1b);
  cursor: pointer;
}

.flaeche-marke:hover,
.flaeche-marke:focus-visible {
  background: color-mix(in srgb, var(--ink) 10%, transparent);
}

/* Ein Fund wiegt: dieselbe Rechnung wie bei der Zahlmarke in der
   Tabelle — Fläche aus der Textfarbe mit acht Prozent Deckung, keine
   Alarmfarbe. Das Modell hat einen Verdacht, kein Urteil. */
.flaeche-marke-fund {
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}

/* Was nicht gelaufen ist, bleibt blass — wie die leere Zahlmarke
   nebenan. Der Knopf bleibt trotzdem ein Knopf: die Blase sagt dann,
   dass nichts dahintersteht, und das ist auch eine Auskunft. */
.flaeche-marke-leer {
  opacity: 0.55;
}

/* **Der Ausgang steht unten und abgesetzt** (Ybug 191). Die fünf
   Zeichen darüber sagen etwas über den Beitrag oder nehmen ihn mit;
   dieses hier verlässt die Seite. Eine dünne Linie sagt den
   Unterschied, ohne die Pille zu teilen. */
.flaeche-marke-zu {
  margin-top: 0.15rem;
  padding-top: 0.45rem;
  border-top: 1px solid var(--line, #d9d9d9);
  border-radius: 0 0 999px 999px;
  height: 2.55rem;
}

.flaeche-ungeprueft {
  margin: 0.5rem 0 0;
  font-size: 0.85rem;
  color: var(--muted, #5c584f);
  text-align: center;
}

/* Die Wahl des Kalenders — ein Fenster im Fenster (Ybug 94). Es trägt
   die Form der Rückfrage und darin den Menüstandard; die Breite ist
   die der Karte darunter, damit der Sprung kein Sprung ist. */
.kalender-wahl {
  width: min(22rem, calc(100vw - 3rem));
}

.kalender-wahl .marken-titel {
  margin-bottom: 0.75rem;
}

.kalender-wahl .menue-optionen {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

/* Die Einträge nehmen die Breite des Fensters. Der Standard gibt
   ihnen 13 rem, weil sie sonst frei über einer Seite schweben; hier
   stehen sie in einem Kasten, und eine Unterschrift, die auf halber
   Strecke abbricht, sagt weniger als keine. */
.kalender-wahl .menue-option {
  width: auto;
  max-width: none;
}

/* --- Die Anmeldeseite eines Falls -------------------------------------
 *
 * **Wer hier ankommt, soll wissen, bei wem er klingelt** (Ybug 108).
 * Über dem Formular steht ein Satz der Verwaltung, darunter die
 * Menschen, die diese Seite führen — Vorname, Zeichen, Wort.
 *
 * Keine Aufzählungspunkte: es ist eine Vorstellung und keine Liste von
 * Bedingungen. Jede Zeile trägt ihre drei Stücke in einer Reihe, damit
 * das Zeichen zwischen Namen und Wort steht und nicht darunter.
 */
.anmeldung-gruss {
  max-width: 34rem;
}

.anmeldung-runde-kopf {
  margin-bottom: 0.3rem;
  color: var(--muted, #5c584f);
}

.anmeldung-runde {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.anmeldung-runde li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.anmeldung-runde-name {
  font-weight: 600;
}

.anmeldung-runde-wort {
  color: var(--muted, #5c584f);
}
/* --- Das Vollbild der Verwaltung ---------------------------------------
 *
 * **Dieselbe Fläche, dieselbe Größe** (Ybug 92). Der Knopf heißt „Im
 * Vollbild ansehen", zeigte aber ein Blatt auf 70 Prozent der
 * Fensterhöhe: gemessen am 2026-09-12 auf 1400x950 waren es 342x608
 * gegen 461x819 auf der Beitragsseite des Besuchers — ein Viertel
 * kleiner bei gleichem Inhalt.
 *
 * **Die feste Höhe ist der ganze Trick.** Die Regel darüber rechnet die
 * Breite aus 70dvh, weil das Fenster seine Höhe sonst aus seinem Inhalt
 * nimmt und der Inhalt aus dem Fenster — ein Kreis, der auf null
 * zusammenfällt (drei gemessene Versuche stehen darüber). Mit einer
 * festen Höhe am Fenster gibt es den Kreis nicht mehr: das Ziel bekommt
 * eine definite Höhe, und die Karte leitet daraus über ihr Verhältnis
 * die Breite ab — genau die Mechanik der Bühne auf der Beitragsseite
 * (.beitrag-buehne).
 *
 * Nur der Vorschau-Dialog der Beitragstabelle trägt die Klasse. Das Log
 * im selben Kasten ist eine Liste, die rollt, und die Nachrichten der
 * Verwaltung sind Text.
 */
.vorschau-dialog.beitrag-vollbild {
  /* **Das Fenster nimmt den Schirm, das Blatt steht mittig darin** —
     dieselbe Anordnung wie auf der Beitragsseite, wo links und rechts
     des Blattes ebenfalls Seite steht. Ein Fenster, das sich um das
     Blatt legt, ginge nicht: seine Breite käme dann aus dem Inhalt und
     die Breite des Inhalts aus dem Fenster — gemessen am 2026-09-12,
     das Verhältnis fiel dabei von 0,562 auf 0,461.

     Breite und max-width beide: das max-width aus .rueckfrage sind 24
     rem und galten einer Rückfrage mit zwei Sätzen. */
  width: calc(100vw - 2rem);
  max-width: calc(100vw - 2rem);
  height: 96dvh;
  max-height: 96dvh;
}

.vorschau-dialog.beitrag-vollbild [data-vorschau-ziel] {
  flex: 1 1 0;
}

/* **Die definite Höhe sitzt an der Bühne und nicht mehr an der Karte**
   (Ybug 205). Sie sass an der Karte, solange die Karte allein im
   Fenster stand; seit die Pille daneben steht (Ybug 167), ist die
   Bühne dazwischen — eine Reihe. Und `flex: 1 1 0` heisst in einer
   Reihe Breite: die Karte nahm die ganze Fensterbreite, das
   Verhältnis machte daraus die Höhe, und die war gemessen am
   2026-09-14 auf 1680x949 genau 2759 Punkte hoch bei 780 Punkten
   Platz. Zu sehen war ein Streifen aus der Mitte, oben und unten
   abgeschnitten.

   Dieselbe Mechanik wie auf der Beitragsseite des Besuchers
   (.beitrag-buehne, eine Ebene höher dieselbe Falle): die Bühne holt
   sich die Höhe aus der Spalte, die Karte nimmt die Höhe der Bühne,
   und die Breite fällt aus dem Verhältnis. `flex: 0 1 auto` statt
   `1 1 0` ist der Kern — eine Karte, die sich in die Breite der Bühne
   streckt, kann ihre Breite nicht mehr aus der Höhe ableiten.

   `max-width` ist das Netz für ein schmales, hohes Fenster: dort wäre
   die aus der Höhe gerechnete Breite grösser als der Platz neben der
   Pille. Gemessen: 438x780 bei 1680x949, Verhältnis 0,562 — genau das
   viewBox der Fläche. */
.vorschau-dialog.beitrag-vollbild .flaeche-buehne {
  flex: 1 1 0;
  min-height: 0;
}

.vorschau-dialog.beitrag-vollbild .post-card {
  flex: 0 1 auto;
  min-height: 0;
  width: auto;
  height: 100%;
  max-width: calc(100% - 3.4rem);
  align-self: center;
}

/* Quer ist die Reihe keine Reihe mehr — dieselbe Auflösung wie auf der
   Beitragsseite (`.beitrag-buehne` unter 48 rem). Die Pille hat neben
   einem Blatt, das schon die ganze Breite braucht, keinen Platz mehr;
   sie legt sich darunter und dreht sich dabei in die Waagerechte.
   Ohne das klemmte das Blatt auf 246 Punkte bei 375 Punkten Fenster
   und verlor sein Verhältnis (0,394 gegen 0,562). */
@media (max-width: 48rem) {
  .vorschau-dialog.beitrag-vollbild .flaeche-buehne {
    display: contents;
  }

  .vorschau-dialog.beitrag-vollbild .post-card {
    flex: 1 1 0;
    height: auto;
    max-width: 100%;
  }

  .vorschau-dialog.beitrag-vollbild .flaeche-pille {
    flex-direction: row;
  }
}

/* Die Vorpruefung in der Beitragstabelle.
   Die Zeile mit Befund tragt es sichtbar: sie steht ohnehin oben, aber
   ohne optischen Unterschied verliert sie sich beim ersten Scrollen
   zwischen dreissig unauffaelligen. Kein Rot -- der Grund ist ein
   Verdacht und kein Urteil, und die Tafel ist eine Trauerseite. */
.zeile-befund > td {
  background: color-mix(in srgb, var(--ink) 6%, transparent);
}

/* **Der Balken steht einmal am Zeilenanfang, nicht elfmal**
 * (2026-09-09). Der Schatten hing an jeder Zelle: bei elf Spalten
 * zeichnete er elf senkrechte Striche quer durch die Zeile, und die
 * Tabelle sah aus, als sei ein Debug-Raster angeschaltet — so gemeldet.
 *
 * `inset` an einer Tabellenzelle ist immer eine Kante dieser Zelle, nie
 * eine der Zeile; ein `tr` kann selbst keinen Schatten tragen, wenn die
 * Zellen ihren Grund malen. Also die erste Zelle, und in der
 * Kartendarstellung ist das dieselbe: dort ist sie die Überschrift
 * ueber die ganze Breite. */
.zeile-befund > td:first-child {
  box-shadow: inset 3px 0 0 0 var(--ink);
}

.admin-ki {
  max-width: 22rem;
}

.admin-ki p {
  margin: 0.25rem 0 0;
  font-size: 0.85rem;
  line-height: 1.35;
}


.admin-ki .ki-leise {
  opacity: 0.7;
}

.admin-ki form {
  margin-top: 0.4rem;
}

/* --- Ja und Nein in der Verwaltung -----------------------------------
 *
 * ASCII-BEWUSST: `wahrheit` und `wahrheit-wort` sind Klassennamen.
 *
 * **Eine Form für jeden Ja-Nein-Wert** (Ybug 63, templates/_wahrheit.html).
 * Vorher stand in „Gemeldet" und „Gepinnt" das Wort „Nein", und drei
 * solche Wörter untereinander lesen sich als Text und nicht als
 * Zustand. Jetzt trägt Wahr ein Zeichen mit dem Wort darunter, Falsch
 * einen Strich.
 *
 * **Der Strich ist leise und nicht grau.** Eine eigene Graustufe wäre
 * eine sechste Farbe je Theme; `opacity` rechnet sie aus dem, was schon
 * geprüft ist.
 */
.wahrheit {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  line-height: 1.2;
}

.wahrheit-wort {
  font-size: 0.78rem;
  color: var(--muted, #5c584f);
}

.wahrheit-nein {
  opacity: 0.55;
}

/* Was unter einem Wert steht und ihn erklärt: der geltende Stand unter
   den drei Statuszeichen, die Namen unter der Sichtbarkeit, „nicht
   geprüft" unter den Prüfmarken. Immer dieselbe Größe und dieselbe
   Farbe — es ist immer dieselbe Sorte Zusatz. */
.stand-wort {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.78rem;
  line-height: 1.25;
  color: var(--muted, #5c584f);
}

.sichtbar-wert {
  font-weight: 600;
}

/* Der geltende Stand trägt das Zeichen gefüllt und ist abgeschaltet:
   er ist die Auskunft, nicht die Handlung. `opacity` bliebe hier
   falsch — ein blasses Zeichen liest sich als „geht nicht", und
   genau das ist gemeint, aber die Fläche muss die Auskunft tragen. */
/* **Auch `.handeln-knopf.gewaehlt` ist weg** (2026-09-10). Der geltende
   Stand war ein abgeschalteter Knopf in der Handlungsreihe; die
   Statusskala trägt ihn jetzt selbst und schaltet ihn gerade nicht ab
   — ein `disabled` nähme ihn aus der Tabreihenfolge. `.gewaehlt` lebt
   weiter an `.skala-stufe`, mit einer anderen Bedeutung: dort heißt es
   „das gilt" und nicht „das geht nicht". */

/* --- Die drei Marken der KI-Prüfung ----------------------------------
 *
 * ASCII-BEWUSST: `pruefreihe` ist ein Klassenname.
 *
 * **Ein Zeichen je Auftrag, dazu die Zahl** (Ybug 63). Drei Marken
 * brauchen rund 100 Punkte; der Absatz, der vorher hier stand, brauchte
 * die ganze Zellenhöhe und bei einem langen Befund auch die der
 * Nachbarn.
 *
 * **Die Marke selbst steht weiter unten** (Ybug 70): sie heißt
 * `.zahlmarke` und gilt portalweit, seit dieselbe Form auch am Log
 * dieser Zeile hängt. Hier steht nur noch, wie die drei nebeneinander
 * liegen.
 */
/* **Die Reihe darf umbrechen** (2026-09-09). Sie stand als Flexkasten
 * ohne `flex-wrap` in einer Spalte fester Breite (`table-layout: fixed`,
 * 11 Prozent) — drei Marken brauchen rund 130 Pixel, die Zelle gab 103,
 * und der Rest lief in die Nachbarspalte. Gemessen an einem Fenster von
 * 1180 Pixeln: Zelle 103, Inhalt 130.
 *
 * Ein Flexkasten ohne wrap kann nicht enger werden als sein Inhalt; in
 * einer Tabellenspalte, deren Breite von aussen kommt, ist das kein
 * Randfall, sondern der Normalfall bei jedem schmaleren Fenster. */
.pruefreihe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* **Eine Lücke, in der die Zahl Platz hat** (Ybug 70). Die Marke
     oben rechts ragt 0.2rem über den Kreis hinaus; bei 0.3rem Lücke
     überdeckte sie den Nachbarkreis. */
  gap: 0.5rem;
  padding-top: 0.2rem;
}

/* Jede Marke ist ein Stück: das Zeichen und sein Wort darunter. In der
   Tabelle ist das Wort nur optisch weggenommen (`.marke-wort`), und
   die Hülle ist dann so breit wie das Zeichen. */
.pruefmarke {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
}

/* **Das Wort einer Info-Marke** (b67). Vier Zeichen standen ohne Text
   nebeneinander, während Status, Sichtbarkeit und Angeheftet in
   derselben Zeile je ein Wort darunter tragen.

   In der Tabelle bleibt es weggenommen: dort ist kein Platz für vier
   Wörter, und die Spalte heißt „Info". In der Kartenform steht es
   sichtbar da — dieselbe Ordnung wie beim Wort einer Skalenstufe
   (`.skala-wort`), und aus demselben Grund im Markup und nicht
   weggelassen: ein Vorleseprogramm braucht es in beiden Formen. */
.marke-wort {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- Die Zahlmarke: ein Zeichen mit einer Anzahl ----------------------
 *
 * ASCII-BEWUSST: `zahlmarke`, `zahlmarke-zahl`, `zahlmarke-fund` und
 * `zahlmarke-leer` sind Klassennamen.
 *
 * **Die portalweite Form für „Zeichen plus Anzahl"** (Ybug 70). Wo ein
 * Zeichen sagt, worum es geht, und eine Zahl, wie viel davon da ist,
 * steht das Zeichen zentriert in einem Kreis und die Zahl als kleine
 * Marke oben rechts darüber.
 *
 * **Warum nicht mehr nebeneinander.** Zeichen und Ziffer in einer Reihe
 * ergaben bei drei Marken in einer Zelle sechs Dinge nebeneinander; was
 * zu welcher Zahl gehört, musste man sich beim Lesen zusammensuchen.
 * Übereinander gelegt ist es ein Gegenstand mit einer Auskunft daran —
 * dieselbe Form, die ein Postfach für ungelesene Nachrichten benutzt und
 * die deshalb niemandem erklärt werden muss.
 *
 * **Der Kreis ist die Fläche zum Anfassen.** Er misst 1.9rem, also rund
 * 30 Punkte; drei davon mit ihren Lücken bleiben unter den 11 Prozent,
 * die die Prüfspalte hat (config/tabellen.py). Ein Zeichen ohne Fläche
 * ist auf einem Berührungsschirm kein Ziel, sondern ein Glücksspiel.
 *
 * **Kein Rot und kein Grün**, wie überall in dieser Verwaltung: die
 * Themes bringen kein geprüftes Rot mit, und eine Trauerseite spricht
 * nicht in Ampelfarben. Was einen Fund hat, wiegt über Gewicht und
 * Fläche — dieselbe Rechnung wie bei `.zeile-befund`.
 */
.zahlmarke {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  padding: 0;
  background: none;
  /* **Die Kante ist sichtbar und leise.** Ohne sie schwebte die Zahl
     neben einem Zeichen im Nichts — sie sitzt auf dem Rand des
     Kreises, und ohne Rand sitzt sie auf nichts. `--line` und nicht
     der Akzent: die Skalen derselben Zeile setzen Zustände und tragen
     deshalb die kräftigere Kante; hier wird etwas geöffnet. */
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  color: var(--muted, #5c584f);
  font: inherit;
  cursor: pointer;
  /* Ein `<summary>` trägt sonst ein Dreieck vor dem Inhalt, und in
     einem Kreis von 30 Punkten ist daneben kein Platz. */
  list-style: none;
}

.zahlmarke::-webkit-details-marker {
  display: none;
}

.zahlmarke:hover,
.zahlmarke:focus-visible {
  border-color: var(--accent, #2f5d62);
  color: var(--ink, #1b1b1b);
}

/* **Oben rechts und halb außerhalb.** Die Marke sitzt auf dem Rand des
   Kreises, nicht darin: innen nähme sie dem Zeichen den Platz. Der Ring
   in Papierfarbe trennt sie vom Kreis darunter, auch wenn beide
   dieselbe Deckung tragen. */
.zahlmarke-zahl {
  position: absolute;
  top: -0.2rem;
  right: -0.2rem;
  min-width: 1.05rem;
  height: 1.05rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.22rem;
  border-radius: 999px;
  border: 1px solid var(--paper, #fdfcf8);
  background: color-mix(in srgb, var(--ink) 10%, var(--paper, #fdfcf8));
  color: var(--muted, #5c584f);
  font-size: 0.68rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* Ein Fund wiegt: Zeichen und Zahl in der Textfarbe, dahinter eine
   Fläche aus derselben Farbe mit acht Prozent Deckung. Dieselbe
   Rechnung wie bei der Zeile mit Befund. */
.zahlmarke-fund {
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  border-color: color-mix(in srgb, var(--ink) 20%, transparent);
  color: var(--ink, #1b1b1b);
}

.zahlmarke-fund .zahlmarke-zahl {
  background: color-mix(in srgb, var(--ink) 22%, var(--paper, #fdfcf8));
  color: var(--ink, #1b1b1b);
}

/* Was nicht gelaufen ist, trägt keinen Knopf und keine Zahl: dahinter
   liegt nichts, was sich zeigen ließe, und ein Strich ist keine
   Anzahl. Die Auskunft liegt in der Blässe und im Titel. */
.zahlmarke-leer {
  opacity: 0.55;
  cursor: default;
}

/* --- Das Log eines Beitrags ------------------------------------------
 *
 * ASCII-BEWUSST: `log-tafel`, `log-zeile`, `log-wer`, `log-text` und
 * `log-was` sind Klassennamen.
 *
 * Die Tafel hiess `notiz-tafel`, solange sie nur geschriebene Notizen
 * trug (2026-09-10). Sie liegt in derselben Hülle wie die Vorschau
 * (`.vorschau-inhalt`) und wird von static/verwaltung.js in dasselbe
 * Fenster gehoben. Hier steht nur, was an einer Reihe anders ist: die
 * Zeilen setzen sich voneinander ab, und das Feld darunter nimmt die
 * ganze Breite.
 */
.log-tafel {
  min-width: 18rem;
}

/* **Ein Ereignis steht neben seinem Zeitpunkt und nicht darunter**
   (Ybug 130). Jeder Eintrag nahm zwei Zeilen und ein Polster, und
   „Angeheftet“ ist ein Wort — vier davon füllten das Fenster, obwohl
   die Auskunft in vier Zeilen passt.

   Ein geschriebener Eintrag bleibt auf seiner eigenen Zeile: er ist
   ein Satz und kann lang sein. `flex-basis: 100%` bricht ihn um, das
   kurze Ereignis daneben nicht. */
.log-zeile {
  padding: 0.3rem 0;
  border-top: 1px solid var(--line, #d9d9d9);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.5rem;
}

/* **Der Absatzrand muss hier weg, und zwar mit Kind-Selektor**
   (Ybug 130). `.log-wer` und `.log-was` setzen ihn schon auf null,
   und eine allgemeinere Regel für Absätze in der Tafel überstimmte
   sie: gemessen am 2026-09-13 standen 20 Punkte unter jedem Kind,
   und die Zeile war 52 statt 32 Punkte hoch — bei fünf Einträgen
   hundert Punkte Luft, die nichts sagen. */
.log-zeile > p {
  margin: 0;
}

.log-zeile:first-of-type {
  border-top: none;
}

.log-wer {
  margin: 0;
  font-size: 0.78rem;
  color: var(--muted, #5c584f);
}

.log-was {
  margin: 0;
  white-space: normal;
}

/* Der geschriebene Eintrag nimmt die ganze Breite und rückt damit
   unter seinen Zeitpunkt — siehe `.log-zeile`. */
.log-zeile > p.log-text {
  flex: 1 0 100%;
  margin: 0.1rem 0 0;
  white-space: normal;
}

/* **Ein Ereignis tritt zurück** (2026-09-10, Form von Ybug 72). Zwei
   Sorten Eintrag stehen in einer Reihe, und beim Überfliegen muss sich
   trennen lassen, was die Verwaltung geschrieben hat, von dem, was
   ohnehin geschah: das Geschriebene ist die Auskunft, die man sucht.

   Das Trennende ist seit Ybug 72 nur noch Gewicht und Länge — der
   Einzug mit seiner Kante ist weg, weil beide Sorten jetzt dieselbe
   Karte tragen und eine Kante an jeder zweiten Karte die Reihe
   zerschnitt. Ein Ereignis sind zwei Wörter in gedämpfter Farbe, ein
   geschriebener Eintrag ein Satz in Textfarbe. Keine zweite Farbe aus
   dem Theme: eine Trauerseite bringt kein geprüftes Rot oder Grün mit. */
.log-was {
  font-size: 0.88rem;
  color: var(--muted, #5c584f);
}

.log-form {
  margin-top: 0.75rem;
}

.log-form textarea {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 4px;
  font: inherit;
  resize: vertical;
}

/* Was das Fenster tun lässt, steht rechts — dieselbe Regel wie bei der
   Rückfrage und beim Ersatztext (Ybug 50, 51). */
.log-knoepfe {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.5rem;
}

/* Die Warnung, wenn ein Beitrag nicht für den gedacht war, der ihn
   ansieht (Ybug 63). Sie steht vor dem Text und nicht danach: wer sie
   erst darunter liest, hat es schon gesehen — dieselbe Überlegung wie
   bei der Warnung über einem Beitrag mit Befund. */
.einblick-warnung {
  display: flex;
  align-items: flex-start;
  gap: 0.4rem;
  margin: 0 0 0.6rem;
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.35;
}

.einblick-warnung > .icon {
  margin-top: 0.15rem;
}

/* Die Warnung ueber einem Beitrag mit Befund.
   Sie steht vor dem Bild, nicht danach: wer sie erst darunter liest,
   hat es schon gesehen -- und die Wahl, ungesehen zu loeschen, ist der
   ganze Sinn einer Vorpruefung auf einer Trauerseite.

   Kein Rot und kein Warndreieck. Der Befund ist ein Verdacht eines
   Modells, kein Urteil, und die Tafel ist eine Gedenkseite. Sie hebt
   sich durch Rahmen und Grund ab, nicht durch Alarmfarbe. */
.befund-warnung {
  margin: 0 0 1.5rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--ink);
  border-left-width: 4px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--ink) 6%, transparent);
}

.befund-warnung h2 {
  margin: 0 0 0.5rem;
  font-size: 1.05rem;
}

.befund-warnung p {
  margin: 0 0 0.5rem;
}

.befund-warnung .befund-hinweis {
  font-size: 0.9rem;
  opacity: 0.85;
}

.befund-knoepfe,
/* --- Die Vollansicht eines Beitrags in der Verwaltung (Ybug 188) ------
 *
 * Sie war eine Seite aus Überschriften und Absätzen; wer aus der E-Mail
 * über einen neuen Beitrag kam, landete bei seiner Beschreibung statt
 * beim Beitrag. Jetzt steht hier dasselbe Fragment wie im Fenster der
 * Tabelle: das Blatt und die Pille daneben (templates/posts/_flaeche.html).
 *
 * Die Breite kommt vom Blatt und nicht von der Seite: 375 zu 667 ist
 * das Mass der Fläche, und die Pille braucht ihre drei Zentimeter
 * daneben. */
.admin-vollansicht {
  margin: 1.5rem auto;
  max-width: min(100%, calc(70dvh * 375 / 667 + 3.4rem));
}

.admin-vollansicht .post-card {
  width: min(calc(100% - 3.4rem), calc(70dvh * 375 / 667));
  margin: 0;
}

/* --- Das Entscheidungspanel (Ybug 188) --------------------------------
 *
 * Es schwebt über dem Blatt und lässt sich schieben (static/panel.js).
 * Vorher stand die Entscheidung unter der Fläche, also unter 667
 * Punkten: wer entscheiden wollte, musste daran vorbeirollen und sah
 * dabei nicht mehr, worüber er entscheidet.
 *
 * `position: fixed`, damit es beim Rollen stehen bleibt — und weil das
 * Skript seine Stellung in Fensterkoordinaten merkt. */
.entscheid-panel {
  position: fixed;
  /* **Die Startstellung liegt neben dem Blatt** (Ybug 190). Sie war die
     rechte Fensterkante: auf 1680 Punkten endete die Bühne aus Blatt und
     Pille bei 1045, das Panel begann bei 1462 — vierhundert Punkte
     Leere dazwischen, und der Blick musste quer über den Schirm. Wer es
     einmal geschoben hat, bekommt seine eigene Stellung
     (static/panel.js); dies hier ist nur der Anfang.

     Das Maß ist dasselbe wie an `.admin-vollansicht .post-card`: 70dvh
     mal dem Verhältnis 375:667 plus 3,4 rem für die Pille. Davon die
     Hälfte, dazu die Breite des Panels und ein Abstand — `max()` hält
     es am Rand, wenn daneben kein Platz mehr ist. */
  right: max(1.5rem, calc(50vw - (70dvh * 375 / 667 + 3.4rem) / 2 - 13.5rem));
  top: 6rem;
  z-index: 35;
  width: 12rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 10px;
  background: var(--surface, #f0ede7);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
}

/* Die Kopfzeile ist der Griff — dieselbe Rolle wie am Textfenster. */
.entscheid-kopf {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.6rem;
  border-bottom: 1px solid var(--line, #d9d9d9);
  color: var(--muted, #5c584f);
  font-size: 0.85rem;
  cursor: grab;
  touch-action: none;
}

.entscheid-kopf:active {
  cursor: grabbing;
}

.entscheid-wort {
  font-weight: 600;
}

/* Untereinander und über die ganze Breite: drei Entscheidungen, von
   denen jede für sich steht — nebeneinander sähen sie aus wie Stufen
   einer Skala. */
.entscheid-knoepfe {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.6rem;
}

.entscheid-knoepfe form {
  margin: 0;
}

.entscheid-knoepfe button {
  width: 100%;
}

/* Unter 48rem liegt das Panel nicht mehr daneben, sondern unten am
   Rand: auf einem Telefon deckt ein schwebender Kasten von zwölf
   Zentimetern die halbe Fläche. */
@media (max-width: 48rem) {
  .entscheid-panel {
    right: 0.75rem;
    left: 0.75rem;
    top: auto;
    bottom: 0.75rem;
    width: auto;
  }

  .entscheid-knoepfe {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .entscheid-knoepfe form {
    flex: 1 1 8rem;
  }
}

.admin-entscheidung {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.8rem;
}

.admin-entscheidung {
  margin: 1.5rem 0;
}

/* --- Die Skala: ein Zustand und der Weg, ihn zu ändern ---------------
 *
 * ASCII-BEWUSST: `skala`, `skala-stufe`, `skala-anfasser`,
 * `skala-menue`, `skala-fahne`, `skala-auswahl` sind Klassennamen.
 *
 * **Was sie ersetzt** (2026-09-10). Bis hierher stand in einer Spalte,
 * was gilt, und in einer anderen die Knöpfe, die es ändern — bei den
 * Nutzern lagen zwischen beiden vier Spalten. Die Skala legt sie
 * zusammen: die Stufen sind die Auskunft und die Handlung in einem.
 *
 * **Die Reihenfolge ist die Achse**, links das Eingeschränkte, rechts
 * das Offene, und sie steht in jeder Zeile gleich. Das ist der Grund,
 * warum diese Zeichen überhaupt in jeder Zeile stehen dürfen: drei
 * Zeichen an derselben Stelle lassen sich überfliegen, drei, deren
 * Anordnung wechselt, nicht.
 *
 * **Der Zustand steht fest, das Wechselnde in der Fahne.** Unter dem
 * Anfasser steht ein Wort, das sich nie ändert; was während der
 * Bedienung wechselt, hängt als Fahne unten am Menükasten und geht mit
 * ihm. Ein wechselndes Wort an der Stelle des Zustands sähe aus wie
 * ein Zustand — und ein Satz im Textfluss der Zelle schiebt bei jedem
 * Überfahren die Tabellenzeile auseinander.
 *
 * Ohne static/skala.js bleibt die offene Reihe stehen und schickt ein
 * gewöhnliches Formular ab. Das ist die Grundform, nicht der Notbehelf.
 */
.skala {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
}

/* Mittig in der Zelle: die Skala ist ein Zeichen und keine Zeile Text,
   und ein Zeichen, das links klebt, während die Spalte breit ist,
   steht nirgends. */
table.wide td.admin-stand {
  text-align: center;
}

.skala-reihe {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  flex-wrap: nowrap;
}

/* **Die einstufige Form: „Alles in Ordnung"** (Ybug 70). Wo nie
   gemeldet wurde, gibt es keine Skala — „nie gemeldet" ist kein Stand,
   den jemand setzen könnte —, aber es gibt eine Handlung: melden. Der
   Knopf trägt deshalb die Form einer Stufe, ohne eine zu sein, und das
   Wort darunter (`.stand-wort`) sagt wie überall in dieser Spalte, was
   gerade gilt. Die Bestätigung hängt am Formular und baut ihre Reihe
   selbst (static/bestaetigen.js). */
.meldung-ohne {
  display: flex;
  justify-content: center;
  /* **`relative`, sonst hängt die Fahne an der falschen Stelle** (Ybug
     150). Die Bestätigung baut dieselbe Reihe wie eine Skala, und ihre
     Fahne steht `absolute` unter dem Kasten (`.skala-fahne`, Ybug
     103) — ohne positionierten Vorfahren suchte sie sich den nächsten
     weiter oben und hing quer über den Nachbarspalten. Die Skala setzt
     es (`.skala`), die Handlungsspalte setzt es, nur diese eine Stelle
     nicht: deshalb „funktioniert Melden nicht nach der Konvention der
     anderen Knöpfe". */
  position: relative;
}

/* **Die Kante ist der volle Akzent** (2026-09-10). Erst stand hier
   `--line` — die Linie zwischen Tabellenzeilen, hell und
   zurückhaltend, weil sie trennen und nicht auffallen soll. An einem
   Knopf gelesen wirkt sie ausgegraut. Ein gemischter Zwischenwert war
   auf einem Theme mit grauem Akzent immer noch blass; die Hierarchie
   trägt deshalb die Kantendicke und die Fläche, nicht die Helligkeit.
   Eine eigene Kantenfarbe je Theme wäre eine weitere, die niemand
   geprüft hat. */
.skala-stufe {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  width: 2rem;
  height: 2rem;
  padding: 0;
  background: none;
  border: 1px solid var(--accent, #2f5d62);
  border-radius: 999px;
  color: var(--ink, #1b1b1b);
  cursor: pointer;
}

.skala-stufe:hover,
.skala-stufe:focus-visible {
  color: var(--accent, #2f5d62);
  border-width: 2px;
}

/* Der übliche Weg trägt Fläche, die anderen nur eine Kante — dieselbe
   Ordnung wie bei `.handeln-knopf.handeln-ja`. Er ist der übliche,
   nicht der ungefährlichste: bei den Beiträgen das Freigeben. */
.skala-stufe.skala-betont {
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
}

.skala-stufe.skala-betont:hover,
.skala-stufe.skala-betont:focus-visible {
  color: var(--accent-ink, #fff);
  opacity: 0.85;
}

/* **Was gilt, trägt Gewicht — und nicht nur Farbe.** Die doppelte
   Kante ist der Unterschied, den auch sieht, wer Farben nicht
   unterscheidet (WCAG 1.4.1). `opacity` wäre hier falsch: ein blasses
   Zeichen liest sich als „geht nicht", und der geltende Stand ist
   erreichbar wie jeder andere — er ist nicht abgeschaltet, sonst
   fiele er aus der Tabreihenfolge. */
.skala-stufe.gewaehlt {
  border-width: 2px;
}

/* **Das Wort ist da und nur optisch weg.** `display: none` nähme es
   aus dem Accessibility Tree, und dann hinge der ganze Name des
   Knopfes am Zeichen daneben. Dieselbe Technik wie `.sr-only`: der
   Bildschirmleser liest „Sperren", das Auge sieht das Zeichen — das
   sichtbare Wort steht in der Fahne. */
.skala-wort {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* **Im aufgeklappten Kasten steht es da** (Ybug 126). In der Zelle
   ist es weggenommen, weil dort kein Platz ist — aufgeklappt sind es
   zwei oder drei fast gleiche Zeichen nebeneinander, und welches was
   tut, stand bis zum 2026-09-12 nur in der Fahne und nur beim
   Überfahren. Auf einem Berührschirm gibt es kein Überfahren; dort
   war die Auskunft gar nicht zu bekommen.

   Der Kasten ist ein Aufklapper und darf breiter sein als seine
   Zelle — er trägt Fläche und Schatten und liegt ohnehin über allem
   (static/skala.js legt ihn so, dass er ins Bild passt). */
.skala-offen .skala-wort {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  font-size: 0.8rem;
}

/* Mit Wort ist eine Stufe kein Kreis mehr, sondern eine Pille. */
.skala-offen .skala-stufe {
  width: auto;
  padding: 0 0.7rem;
  border-radius: 999px;
}

/* Der Zustand unter dem Anfasser. Er ändert sich nie, also springt
   hier auch nichts. */
.skala-zustand {
  display: block;
  margin-top: 0.2rem;
  text-align: center;
  font-size: 0.78rem;
  line-height: 1.25;
  color: var(--muted, #5c584f);
}

/* **In der Tabelle hat die Beschriftung überall dieselbe Breite**
   (Ybug 129, 131). Sie wuchs mit ihrem Text, und weil der Anfasser
   darüber mittig sitzt, war jede Zelle anders breit: „Offen“ 34
   Punkte, „Verwalter“ 58, „E-Mail bei jedem neuen Beitrag“ 88 —
   gemessen am 2026-09-12. Der Anfasser stand in jeder Zelle an
   derselben Stelle, seine Beschriftung ragte darunter verschieden
   weit heraus, und die Spalte hatte keine Kante mehr.

   Ein fester Kasten gibt ihr eine. Er ist so breit wie die längste
   Beschriftung ohnehin wurde; kürzere stehen mittig darin, und Zeichen
   und Wort schließen in jeder Zelle gleich ab.

   **Nur in der Tabelle.** In der Kartenform steht die Beschriftung
   neben dem Anfasser und in einer Zeile — dort gibt es nichts
   auszurichten. */
table.wide .skala-zustand {
  width: 5.5rem;
}

/* Der Anfasser sieht aus wie die Stufe, die er zeigt — er ist
   dieselbe Sache in zugeklappt. */
.skala-anfasser {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  background: none;
  border: 2px solid var(--accent, #2f5d62);
  border-radius: 999px;
  color: var(--accent, #2f5d62);
  cursor: pointer;
}

.skala-anfasser.skala-betont {
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
}

.skala-anfasser:hover,
.skala-anfasser:focus-visible {
  opacity: 0.85;
}

/* **Der Menükasten: Leiste oben, Fahne unten, ein Stück.**
 *
 * Er liegt über dem Anfasser und aus dem Textfluss. Der Anfasser
 * behält seinen Platz in der Zelle (`visibility`, nicht `display`);
 * sonst zöge sich die Spalte beim Öffnen zusammen und die halbe
 * Tabelle rutschte. Und weil der Kasten absolut liegt, kann die Fahne
 * beliebig lang werden, ohne eine Tabellenzeile anzufassen.
 *
 * Wie weit er nach links steht, rechnet das Skript aus — so weit, dass
 * der Knopf, um den es gerade geht, über dem Punkt liegt, wo die Hand
 * schon ist.
 *
 * Kein Pillenradius: der Kasten trägt zwei Zeilen und ist kein Knopf.
 */
.skala-offen .skala-anfasser,
.skala-waehlt .skala-anfasser {
  visibility: hidden;
}

/* **Der Kasten ist so groß wie seine Zeichen** (Ybug 102). Er trug
   die Fahne in seinem Fluss, und weil dort alle Wörter
   übereinanderliegen (damit er beim Überfahren nicht springt, Ybug
   74), reservierte jeder Zustand die Höhe des längsten Satzes: 129
   Punkte für zwei Zeichen und ein Wort, davon zwei Drittel leer.
   Gemessen am 2026-09-12.

   Die Fahne hängt jetzt unter dem Kasten und nicht darin — sie ist
   aus dem Fluss genommen und kostet ihn keine Höhe mehr. Gesprungen
   wird trotzdem nicht: die Wörter liegen weiter übereinander, nur
   eben in einer eigenen Fläche. */
.skala-menue {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 5;
  width: max-content;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.3rem;
  margin: -0.3rem;
  background: var(--paper, #fff);
  border-radius: 1.15rem;
  box-shadow: 0 2px 10px rgb(0 0 0 / 18%);
}

/* **Die Fahne.** Sie sagt, was der Knopf darüber täte, und sie gehört
   sichtbar zum Kasten — deshalb hängt sie darin und nicht darunter.
   `max-width` hält sie bei einem längeren Satz zusammen, statt den
   Kasten quer über die Tabelle zu ziehen. */
/* **Alle Wörter liegen übereinander, sichtbar ist eines** (Ybug 74).
   Die Fahne trug einen wechselnden Text, und damit wechselte die Breite
   des Kastens: „Bescheid" ist halb so breit wie „Kein Bescheid mehr",
   der Kasten wuchs und schrumpfte beim Abfahren der Stufen — und die
   Knöpfe darin wanderten unter der Hand weg.

   Ein Raster mit einer Zelle: jedes Wort sitzt in `1 / 1`, also
   übereinander. Die Breite ist die des breitesten, die Höhe die des
   höchsten, und beide ändern sich nie. `visibility` und nicht
   `display`, weil ein ausgeblendetes Kind keinen Platz mehr
   beanspruchte — genau den soll es ja halten. */
.skala-fahne {
  /* **Kein Raster mehr** (Ybug 102). Alle Wörter lagen übereinander in
     einer Zelle, damit der Kasten beim Überfahren nicht springt (Ybug
     74) — das kostete ihn die Höhe und die Breite des längsten
     Satzes. Seit die Fahne unter dem Kasten hängt, bewegt ihre Größe
     nichts mehr: die Zeichen darüber stehen fest, gleich wie lang das
     Wort darunter ist. Sie ist damit so groß wie das, was dasteht. */
  display: block;
  /* Unter dem Kasten und aus seinem Fluss heraus: so kostet der
     längste Satz keine Höhe im Kasten. Mittig darunter, in derselben
     Fläche und mit denselben Kanten — sie gehört sichtbar dazu. */
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  /* Über die Nachbarzelle, nicht darunter: sie wird später gezeichnet
     und legte sich sonst über den Satz. */
  z-index: 6;
  width: max-content;
  max-width: 14rem;
  padding: 0.1rem 0.5rem 0.35rem;
  background: var(--paper, #fff);
  border-radius: 0 0 1.15rem 1.15rem;
  box-shadow: 0 4px 10px rgb(0 0 0 / 18%);
  text-align: center;
  font-size: 0.78rem;
  line-height: 1.3;
  color: var(--muted, #5c584f);
}

.skala-fahne-wort {
  display: none;
}

.skala-fahne-wort.skala-fahne-gilt {
  display: block;
}

/* **Die Erstauswahl: Abbruch und das ausgeschriebene Verb.**
 *
 * Sie ersetzt den Rückfragekasten. Der stand als eigene Fläche von
 * 16rem über der Zeile und verdeckte die Nachbarn; das hier ist
 * dieselbe Leiste in ihrer zweiten Lage, im selben Kasten.
 *
 * **Der Abbruch links, die Bestätigung rechts**, und der Fokus startet
 * links: dieselbe Leserichtung wie die Skala selbst, hier als
 * Fortschritt im Dialog. Der zweite Enter darf nicht die Handlung
 * sein, die niemand zurücknehmen will.
 *
 * Das Abbruchzeichen ist immer dasselbe, an jeder Skala. Es ist die
 * eine Stelle, an der ein Verwalter nicht nachsehen muss, was ein
 * Zeichen bedeutet. */
.skala-auswahl {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
}

.skala-ab,
.skala-ja {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-height: 2rem;
  border-radius: 999px;
  cursor: pointer;
}

.skala-ab {
  width: 2rem;
  padding: 0;
  background: none;
  border: 1px solid var(--accent, #2f5d62);
  color: var(--ink, #1b1b1b);
}

.skala-ab:hover,
.skala-ab:focus-visible {
  color: var(--accent, #2f5d62);
  border-width: 2px;
}

.skala-ja {
  padding: 0 0.75rem 0 0.6rem;
  background: none;
  border: 2px solid var(--accent, #2f5d62);
  color: var(--accent, #2f5d62);
  font-size: 0.85rem;
}

.skala-ja.skala-betont {
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
}

.skala-ja:hover,
.skala-ja:focus-visible {
  opacity: 0.85;
}

/* Solange die Antwort unterwegs ist. Kein Kreisel: eine Zeile, die
   kurz blasser ist, sagt dasselbe und dreht sich nicht. */
.skala-laeuft {
  opacity: 0.6;
  pointer-events: none;
}

/* **Eine Zeile, die nicht mehr in diese Sicht gehört.** Sie fällt
   nicht weg: wer aus „Zur Prüfung" heraus freigibt, ist mit dem
   Beitrag meist nicht fertig, und eine Zeile, die unter dem Fokus
   verschwindet, wirft ihn auf den Seitenanfang. Weg ist sie beim
   nächsten Laden. Dass sie nicht mehr dazugehört, sagt der Toast —
   das Verblassen ist nur das Bild dazu. */
tr.zeile-fremd {
  opacity: 0.5;
}

/* **In der Karte bleiben die Stufen Zeichen** (2026-09-10). Mit
   Wörtern passen drei nicht in eine Reihe von 375 Punkten; sie brachen
   um, und aus der Achse von links nach rechts wurde eine Liste
   untereinander. Nötig sind die Wörter dort ohnehin nicht: auf einem
   Berührungsbildschirm gibt es kein Überfahren, und die Erstauswahl
   schreibt das Verb genau dann aus, wenn es zählt. */
@media (max-width: 72rem) {
  /* **In der Karte steht alles links, auch die Skala** (b61).
     Linksbündig ist sie als Ganzes seit dem 2026-09-10 — das macht
     `text-align` an der Zelle, weil `.skala` inline liegt. Ihr Inneres
     blieb dabei, wie es in der Tabelle steht, und dort steht die
     Beschriftung in einem festen Kasten von 5,5 rem mit dem Anfasser
     mittig darüber (siehe `table.wide .skala-zustand`). In der Karte
     ergab das einen Einzug, den daneben niemand hat: „Sichtbarkeit"
     beginnt an der Kante, „Gemeldet" dreißig Punkte weiter innen —
     zwei Felder derselben Karte, die verschieden anfangen.

     Der feste Kasten hat in der Karte auch keine Aufgabe. Er gibt der
     **Spalte** eine Kante, indem er jede Beschriftung gleich breit
     macht; in der Karte steht jedes Feld für sich, und es gibt keine
     Spalte, die eine Kante bräuchte. */
  table.wide td.admin-stand {
    text-align: left;
  }

  /* Die Skala ist eine Spalte aus Anfasser und Wort; in der Tabelle
     stehen beide mittig übereinander, hier beide an der Kante. */
  table.wide td.admin-stand .skala {
    align-items: flex-start;
  }

  table.wide .skala-zustand {
    width: auto;
    text-align: left;
  }

  /* **Und die vier Info-Marken tragen hier ihr Wort** (b67). In der
     Tabelle sind sie Zeichen, weil vier Wörter die Spalte sprengen; in
     der Karte steht jedes Feld für sich, und vier Zeichen ohne Text
     wären ein Rätsel mit vier Feldern. */
  .marke-wort {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    white-space: normal;
    /* **Getrennt und nicht zerschnitten.** „Prüfungsergebnisse" ist
       länger als der Platz, den ein Zeichen daneben lässt; ohne
       `hyphens` bricht der Browser mitten im Wort um und schreibt
       „Prüfungsergebniss / e der KI". Die Seite trägt `lang="de"`, also
       weiß er, wo eine deutsche Silbe endet. */
    max-width: 8rem;
    hyphens: auto;
    text-align: center;
    font-size: 0.78rem;
    line-height: 1.25;
    color: var(--muted, #5c584f);
  }
  .skala-fahne {
    max-width: 11rem;
  }
}

/* **Auf dem Telefon bricht der aufgeklappte Kasten um** (b64). Er steht
   in einer Reihe und soll es auch: waagerecht abgefahren zeigt er die
   Stufen in der Ordnung, in der sie stehen. Auf 375 Punkten passt das
   nicht mehr -- "Sperren", "Zurueckstellen" und "Freigeben"
   ausgeschrieben sind 340 Punkte, und seit der Abbruch davorsteht, sind
   es 377. Gemessen am 2026-09-13: rechts abgeschnitten, "Freigeben" nur
   noch halb zu lesen.

   Statt das Zeichen wieder wegzunehmen, darf die Reihe hier umbrechen.
   Die Regel, dass die geltende Stufe ueber dem Anfasser liegt, gilt
   damit nur noch fuer die erste Zeile -- auf einem Telefon tippt man
   ohnehin, statt mit dem Zeiger abzufahren, und ein abgeschnittener
   Knopf ist der schlechtere Tausch. */
@media (max-width: 30rem) {
  .skala-menue {
    max-width: calc(100vw - 0.5rem);
  }

  .skala-menue .skala-reihe {
    flex-wrap: wrap;
    justify-content: flex-start;
  }
}

@media (prefers-reduced-motion: reduce) {
  .skala-menue {
    transition: none;
  }
}

/* --- Die Auswahl mit Suche ------------------------------------------
 *
 * ASCII-BEWUSST: `auswahl`, `auswahl-leiste`, `auswahl-gewaehlt`,
 * `auswahl-treffer-knopf`, `auswahl-steuer` sind Klassennamen.
 *
 * **Die zweite Form der Konvention für Zustände** (2026-09-10). Eine
 * Skala hat zwei oder drei feste Stufen und passt in eine Reihe; hier
 * ist die Menge zu groß dafür — der Motivsatz umfasst 1779 Zeichen.
 * Also Suche statt Stufen, und ein Übernehmen, das die Skala nicht
 * braucht: dort ist ein Klick ein Vorgang, hier sind drei Klicks einer.
 *
 * DIE ORDNUNG DER LEISTE
 *
 *     [Abbruch] [Übernehmen] (Gewähltes) [Suchfeld] (Treffer) …
 *
 * Gewähltes links, Treffer rechts, das Suchfeld dazwischen. Ein
 * gewählter Treffer springt nach links, ein abgewähltes Zeichen fällt
 * nach rechts. Die Bewegung sagt, was passiert ist.
 *
 * Sie liegt aus dem Textfluss wie das Skalenmenü und aus demselben
 * Grund: eine Leiste, die in der Zelle steht, schiebt bei jedem Treffer
 * die Tabellenzeile auseinander.
 */
.auswahl {
  position: relative;
  display: inline-flex;
  align-items: center;
}

/* Der Anfasser trägt das Zeichen, das gilt — dieselbe Form wie der
   Anfasser einer Skala, weil es dieselbe Sache ist: eine Zelle, die
   zeigt, was gilt, und der Weg, es zu ändern. */
.auswahl-anfasser {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  background: none;
  border: 2px solid var(--accent, #2f5d62);
  border-radius: 999px;
  color: var(--accent, #2f5d62);
  cursor: pointer;
}

/* **Ohne Zeichen ein leerer Kreis und kein fehlender Knopf.** Eine
   Zelle ohne Anfasser wäre eine, die sich nicht ändern lässt — und
   genau das ist der Fall, den man am häufigsten ändern will. */
.auswahl-anfasser-leer {
  border-style: dashed;
}

/* **Die Vorgabe traegt Flaeche** (b65). Der Anfasser zeigt, was gilt;
   solange niemand Leser benennt, gilt „fuer alle" — derselbe Rang, den
   „Besucher" an der Rollenskala hat (b77), und dort ist der Anfasser
   gefuellt. Eine Zelle mit leerem Kreis neben einer mit Flaeche sagte
   dasselbe in zwei Sprachen.

   Der Unterschied ist nicht die Farbe allein: wer Leser benennt, sieht
   im Kreis ihre Kuerzel statt des Zeichens fuer „alle", und darunter
   steht der Klartext. */
.auswahl-anfasser-vorgabe {
  background: var(--accent, #2f5d62);
  border-color: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
}

.auswahl-anfasser:hover,
.auswahl-anfasser:focus-visible {
  opacity: 0.85;
}

/* Die Form ohne Skript: Marke, Textfeld, Knopf. Wenig, aber bedienbar
   — eine Suche über 1779 Zeichen ohne eine Zeile JavaScript gibt es
   nicht, und ein Wähler, der ohne Skript nichts täte, wäre schlimmer
   als ein Textfeld. */
.auswahl-form {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.auswahl-feld {
  width: 7rem;
  font-size: 0.8rem;
}

.auswahl-marke {
  display: inline-flex;
  align-items: center;
  color: var(--accent, #2f5d62);
}

/* **Der Anfasser behält seinen Platz.** `visibility` und nicht
   `hidden`: nimmt man ihn ganz heraus, zieht sich die Zelle zusammen
   und die Zeilenhöhe springt beim Öffnen — gemessen am 2026-09-10,
   152 auf 137 Punkte. Dieselbe Lösung wie bei der Skala. */
.auswahl-offen .auswahl-anfasser {
  visibility: hidden;
}

/* **Die Leiste.** Sie wird breiter als die Zelle und scrollt dann
   waagerecht; die Höhe bleibt, weil sie nicht umbricht. Ein Umbruch
   wäre hier schlimmer als Scrollen: aus der Ordnung „links gewählt,
   rechts gefunden" würde ein Block, in dem beides durcheinander
   steht. */
.auswahl-offen .auswahl-leiste {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 0.3rem;
  max-width: 34rem;
  padding: 0.3rem;
  margin: -0.3rem;
  background: var(--paper, #fff);
  border-radius: 1.15rem;
  box-shadow: 0 2px 10px rgb(0 0 0 / 18%);
  white-space: nowrap;
}

/* **Abbruch und Übernehmen kleben am linken Rand.** Ohne `sticky`
   scrollt man die Bestätigung aus dem Bild und kommt nicht mehr heran
   — bei einer Leiste, die breiter ist als ihre Zelle, ist das der
   Normalfall und nicht die Ausnahme. */
.auswahl-steuer {
  position: sticky;
  left: 0;
  z-index: 1;
  display: flex;
  gap: 0.3rem;
  padding-right: 0.2rem;
  background: var(--paper, #fff);
}

.auswahl-ab,
.auswahl-ja {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border-radius: 999px;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.auswahl-ab {
  background: none;
  border: 1px solid var(--accent, #2f5d62);
  color: var(--ink, #1b1b1b);
}

.auswahl-ab:hover,
.auswahl-ab:focus-visible {
  color: var(--accent, #2f5d62);
  border-width: 2px;
}

/* Übernehmen ist der übliche Weg heraus und trägt deshalb Fläche —
   dieselbe Ordnung wie `.skala-betont`. */
.auswahl-ja {
  background: var(--accent, #2f5d62);
  border: 2px solid var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
}

.auswahl-ja:hover,
.auswahl-ja:focus-visible {
  opacity: 0.85;
}

.auswahl-gewaehlte {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  flex: 0 0 auto;
}

/* **Nur die Treffer scrollen** (2026-09-10). Vorher scrollte die ganze
   Leiste, und mit ihr das Suchfeld und die Gewählten: wer nach rechts
   sah, verlor das Feld, in das er gerade tippte, und die Auswahl, die
   er gerade getroffen hatte. Was links steht, ist entschieden und
   bleibt stehen; was rechts steht, ist Angebot und darf laufen. */
.auswahl-treffer {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}

/* **Gewähltes trägt Fläche, Gefundenes nur eine Kante.** Der
   Unterschied ist nicht die Farbe allein: das Gewählte trägt zusätzlich
   `aria-pressed` und steht auf der anderen Seite des Suchfeldes. Wer
   Farben nicht unterscheidet, liest die Seite. */
.auswahl-gewaehlt,
.auswahl-treffer-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border-radius: 999px;
  cursor: pointer;
}

/* **Das Zeichen füllt seinen Kreis** (Ybug 154). Es kam aus zwei
   Quellen in verschiedenen Größen: das gefundene baut static/auswahl.js
   mit 1,05 rem, das geltende kopiert es aus der Marke der Zeile, und
   die steht dort in `1em` — in einer Tabelle mit 0,9 rem Schrift also
   noch kleiner. In einem Knopf von 2 rem, neben einem Kreuz und einem
   Haken in voller Schriftgröße, sah das gewählte Zeichen aus wie ein
   Versehen.

   Die Größe steht deshalb hier und nicht an der Quelle: sie gehört zum
   Kreis, in dem das Zeichen sitzt, und gilt damit für beide Wege. */
.auswahl-gewaehlt .icon,
.auswahl-treffer-knopf .icon {
  width: 1.25rem;
  height: 1.25rem;
}

.auswahl-gewaehlt {
  background: var(--accent, #2f5d62);
  border: 1px solid var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
}

.auswahl-treffer-knopf {
  background: none;
  border: 1px solid var(--accent, #2f5d62);
  color: var(--ink, #1b1b1b);
}

.auswahl-treffer-knopf:hover,
.auswahl-treffer-knopf:focus-visible,
.auswahl-gewaehlt:hover,
.auswahl-gewaehlt:focus-visible {
  border-width: 2px;
}

/* **Die Pille mit einem Wort darin** (b65). „Fuer alle" ist die eine
   Wahl in dieser Leiste, die kein Mensch ist: die anderen tragen
   Initialen und sind daran zu erkennen, diese trug ein Zeichen und
   sonst nichts. Sie steht auf beiden Seiten des Suchfeldes in
   derselben Form — links gefuellt, weil sie gilt, rechts als Kante,
   weil sie zu holen waere. */
.auswahl-wortpille {
  width: auto;
  gap: 0.3rem;
  padding: 0 0.7rem;
  font-size: 0.8rem;
  white-space: nowrap;
}

/* Das Suchfeld steht zwischen beiden Seiten und ist der Ort, an dem
   gearbeitet wird. Es schrumpft nicht mit: ein Feld von zwei Zeichen
   Breite ist kein Feld. */
.auswahl-suche {
  flex: 0 0 8rem;
  min-width: 8rem;
  font-size: 0.8rem;
}

/* Was gerade gewählt wurde, in Worten. Bei einer Mehrfachauswahl ist
   das die Stelle, an der die Zahl steht — ein Haken ohne Rückmeldung
   ist der Punkt, an dem man anfängt zu zählen. */
.auswahl-stand {
  font-size: 0.78rem;
  color: var(--muted, #5c584f);
}

.auswahl-laeuft {
  opacity: 0.6;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .auswahl-offen .auswahl-leiste {
    transition: none;
  }
}

/* **Ein Anfasser mit Text statt eines Zeichens** (2026-09-10). Für
   „drei bestimmte Leser" gibt es kein Zeichen, und eines zu erfinden
   hieße, dass beim Überfliegen niemand sieht, wer gemeint ist. Also
   eine Pille mit Wörtern — dieselbe Kante und dieselbe Rundung wie der
   Anfasser mit Zeichen, nur breiter. */
.auswahl-anfasser-text {
  width: auto;
  min-width: 2rem;
  padding: 0 0.7rem;
  font-size: 0.8rem;
  line-height: 1.2;
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Die Form ohne Skript bei einer endlichen Liste: Kästchen
   untereinander. Es ist dieselbe Auswahl, nur senkrecht — und bei einem
   Dutzend Namen geht das ohne eine Zeile JavaScript. */
.auswahl-kaestchen {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.8rem;
}

.auswahl-kaestchen-zeile {
  display: flex;
  align-items: center;
  gap: 0.3rem;
}

/* **Der Speichern-Knopf der Form ohne Skript** (b05). Er stand hier als
   nacktes `<button>` ohne eine einzige Regel — in der Zeit, als es die
   Konvention noch nicht gab, hiess das: Systemknopf, grau, eckig, mitten
   in einer Liste aus Kaestchen. Jetzt traegt er die Rolle, die er hat:
   er ist das, wofuer die Liste da ist. Eigen bleibt nur, dass er sich
   absetzt und nicht ueber die ganze Breite laeuft — er steht unter
   einer Liste und nicht in einer Knopfreihe. */
.auswahl-speichern {
  align-self: flex-start;
  margin-top: 0.6rem;
}

/* **Gefundenes trägt seinen Namen, Gewähltes sein Kürzel**
   (2026-09-10). In der Trefferreihe sucht man einen Menschen und
   braucht den Namen; links steht, was schon entschieden ist, und dort
   zählt der Platz — die Zelle trägt 104 Punkte. Wer nachsehen will,
   hat den Titel und den Klartext unter der Zelle. */
.auswahl-treffer-knopf.auswahl-name {
  width: auto;
  padding: 0 0.6rem;
  font-size: 0.8rem;
  white-space: nowrap;
}

/* Der Kreis mit zwei Buchstaben — in der Leiste als Knopf, in der
   Zelle als Marke am Anfasser. Dieselbe Form an beiden Orten, damit
   man sie wiedererkennt. */
.auswahl-gewaehlt,
.auswahl-kuerzel {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.auswahl-kuerzel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 999px;
  background: var(--accent, #2f5d62);
  color: var(--accent-ink, #fff);
}

/* **Mehrere Kürzel machen den Anfasser breiter, nicht höher.** Drei
   Kreise nebeneinander bleiben eine Zeile; untereinander wären sie
   eine Liste, und die Zeilenhöhe der ganzen Tabelle hinge daran, wie
   viele Leser der Beitrag mit den meisten hat. */
.auswahl-anfasser-marken {
  width: auto;
  min-width: 2rem;
  padding: 0 0.25rem;
  gap: 0.15rem;
  border-radius: 1rem;
}

/* Solange die Bestätigung unterwegs ist (static/bestaetigen.js) —
   dieselbe Form wie bei einer Skala, die schickt. */
.bestaetigt-laeuft {
  opacity: 0.6;
  pointer-events: none;
}
/* --- Die Bestätigungsreihe einer Handlung ----------------------------
 *
 * ASCII-BEWUSST: `bestaetigt-reihe` und `bestaetigt-offen` sind
 * Klassennamen.
 *
 * **Sie bleibt in der Zeile** (Ybug 99). Sie war am 2026-09-12 kurz im
 * Fenster des Hauses und ist wieder hier: eine Handlung an einer Zeile
 * wird dort bestätigt, wo sie steht — ein Klick wählt, der zweite
 * bestätigt, und beides liegt dort, wo die Hand schon ist. Dieselbe
 * Form wie die Skala daneben (static/skala.js).
 *
 * **Ohne Fahne darunter** (Ybug 150). Der Satz über die Folge hing als
 * halbrunder Kasten unter der Reihe und legte sich damit über die
 * Zeile darunter — in einer Tabelle, deren Zeilen dicht liegen, ist
 * das ein Fremdkörper, der mehr verdeckt als er sagt. Er steht jetzt
 * als Titel am Knopf, der die Sache tut (static/bestaetigen.js).
 *
 * Der Bezugspunkt bleibt: der Kasten wächst nach links über die
 * Nachbarspalte, und dafür braucht er ihn (weiter unten).
 */
.bestaetigt-reihe {
  position: relative;
}

/* **Und der Kasten wächst nach innen, nicht über den Rand** (Ybug 71).
   Die Handlungsspalte ist die letzte; eine Leiste von 13 rem in einer
   Zelle von 7 rem muss irgendwohin. Nach rechts wäre aus der Tabelle
   heraus, also nach links über die Nachbarspalte — mit Fläche und
   Schatten wie der Menükasten einer Skala, damit sichtbar bleibt, was
   oben liegt und was darunter. */
table.wide td.admin-handeln form[data-bestaetigen],
table.wide td.admin-handeln form.bestaetigt-offen {
  position: relative;
}

table.wide td.admin-handeln .bestaetigt-reihe {
  position: absolute;
  top: -0.3rem;
  right: -0.3rem;
  z-index: 5;
  /* Ein absoluter Kasten, der nur `right` kennt, wird shrink-to-fit —
     und sein Platz reicht nur bis zum linken Rand des Formulars, das
     hier 2 rem breit ist. Dann bricht die Knopfreihe um und der
     Abbruch steht allein über dem Verb. */
  width: max-content;
  padding: 0.3rem;
  background: var(--paper, #fff);
  border-radius: 1.15rem;
  box-shadow: 0 2px 10px rgb(0 0 0 / 18%);
}

/* **In der Karte steht sie im Fluss** (b72). Der Kasten oben schwebt,
   weil die Handlungsspalte die letzte und zu schmal fuer eine Leiste
   ist: er waechst nach links ueber die Nachbarspalte.

   In der Karte gibt es diese Nachbarspalte nicht. Das Formular ist dort
   null Punkte breit -- sichtbar ist daran nur der schwebende Kasten
   selbst --, und `right: -0.3rem` liess ihn von dieser Null aus nach
   links wachsen: gemessen am 2026-09-13 auf 375 Punkten stand er bei
   x = -176, also zu vier Fuenfteln ausserhalb des Schirms. Es war nicht
   die Rueckfrage, die fehlte -- sie stand neben dem Bild.

   Hier ist sie deshalb ein Knopfpaar wie jedes andere in der Zelle: im
   Fluss, ohne Flaeche und ohne Schatten. Ein schwebender Kasten traegt
   beides, um zu zeigen, dass er ueber etwas liegt; hier liegt er ueber
   nichts. */
@media (max-width: 72rem) {
  table.wide td.admin-handeln .bestaetigt-reihe {
    position: static;
    width: auto;
    padding: 0;
    background: none;
    box-shadow: none;
  }
}
/* **Die Auswahl-Leiste auf einem schmalen Schirm** (2026-09-10). Ihre
   34 rem sind bei 375 Punkten das Doppelte des Verfügbaren; sie ragte
   rechts hinaus, und seit `.site-content` quer abschneidet, ließ sich
   das nicht wegscrollen — dieselbe Falle wie bei den Tabellen vor dem
   Umbau auf Karten.

   Die Breite folgt jetzt der Zelle, und weil nur die Trefferreihe
   scrollt, bleiben Abbruch, Übernehmen, die Gewählten und das Suchfeld
   erreichbar. Was rechts nicht mehr hinpasst, holt der Finger sich in
   der Trefferreihe.

   **Das Suchfeld wird schmaler, aber nicht klein.** 8 rem sind auf 375
   Punkten neben zwei Steuerknöpfen und zwei Pillen zu viel; 5 rem
   trägt noch ein Wort. */
@media (max-width: 72rem) {
  .auswahl-offen .auswahl-leiste {
    max-width: calc(100vw - 2.5rem);
  }
  .auswahl-suche {
    flex: 0 1 5rem;
    min-width: 4rem;
  }
}

/* ===================================================================
   Der Inline-Editor der Texte (2026-09-13)

   **Er darf die Seite nicht verstellen.** Wer Texte ändert, will sehen,
   wie sie im Satz stehen — ein Rahmen um jedes Wort machte daraus eine
   Sammlung von Kästchen. Deshalb nur ein Stift daneben und ein leiser
   Untergrund, der erst beim Zeigen deutlich wird.
   =================================================================== */

.vok {
  /* Kein `display` und kein Rahmen: das Wort bleibt, was es war. */
  border-radius: 3px;
  box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--accent, #2f5d62) 30%, transparent);
}

.vok:hover {
  background: color-mix(in srgb, var(--accent, #2f5d62) 8%, transparent);
}

/* Der Stift. Klein, tiefgestellt, ohne eigene Fläche — er hängt am
   Wort und bildet keinen zweiten Knopf in der Zeile. */
.vok-stift,
.vok-attr-stift {
  background: none;
  border: none;
  padding: 0 0 0 .15em;
  margin: 0;
  font-size: .75em;
  line-height: 1;
  color: var(--accent, #2f5d62);
  cursor: pointer;
  vertical-align: super;
  opacity: .55;
}

.vok:hover .vok-stift,
.vok-stift:focus-visible,
.vok-attr-stift:hover,
.vok-attr-stift:focus-visible {
  opacity: 1;
}

/* Das Feld beim Bearbeiten. Es erbt die Schrift der Stelle, an der es
   steht — deshalb `contenteditable` und kein `<input>`. */
.vok-feld {
  display: inline;
  outline: 2px solid var(--accent, #2f5d62);
  outline-offset: 2px;
  border-radius: 2px;
  background: var(--paper, #fff);
  min-width: 2ch;
}

/* Kurz nach dem Speichern. Der Ton verklingt von selbst. */
.vok-frisch {
  animation: vok-verklingen 1.6s ease-out;
}

@keyframes vok-verklingen {
  from { background: color-mix(in srgb, var(--accent, #2f5d62) 28%, transparent); }
  to   { background: transparent; }
}

/* Das Fenster: Weg hinaus und die Texte, die in Attributen stecken.
 *
 * **Es lag bis zum 2026-09-14 als Leiste über der ganzen Breite am
 * unteren Rand** (Ybug 138) und nahm bis zu 45 vh davon ein — bei
 * einem Fall mit vielen Attributtexten war die halbe Seite zu, und
 * genau die Stelle, deren Wort man ändern wollte, lag darunter. Ein
 * Werkzeug, das den Gegenstand verdeckt, an dem es arbeitet.
 *
 * Jetzt ist es ein Fenster: es steht unten rechts, lässt sich an
 * seiner Kopfzeile verschieben und an der Ecke unten rechts größer
 * ziehen (`resize: both`, das übliche Griffdreieck des Browsers).
 * Position und Größe bleiben je Browser erhalten — static/vokabel.js
 * legt sie in den localStorage, denn wer Texte pflegt, macht das über
 * mehrere Seiten hinweg und will das Fenster nicht jedes Mal neu
 * hinschieben.
 *
 * `min-*` und `max-*`: kleiner als die Kopfzeile wäre es ein Streifen
 * ohne Inhalt, größer als der Schirm nicht mehr zu fassen. */
.vok-fenster {
  position: fixed;
  inset-inline-end: 1rem;
  inset-block-end: calc(1rem + env(safe-area-inset-bottom));
  z-index: 60;
  width: min(26rem, calc(100vw - 2rem));
  height: min(24rem, 60vh);
  min-width: 14rem;
  min-height: 3.5rem;
  max-width: calc(100vw - 1rem);
  max-height: calc(100vh - 1rem);
  resize: both;
  overflow: auto;
  padding: .6rem .8rem;
  background: var(--surface, #f0f0f0);
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 12px;
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.28);
  font-size: .9rem;
}

/* Die Kopfzeile ist der Griff. `position: sticky`, damit sie beim
   Rollen der Liste stehen bleibt — sonst wäre das Fenster nach dem
   ersten Rollen nicht mehr zu fassen. `touch-action: none` gibt die
   Geste dem Ziehen und nicht dem Rollen der Seite darunter. */
.vok-fenster-kopf {
  position: sticky;
  inset-block-start: -.6rem;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  margin: -.6rem -.8rem .2rem;
  padding: .5rem .8rem;
  background: var(--surface, #f0f0f0);
  border-block-end: 1px solid var(--line, #d9d9d9);
  cursor: move;
  touch-action: none;
}

/* Der Weg hinaus wird nicht zum Griff: wer ihn drückt, will beenden
   und nicht schieben. */
.vok-fenster-kopf form,
.vok-fenster-aus {
  cursor: auto;
  touch-action: auto;
}

.vok-fenster-wort { font-weight: 600; }

.vok-fenster-aus {
  font: inherit;
  padding: .25rem .8rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  background: var(--paper, #fff);
  color: var(--ink, #1b1b1b);
  cursor: pointer;
}

.vok-fenster-hinweis {
  margin: .5rem 0 .25rem;
  font-size: .8rem;
  opacity: .75;
}

/* Das Suchfeld über der Liste (Ybug 175). Über die ganze Breite des
   Fensters: es gehört zur Liste darunter und nicht neben sie. */
.vok-fenster-suche {
  width: 100%;
  margin: 0 0 .5rem;
  padding: .35rem .5rem;
  font: inherit;
  font-size: .85rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 6px;
  background: var(--paper, #fff);
  color: inherit;
}

.vok-attr-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .3rem;
}

.vok-attr-liste li {
  display: flex;
  align-items: baseline;
  gap: .3rem;
}

/* **Die schwebenden Knöpfe rücken nicht mehr hoch** (Ybug 138). Sie
   taten es, solange das Werkzeug eine Leiste über die ganze Breite war
   und ihnen den Platz nahm. Ein Fenster, das man verschieben kann,
   nimmt keinen festen Platz — und Knöpfe, die trotzdem 45 vh höher
   stünden, wären an einer Stelle, an der nichts liegt. Liegt das
   Fenster einmal über einem Knopf, schiebt man es weg; genau dafür ist
   es verschiebbar. */
.vok-fenster-aus {
  flex: 0 0 auto;
}

/* Die Überschrift im Info-Fenster eines Beitrags (Befund b21). Klein
   und leise: sie ordnet ein, sie ist nicht der Inhalt. */
.post-info-titel {
  margin: 0 0 .4rem;
  font-size: .85rem;
  font-weight: 600;
  opacity: .7;
}

/* --- Die Folge der Beiträge, gezogen ----------------------------------
 *
 * ASCII-BEWUSST: `folge-griff` und `folge-zieht` sind Klassennamen.
 *
 * **Der Griff steht nur in einer Sortierung da** (Ybug 158) — in der
 * nach der Folge. In jeder anderen hat eine verschobene Zeile kein
 * Ziel: die Liste ordnet sich beim nächsten Aufbau wieder selbst
 * (posts/views.py, `folge_ziehbar`).
 *
 * Er ist leise wie eine Angabe und nicht laut wie ein Knopf: die sechs
 * Punkte in der gedämpften Farbe, und erst unter dem Zeiger in der
 * Textfarbe. Was er tut, sagt der Zeiger selbst — `grab` ist die eine
 * Form, die jeder kennt, ohne ein Wort gelesen zu haben.
 */
.folge-griff {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--muted, #5c584f);
  cursor: grab;
  touch-action: none;
}

.folge-griff:hover,
.folge-griff:focus-visible {
  color: var(--ink, #1b1b1b);
}

.folge-griff:active {
  cursor: grabbing;
}

/* Die Zeile, die gerade gezogen wird, bleibt sichtbar und tritt
   zurück: ganz ausblenden hiesse, den Platz zu verlieren, an dem sie
   gerade liegt. */
.folge-zieht {
  opacity: 0.45;
}

table.wide td.admin-folge {
  text-align: center;
}

/* **Die Marke „Extern" an einer Zuschrift von aussen** (Ybug 164).
   Seit die Anmeldeseite einen Weg zur Verwaltung trägt, kann eine
   Nachricht von jemandem kommen, der kein Konto hat — und das ist die
   erste Frage beim Lesen: schreibt da ein Mitglied, oder jemand, der
   nicht hereinkommt?

   Eine kleine Pille in der gedämpften Farbe: sie ordnet ein und ruft
   nicht. Dieselbe Form wie der Kopf eines zweistufigen Menüs, nur
   kleiner — sie ist eine Angabe und kein Griff. */
.marke-extern {
  display: inline-block;
  margin-top: 0.2rem;
  padding: 0.05rem 0.5rem;
  border: 1px solid var(--line, #d9d9d9);
  border-radius: 999px;
  background: var(--surface, #f0ede7);
  color: var(--muted, #5c584f);
  font-size: 0.75rem;
  font-weight: 600;
}
