/* ═══════════════════════════════════════════════════════════════════════════
   BLUE HORIZON DESIGN SYSTEM — patterns/detail.css
   Version: 0.1.18 · Build: 2026-09-24

   0.1.18 — .bh-thread__entry--opening verliert seine Fläche und behält
   die Kante. Die Regel griff wie gebaut; der Befund war gestalterisch:
   Dieselbe Tönung wirkt nach Fläche, und der Eröffnungsbeitrag ist die
   größte der Seite. Dazu die Absicht — --internal ist eine Warnung und
   will auffallen, --opening sagt nur, wo es anfängt. Begründung und die
   verworfene Variante stehen an der Regel.

   0.1.17 — Zwei Merkmale im Kopf der Variante, an denen sich ohne
   Diskussion entscheiden lässt, ob sie passt: Wechselt man zwischen
   Lesen und Schreiben, und ist der Scrollbereich eindeutig? Dazu die
   erste dokumentierte Ablehnung (Team Hub, post.php und event.php).
   Nur Kommentar, keine Regel geändert.

   0.1.16 — Vier Teile des Verlaufs, die es im Bestand gab und die beim
   Umbau durchfielen: __event-label, __event-by, --opening und
   .is-deleted. Gefunden hat sie check-markup.py, der fragt, welches
   Markup KEINE Regel hat.

   0.1.15 — Systemereignisse tragen wieder die Farbe ihrer Handlung. Das
   Pattern erzeugte seit 0.1.0 die Zustandsklassen (is-status-open,
   -in-progress, -closed, is-assigned, is-forwarded), hatte aber nie eine
   Regel dazu — die Farbe stand im Projekt und fiel mit dem Umbau des
   Verlaufs. Ein Pattern, das eine Klasse VERLANGT und sie nicht bedient,
   verschiebt die Arbeit in jedes Projekt.
   Gefärbt wird nur das SYMBOL, nicht der Text und nicht die Fläche: der
   Punkt ist der Kanal, den §0b für den Status vorsieht.

   Dazu unter --fixed: der Abstand zwischen Textfeld und Fuß war die Summe
   zweier Polster (12 + 12), der zwischen Reitern und Textfeld nur eines.
   Jetzt trägt der Fuß oben nichts mehr — ein Abstand, zwei Stellen, das
   ist die Summe aus DESIGN.md §0c.

   0.1.14 — Der Composer-Fuß behielt unter --fixed sein unteres Polster aus
   der Kastenfassung. Dort trennt es den Knopf vom Rahmen; ohne Rahmen
   schiebt es ihn nur 12px über die Unterkante, auf der die Meta-Spalte
   liegt. Die sichtbare Unterkante des Composers IST jetzt der Knopf.

   0.1.13 — .bh-thread__entry-actions stand im FLUSS. Die Regel seit 0.1.0
   war „margin-left: auto" — gebaut für den Fall, dass die Aktionen das
   letzte Kind von __entry-head sind. Liegen sie irgendwo sonst im Eintrag,
   tut margin-left nichts, sie brechen auf eine eigene Zeile, und weil
   opacity: 0 nur die Sichtbarkeit nimmt und nicht den Platz, reservieren
   sie ihn auch unsichtbar. Das war der Grund für die zu große Luft oben an
   jedem Eintrag.
   Jetzt absolut oben rechts im Eintrag: unabhängig davon, wo im Markup sie
   stehen, und ohne Platz im Fluss.

   Dazu align-content: start am Gitter unter --fixed. Mit stretch allein
   wurde die Zeile immer so hoch wie der Behälter, auch wenn beide Spalten
   weniger Inhalt hatten — die Meta-Spalte reichte dann bis zum Fensterrand,
   die Hauptspalte endete unter dem Composer. Jetzt ist die Zeile so hoch
   wie der höhere der beiden Inhalte (gedeckelt durch max-height: 100%),
   und stretch zieht die andere Spalte darauf.

   0.1.12 — Fünf Abstände, jeder mit eigener Ursache:
     · <details> gibt seinen Inhalt in Chrome ≥131 in ::details-content und
       unterbricht damit die Flex-Kette der Meta-Spalte. Die letzte Karte
       wuchs deshalb nicht mit (Pflichttest, Punkt 3).
     · Der Datumstrenner saß näher am Folgenden als am Vorherigen (16/12).
       Jetzt symmetrisch; dass er zum Folgenden gehört, sagt die Linie
       ÜBER ihm, nicht ein kleinerer Abstand darunter.
     · Der erste Eintrag war nur für __entry und __day entschärft, nicht
       für __event. Jetzt gilt es für jedes erste Kind.
     · Die Trennlinie im Composer-Fuß entfällt unter --fixed: eine Linie
       über dem Composer reicht, zwei zerschneiden ihn.
     · Kopfzeile: __head-meta richtete an der Grundlinie aus. Ein Knopf von
       36px und eine Textzeile von 12px haben zwar eine gemeinsame
       Grundlinie, aber sie bedeutet nichts — jetzt mittig.

   0.1.11 — Unter --fixed steht der Verlauf DIREKT AUF DEM SEITENGRUND,
   und das Antwortfeld darunter ist nur durch eine Linie abgesetzt. Die
   Karte um beide war auf einer stehenden Seite Zierrat: sie reicht ohnehin
   bis an die Fensterkante, und ein Rahmen um etwas, das den ganzen Bereich
   einnimmt, trennt nichts mehr von nichts.
   Das gilt NUR hier. Auf einer normal scrollenden Detailseite steht der
   Verlauf weiter in einer Karte und der Composer bleibt ein Kasten — dort
   grenzt beides gegen das ab, was darüber und darunter kommt.
   Kein neuer Klassenname: es ist dieselbe Bedingung wie für alles andere
   an dieser Variante.

   0.1.10 — Unter --fixed enden beide Spalten auf derselben Kante. Das
   Gitter trägt align-items: start, weil eine kurze Karte nicht auf die
   Länge der Nachbarspalte gezogen werden soll — richtig für die normale
   Detailseite. Unter --fixed ist es falsch: dort hat die Seite eine feste
   Höhe, die Hauptspalte füllt sie, und die Meta-Spalte hörte auf halber
   Strecke auf. Jetzt stretch, und die LETZTE Karte nimmt den Rest.
   Dazu eine dünne Scrollleiste für den Verlauf.

   (0.1.9 war die Entfernung der Variante — zurückgenommen, siehe git.)

   0.1.8 — Die Kette riss in der öffentlichen Hülle. 0.1.4 gab
   .bh-public__main und .bh-public__section min-height: 0 und nannte die
   Kette damit durchgezogen — aber keines der beiden ist ein Flex-BEHÄLTER,
   und „darf schrumpfen" hilft nicht, wo nichts schrumpft. Der Abschnitt
   blieb ein Block, gab seine Höhe nicht weiter, und jedes Glied darunter
   war richtig gebaut und wirkungslos: kein eigener Scrollbereich, die
   Karte über die Fensterhöhe, das Eingabefeld abgeschnitten.
   Jetzt display: flex auf allen Gliedern der Hülle, .bh-public dazu.

   VIERTER Fehler derselben Variante, und wieder stand er vorher korrekt
   beschrieben in diesem Kommentar. Deshalb steht dort jetzt ein
   Pflichttest statt einer Beschreibung.

   0.1.7 — Zwei Abstandsfehler im Verlauf, beide aus §0c:

   (a) Der erste Eintrag klebte an der Kartenkante. .bh-thread__entry:
   first-child setzt padding-top: 0 — richtig, wenn der Behälter sein
   eigenes Polster hat. Ein Pane mit --flush hat keines, und 0.1.6 gab nur
   das waagerechte zurück. Jetzt auch das senkrechte; --bh-detail-scroll-
   min steigt um dieselben 16px, damit die zugesagten zwei Einträge zwei
   bleiben (border-box rechnet das Polster mit).

   (b) Der Abstand unter einem Datumstrenner hing davon ab, WAS folgte:
   ein Eintrag brachte 16px Polster plus Trennlinie (25px), ein Ereignis
   nur 8px (17px). Derselbe Trenner, zwei Abstände. Jetzt trägt der
   Trenner den Abstand allein, und was folgt, bringt keinen eigenen mehr
   mit — ein Element hinter einem Trenner braucht keine zweite Trennung.

   0.1.6 — .bh-detail__pane gibt das Polster zurück, das --flush der Karte
   nimmt. Nur waagerecht; das senkrechte holt 0.1.7 nach. (Die Version war
   bei diesem Schritt nicht mitgezogen worden.)

   0.1.5 — Die Kette war durchgezogen, aber unsymmetrisch: __scroll trug
   min-height: 0, der Composer trug nichts. Damit galt für ihn die
   automatische Mindestgröße eines Flex-Elements, er konnte nicht
   schrumpfen, und der Verlauf gab bis auf null nach. Jetzt sagen beide
   ausdrücklich, was sie sind. Dazu der Höhen-Haltepunkt, das ausgeblendete
   Fußband und das knappere Abschnittspolster — siehe DAS HÖHENBUDGET.

   0.1.4 — Die Kette der --fixed-Variante reichte nicht bis in die Hülle.
   Weder .bh-shell__content noch .bh-public__main/-__section trugen
   min-height: 0, also konnte der Inhaltsbereich nicht schrumpfen und
   __scroll bekam nie eine eigene Leiste. Beschrieben war die Kette seit
   0.1.3, durchgezogen nicht — die Variante hatte bis heute keinen Nutzer.

   0.1.3 — Variante .bh-detail--fixed: Die Seite scrollt nicht, ein
   benannter Bereich darin schon. Dazu .bh-detail__pane und __scroll.

   0.1.2 — Zwei Behälter, die ihre Kinder stapeln, taten es nicht selbst.
   .bh-detail__main setzte gar keinen Abstand (Karten berührten sich),
   .bh-props__danger ließ ihn als margin am Kind entstehen (12+8=20px).
   Beide folgen jetzt DESIGN.md §0c. Die zerstörenden Aktionen bekommen
   zusätzlich die Trennlinie, die ihnen fehlte.

   0.1.1 — Der Verlauf als Ganzes steht in einer Karte, zusammen mit dem
   Composer. Die einzelnen Einträge bleiben Zeilen, nicht Karten.
   (Präzisiert 0.1.11: Das gilt für die normal scrollende Detailseite.
   Unter --fixed steht der Verlauf ohne Karte direkt auf dem Seitengrund.)
   Benötigt: tokens.css, base.css, card.css, badge.css, avatar.css, field.css,
             select.css, tabs.css, button.css, divider.css,
             patterns/shell.css, patterns/public.css
   VENDORED — READ-ONLY.

   Verbindlich für: Ticket-Detail, Forum-Thread, Termin-Detail (Team Hub),
   Bewerbungs-Detail. Kein Baukasten — dieser Grundriss gilt.
   ═══════════════════════════════════════════════════════════════════════════ */

.bh-detail {
  --bh-detail-aside-w:     320px;
  --bh-detail-scroll-min:  160px;   /* zwei einzeilige Einträge à 80px   */
}

/* ═══ KOPF ══════════════════════════════════════════════════════════════════
   Eine Zeile, eine Grundlinie. Kein Hero, kein Verlauf, keine eigene Karte.
   Der Kopf wiederholt nichts, was in der Meta-Spalte steht: kein Status,
   kein Bearbeiter, keine Priorität.                                          */

.bh-detail__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--bh-space-4);
  flex-wrap: wrap;

  padding-bottom: var(--bh-space-4);
  margin-bottom: var(--bh-space-5);
  border-bottom: 1px solid var(--bh-border-subtle);
}

/* Links: ID, Titel, Kontextbezug. */
.bh-detail__ident {
  display: flex;
  align-items: baseline;
  gap: var(--bh-space-3);
  flex-wrap: wrap;
  min-width: 0;
}

.bh-detail__id {
  flex: none;
  font-family: var(--bh-font-mono);
  font-size: var(--bh-text-sm);
  color: var(--bh-text-muted);
  font-variant-numeric: tabular-nums;
}

.bh-detail__title {
  margin: 0;
  font-size: var(--bh-text-lg);
  font-weight: var(--bh-weight-semibold);
  color: var(--bh-text-primary);
  min-width: 0;
}

/* Kontextbezug: Kunde, Kategorie, Fraktion. Der einzige Akzentlink im Kopf. */
.bh-detail__context {
  flex: none;
  color: var(--bh-color-accent);
  font-size: var(--bh-text-sm);
  font-weight: var(--bh-weight-medium);
  border-radius: var(--bh-radius-sm);
  transition: color var(--bh-transition);
}
.bh-detail__context:hover  { color: var(--bh-color-accent-bright); text-decoration: underline; text-underline-offset: 2px; }
.bh-detail__context:active { color: var(--bh-color-accent-bright); }
.bh-detail__context:focus-visible {
  outline: var(--bh-focus-width) solid var(--bh-focus-color);
  outline-offset: var(--bh-focus-offset);
}

/* Rechts: sekundäre Meta und Aktionen. */
/* Mittig, nicht an der Grundlinie: rechts steht ein Knopf von 36px, links
   eine Textzeile von 12px. Eine gemeinsame Grundlinie gibt es, aber sie
   bedeutet nichts — sie schiebt den Knopf nach unten. */
.bh-detail__head-meta {
  display: flex;
  align-items: center;
  gap: var(--bh-space-4);
  margin-left: auto;
}
.bh-detail__created {
  color: var(--bh-text-muted);
  font-size: var(--bh-text-xs);
  white-space: nowrap;
}
.bh-detail__head-actions {
  display: flex;
  align-items: center;
  gap: var(--bh-space-2);
  align-self: center;
}

/* ═══ ZWEI SPALTEN ══════════════════════════════════════════════════════════ */

.bh-detail__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(300px, var(--bh-detail-aside-w), 360px);
  gap: var(--bh-space-5);
  align-items: start;
}

/* Die Hauptspalte stapelt Karten — also setzt SIE den Abstand, nicht die
   Karten. Bis 0.1.1 stand hier nur min-width, und der Abstand zwischen zwei
   Karten war 0: keine Regel im ganzen System trennte sie. Zwei von vier
   Detailseiten des ersten Projekts fingen das im Markup mit einem eigenen
   Stapel-Behälter ab, zwei nicht — derselbe Abstand an vier Stellen
   entschieden, zweimal gar nicht (DESIGN.md §0).

   Selbstheilend: wo bereits ein Stapel-Behälter steht, hat die Spalte genau
   ein Kind, und ein gap zwischen einem Kind wirkt nicht. Solche Seiten
   ändern sich durch diese Regel nicht.

   Derselbe Wert wie in der Meta-Spalte — eine Seite, ein Rhythmus. */
.bh-detail__main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--bh-space-4);
}

/* Meta-Spalte bleibt beim Scrollen stehen. */
.bh-detail__aside {
  position: sticky;
  top: var(--bh-space-5);
  display: flex;
  flex-direction: column;
  gap: var(--bh-space-4);
  max-height: calc(100vh - var(--bh-space-6) * 2);
  overflow-y: auto;
}

/* Der Umschalter existiert nur unterhalb von 1024px. */
.bh-detail__aside-toggle { display: none; }
.bh-detail__aside-panel  { display: flex; flex-direction: column; gap: var(--bh-space-4); }

/* ═══ HAUPTSPALTE — VERLAUF ═════════════════════════════════════════════════
   Ein Eintrag ist eine Zeile, keine Karte. Keine Autorenspalte links —
   Avatar, Name, Rolle und Zeit stehen inline in der Kopfzeile des Eintrags,
   der Text beginnt darunter am linken Rand.                                  */

/* Verlauf und Composer gehören in eine Karte — wie alles andere in der
   Hauptspalte.

   Bis 2026-09-15 stand der Verlauf hier nackt auf dem Seitenhintergrund. Das
   trägt, solange die Hauptspalte NUR aus Verlauf und Composer besteht. Sobald
   darüber Karten stehen — Hauptaktion, Arbeitsflächen —, bricht die Seite an
   dieser Stelle optisch: die Karten hören auf, und darunter fängt etwas
   anderes an. Deshalb ist die Karte jetzt die Regel und nicht die Ausnahme.

   Der Composer behält innerhalb der Karte seinen eigenen Rahmen: er ist ein
   Eingabefeld, und ein Rahmen ist dort die richtige Affordanz. */
.bh-thread { display: flex; flex-direction: column; }

/* position: relative trägt die Aktionsleiste — siehe dort. */
.bh-thread__entry {
  position: relative;
  padding: var(--bh-space-4) 0;
  border-top: 1px solid var(--bh-border-subtle);
}
/* Das ERSTE Kind des Verlaufs trennt sich von nichts ab — egal welcher Art
   es ist. Bis 0.1.11 galt das nur für __entry und __day; ein __event an
   erster Stelle behielt sein Polster und schob den Verlauf nach unten. */
.bh-thread > :first-child { border-top: 0; padding-top: 0; }

.bh-thread__entry-head {
  display: flex;
  align-items: center;
  gap: var(--bh-space-2);
  flex-wrap: wrap;
  margin-bottom: var(--bh-space-2);
}

.bh-thread__author {
  color: var(--bh-text-primary);
  font-size: var(--bh-text-sm);
  font-weight: var(--bh-weight-semibold);
}
a.bh-thread__author:hover { color: var(--bh-color-accent); }

.bh-thread__time {
  color: var(--bh-text-muted);
  font-size: var(--bh-text-xs);
  white-space: nowrap;
}
.bh-thread__time::before { content: "·"; margin-right: var(--bh-space-2); }

/* Aktionen des Eintrags erscheinen erst beim Überfahren. */
/* OBEN RECHTS, AUSSERHALB DES FLUSSES. Bis 0.1.12 stand hier
   margin-left: auto — das setzt voraus, dass die Leiste das letzte Kind
   von __entry-head ist. Steht sie irgendwo sonst im Eintrag (und das tut
   sie in jedem der drei Verläufe, die dieses Pattern tragen sollen), tut
   margin-left nichts und sie bricht auf eine eigene Zeile. opacity: 0 nimmt
   dann die Sichtbarkeit, aber nicht den Platz: ein unsichtbarer Streifen
   über jedem Namen.

   top: 8px, weil die Knöpfe 36px hoch sind und der Kopf bei 16px beginnt
   und 28px misst — 8 + 36 = 44 = 16 + 28, die Unterkanten treffen sich.

   opacity statt visibility oder display: nur so bleiben die Knöpfe in der
   Tabreihenfolge, und :focus-within kann sie überhaupt einblenden. Ein
   unsichtbarer Klick ist dabei nicht möglich: die Leiste liegt IM Eintrag,
   also blendet der Zeiger sie ein, bevor er sie erreicht. */
.bh-thread__entry-actions {
  position: absolute;
  top: var(--bh-space-2);
  right: 0;
  display: flex;
  gap: var(--bh-space-1);
  opacity: 0;
  transition: opacity var(--bh-transition);
}
.bh-thread__entry:hover .bh-thread__entry-actions,
.bh-thread__entry:focus-within .bh-thread__entry-actions { opacity: 1; }

.bh-thread__text {
  color: var(--bh-text-secondary);
  font-size: var(--bh-text-sm);
  line-height: var(--bh-leading-normal);
}
.bh-thread__text > :last-child { margin-bottom: 0; }

/* Interne Notiz — dieselbe Zeilenform, nur getönt. Keine eigene Karte. */
.bh-thread__entry--internal {
  background: var(--bh-color-warning-soft);
  border-left: 2px solid var(--bh-color-warning);
  padding-left: var(--bh-space-3);
  margin-left: calc(var(--bh-space-3) * -1);
  border-radius: 0 var(--bh-radius-md) var(--bh-radius-md) 0;
}

/* Eröffnungsbeitrag — die Anfrage selbst, als erster Eintrag des
   Verlaufs. Eine Kante, keine Fläche.

   Im ersten Projekt hieß das .is-opening-post und brachte Radius, Polster
   und eigene Ränder mit. Übernommen ist die Aussage, nicht die Regel: Die
   Zeilenform des Verlaufs gilt weiter.

   KEINE TÖNUNG, anders als bei --internal, und das ist Absicht (§0b: ein
   Kanal trägt eine Bedeutung). Die interne Notiz WILL auffallen, sie ist
   eine Warnung; dieser Eintrag sagt nur „hier fängt es an". Zwei
   verschiedene Absichten dürfen nicht dieselbe Lautstärke haben.

   Der Grund, warum es hier auch technisch nicht anders geht: Eine Tönung
   wirkt nach FLÄCHE, nicht nach Alpha. --internal steht über zwei, drei
   Zeilen. Der Eröffnungsbeitrag trägt Beschreibung UND Lösungsversuche und
   ist damit die größte Fläche der Seite — dieselben 15 % erschlagen dort
   alles andere. Ein Merkmal, dessen Stärke davon abhängt, wie viel jemand
   geschrieben hat, ist kein verlässliches Merkmal.

   VERWORFEN: dieselbe Fläche mit kleinerem Alpha (etwa 6 %) und einem
   neuen Token. Es scheitert an derselben Beobachtung — über die größte
   Fläche der Seite ist auch ein schwacher Ton noch der dominante Ton,
   und über einen kurzen Eintrag wäre er unsichtbar. Der Fehler säße dann
   nur woanders. Außerdem verlangt §4 für eine neue Stufe eine neue
   Aufgabe; hier brauchte es keine zusätzliche Stufe, sondern einen Kanal
   WENIGER.

   Was bleibt, trägt die Aussage vollständig: die Kante in Akzentfarbe —
   dieselbe Bauart wie --internal, nur in der Farbe des Anlasses — und die
   Einrückung, die sie in den Freiraum links stellt. Der Inhalt selbst
   nennt sich ohnehin beim Namen („Problembeschreibung",
   „Bisherige Lösungsversuche"); kein anderer Eintrag hat Überschriften.

   Der border-radius ist mit der Fläche entfallen: Ohne Hintergrund rundet
   er nichts, und eine Deklaration, die nichts tut, liest sich wie eine,
   die etwas tut. */
.bh-thread__entry--opening {
  border-left: 2px solid var(--bh-color-accent);
  padding-left: var(--bh-space-3);
  margin-left: calc(var(--bh-space-3) * -1);
}

/* Gelöscht: Der Eintrag bleibt stehen, sein Text tritt zurück. EIN
   Kanal — die Deckkraft. Farbe zusätzlich zu dimmen wäre dieselbe
   Aussage zweimal (DESIGN.md §0b). */
.bh-thread__entry.is-deleted .bh-thread__text { opacity: .6; }

/* ── Datumstrenner ───────────────────────────────────────────────────────── */
/* Der Trenner sitzt ZWISCHEN zwei Einträgen, mit gleichem Abstand nach oben
   und unten. Dass er zum Folgenden gehört, sagt die LINIE über ihm: sie
   trennt vom Vorherigen ab, und das Folgende bringt keine zweite mit (Regel
   darunter). Bis 0.1.11 stand hier 16 oben / 12 unten — ein
   Größenunterschied, der dieselbe Aussage ein zweites Mal machen sollte und
   dabei nur schief aussah (DESIGN.md §0b). */
.bh-thread__day {
  padding: var(--bh-space-4) 0;
  border-top: 1px solid var(--bh-border-subtle);
}
/* Was direkt hinter einem Trenner steht, trennt sich nicht noch einmal:
   keine zweite Linie, kein zweites Polster. Ohne diese Regel hing der
   Abstand an der Art des Nachbarn (Eintrag 25px, Ereignis 17px). */
.bh-thread__day + * { border-top: 0; padding-top: 0; }

.bh-thread__entry:first-child + .bh-thread__day,
.bh-thread__day:first-child { border-top: 0; padding-top: 0; }

/* ── Systemereignis ──────────────────────────────────────────────────────
   Eigene Zeilenart: kleines Icon, eine Zeile, gedämpft, ohne Avatarspalte.  */
.bh-thread__event {
  display: flex;
  align-items: center;
  gap: var(--bh-space-2);
  flex-wrap: wrap;

  padding: var(--bh-space-2) 0;
  border-top: 1px solid var(--bh-border-subtle);

  color: var(--bh-text-muted);
  font-size: var(--bh-text-xs);
}
.bh-thread__event:first-child { border-top: 0; }

/* DIE FARBE DES EREIGNISSES STEHT IM SYMBOL. Das Pattern erzeugt die
   Zustandsklassen seit 0.1.0 — bedient hat sie nie jemand, die Farbe lag
   im Projekt. Eine Klasse, die ein Pattern verlangt und nicht bedient,
   ist eine Aufgabe, die es an jedes Projekt weiterreicht.

   Nur das Symbol: Text und Fläche bleiben gedämpft. Ein Statuswechsel
   ist eine Zeile im Verlauf, keine Meldung — und der Punkt davor ist
   derselbe Kanal, den auch .bh-badge--dot benutzt (DESIGN.md §0b).
   Eine dritte Farbebene im Verlauf wäre zu viel (BACKLOG). */
.bh-thread__event.is-status-open > i,
.bh-thread__event.is-status-open > svg      { color: var(--bh-color-success); }
.bh-thread__event.is-status-in-progress > i,
.bh-thread__event.is-status-in-progress > svg { color: var(--bh-color-warning); }
.bh-thread__event.is-status-closed > i,
.bh-thread__event.is-status-closed > svg    { color: var(--bh-color-danger); }
.bh-thread__event.is-assigned > i,
.bh-thread__event.is-assigned > svg         { color: var(--bh-color-accent); }
/* Die beiden Teile der Ereigniszeile. Sie standen im ersten Projekt als
   .system-event-label und .system-event-by im Projekt-Stylesheet und
   sind beim Umbau auf .bh-thread__event umbenannt worden — ohne dass die
   Regeln mitkamen. Sie gehören hierher und nicht dorthin zurück: Wer
   Teile eines fremden Blocks im eigenen Stylesheet erfindet, hat eine
   Komponente an zwei Stellen (DESIGN.md §0).

   Zwei Stufen, mehr nicht: Die Aussage steht in der Beschriftung, der
   Urheber ist Beiwerk. Das <strong> darin hebt heraus, WAS gesetzt
   wurde — „Status auf FERTIG gesetzt". */
.bh-thread__event-label { color: var(--bh-text-secondary); }
.bh-thread__event-label strong {
  color: var(--bh-text-primary);
  font-weight: var(--bh-weight-semibold);
}
.bh-thread__event-by { color: var(--bh-text-muted); }

.bh-thread__event.is-forwarded > i,
.bh-thread__event.is-forwarded > svg        { color: var(--bh-color-accent); }
.bh-thread__event > svg { width: 14px; height: 14px; flex: none; }
.bh-thread__event strong { color: var(--bh-text-tertiary); font-weight: var(--bh-weight-medium); }
.bh-thread__event time { margin-left: auto; white-space: nowrap; }

/* ── Zitat ───────────────────────────────────────────────────────────────── */
.bh-thread__quote {
  margin: 0 0 var(--bh-space-3);
  padding: var(--bh-space-2) var(--bh-space-3);
  border-left: 2px solid var(--bh-border-strong);
  border-radius: 0 var(--bh-radius-md) var(--bh-radius-md) 0;
  background: var(--bh-surface-2);
  color: var(--bh-text-tertiary);
  font-size: var(--bh-text-sm);
}
.bh-thread__quote-author {
  display: block;
  margin-bottom: var(--bh-space-1);
  color: var(--bh-text-muted);
  font-size: var(--bh-text-xs);
  font-weight: var(--bh-weight-medium);
}

/* ── Anhänge ─────────────────────────────────────────────────────────────── */
.bh-thread__attachments {
  display: flex;
  flex-direction: column;
  gap: var(--bh-space-2);
  margin-top: var(--bh-space-3);
  padding-left: var(--bh-space-3);
  border-left: 1px solid var(--bh-border-subtle);
}
.bh-thread__attachment {
  display: flex;
  align-items: center;
  gap: var(--bh-space-2);
  min-height: var(--bh-control-height);
  padding: 0 var(--bh-space-3);
  border: 1px solid var(--bh-border-subtle);
  border-radius: var(--bh-radius-lg);
  background: var(--bh-surface-2);
  color: var(--bh-text-secondary);
  font-size: var(--bh-text-xs);
  transition: border-color var(--bh-transition), background var(--bh-transition);
}
.bh-thread__attachment > svg { width: var(--bh-icon-size); height: var(--bh-icon-size); flex: none; color: var(--bh-text-muted); }
.bh-thread__attachment:hover  { border-color: var(--bh-border-strong); background: var(--bh-surface-3); }
.bh-thread__attachment:active { background: var(--bh-surface-1); }
.bh-thread__attachment:focus-visible {
  outline: var(--bh-focus-width) solid var(--bh-focus-color);
  outline-offset: var(--bh-focus-offset);
}
.bh-thread__attachment-size { margin-left: auto; color: var(--bh-text-muted); font-variant-numeric: tabular-nums; }

/* ═══ META-SPALTE — KARTE 1: EIGENSCHAFTEN ══════════════════════════════════
   Bearbeitbare Felder als Zeilen, darunter genau EINE Primäraktion.
   Ein Feld erscheint entweder als Anzeige (.bh-props__value) oder als
   Bedienelement (.bh-select / .bh-input) — nie beides. Es gibt keine
   getrennte Details- und Aktionen-Karte mit denselben Feldern.               */

.bh-props { display: flex; flex-direction: column; gap: var(--bh-space-3); }

/* Nur-Anzeige-Zeile: gleiche Geometrie wie .bh-field--row, ohne Control. */
.bh-props__value {
  display: flex;
  align-items: center;
  min-height: var(--bh-control-height);
  color: var(--bh-text-secondary);
  font-size: var(--bh-text-sm);
}

.bh-props__action {
  margin-top: var(--bh-space-1);
  padding-top: var(--bh-space-3);
  border-top: 1px solid var(--bh-border-subtle);
}

/* Zerstörendes am Fuß der Karte: Ghost mit danger-Text, nie ein Farbblock.

   Der Abschluss nach oben ist eine Linie, kein Abstand. Bis 0.1.1 stand hier
   margin-top: 8px — zusammen mit dem 12px-gap der .bh-props ergab das 20px,
   einen Wert, den niemand gewählt hat und der auf keiner Stufe der Skala
   steht (DESIGN.md §0c). Zu wenig, um als Abschluss zu wirken, zu viel für
   eine Zeile. Jetzt trägt der Block seine Polsterung und seine Linie selbst;
   der Abstand davor kommt allein vom Behälter.

   gap wie der Zeilenrhythmus der Karte: die Aktionen stehen im selben Takt
   wie alles darüber, nicht enger. */
.bh-props__danger {
  display: flex;
  flex-direction: column;
  gap: var(--bh-space-3);
  padding-top: var(--bh-space-4);
  border-top: 1px solid var(--bh-border-subtle);
}

/* ═══ META-SPALTE — KARTE 2: SEKUNDÄRES MATERIAL ════════════════════════════
   Dateien / Aktivität / Verknüpfungen / Zeit hinter Tabs. Mehr als zwei
   Karten hat diese Spalte nicht.                                             */

.bh-aside-list { display: flex; flex-direction: column; }
.bh-aside-list__item {
  display: flex;
  align-items: center;
  gap: var(--bh-space-2);
  padding: var(--bh-space-2) 0;
  border-top: 1px solid var(--bh-border-subtle);
  color: var(--bh-text-secondary);
  font-size: var(--bh-text-xs);
}
.bh-aside-list__item:first-child { border-top: 0; }
.bh-aside-list__item > svg { width: 14px; height: 14px; flex: none; color: var(--bh-text-muted); }
.bh-aside-list__meta { margin-left: auto; color: var(--bh-text-muted); white-space: nowrap; }

/* Zwei Formen, und die zweite kam am 2026-10-01 dazu:

     (1) Der Eintrag IST der Verweis.          <a class="bh-aside-list__item">
     (2) Der Eintrag ENTHAELT einen Verweis    <div class="bh-aside-list__item">
         und daneben eine Aktion.                <a href=…>…</a>
                                                 <form>…</form>
                                               </div>

   Form (2) ist nicht die Abweichung eines Projekts, sondern der Normalfall,
   sobald ein Eintrag etwas anderes kann als geoeffnet werden — im
   Ticketsystem steht neben jedem verknuepften Ticket ein Knopf zum
   Entknuepfen. Ein Formular in einem Verweis waere ungueltiges Markup, der
   Eintrag MUSS dort ein div bleiben.

   Bis dahin griff die Hover-Regel nur bei (1), und der Verweis in (2) war
   nach dem Entfernen der globalen a-Farbe nicht mehr als Verweis erkennbar. */
a.bh-aside-list__item,
.bh-aside-list__item > a { border-radius: var(--bh-radius-sm); transition: color var(--bh-transition); }
a.bh-aside-list__item:hover,
.bh-aside-list__item > a:hover { color: var(--bh-color-accent); }
a.bh-aside-list__item:focus-visible,
.bh-aside-list__item > a:focus-visible {
  outline: var(--bh-focus-width) solid var(--bh-focus-color);
  outline-offset: var(--bh-focus-offset);
}

/* ═══ COMPOSER ══════════════════════════════════════════════════════════════
   Unten in der Hauptspalte: Tabs, Textarea, Fußzeile.                        */

.bh-composer {
  margin-top: var(--bh-space-5);
  border: 1px solid var(--bh-border-subtle);
  border-radius: var(--bh-radius-xl);
  background: var(--bh-surface-1);
  transition: border-color var(--bh-transition), box-shadow var(--bh-transition);
}
.bh-composer:focus-within {
  border-color: var(--bh-color-accent);
  box-shadow: var(--bh-focus-ring);
}

.bh-composer > .bh-tabs { padding: 0 var(--bh-space-4); }

.bh-composer__body { padding: var(--bh-space-3) var(--bh-space-4); }

/* Die Textarea sitzt flächenbündig; den Fokus zeigt der Composer selbst. */
.bh-composer__body .bh-textarea {
  border: 0;
  background: transparent;
  padding: 0;
  min-height: calc(var(--bh-control-height) * 2.5);
  resize: vertical;
}
.bh-composer__body .bh-textarea:focus,
.bh-composer__body .bh-textarea:hover { box-shadow: none; border: 0; }

.bh-composer__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--bh-space-3);
  padding: var(--bh-space-3) var(--bh-space-4);
  border-top: 1px solid var(--bh-border-subtle);
}
.bh-composer__hint { color: var(--bh-text-muted); font-size: var(--bh-text-xs); }
.bh-composer__actions { display: flex; align-items: center; gap: var(--bh-space-2); margin-left: auto; }

/* Interner Modus färbt nur den Rand — der Composer wechselt nicht die Gestalt. */
.bh-composer.is-internal { border-color: var(--bh-color-warning); }
.bh-composer.is-internal .bh-composer__hint { color: var(--bh-color-warning); }

/* ═══ VARIANTE: DIE SEITE SCROLLT NICHT ═════════════════════════════════════
   .bh-detail--fixed am Wurzelelement schaltet um: Das Fenster steht, und
   EIN benannter Bereich darin scrollt. Für Arbeitsansichten, bei denen das
   Eingabefeld sichtbar bleiben muss — Ticket-Verlauf, Forum-Thread, Chat.

   Keine eigene Komponente: Es ist dieselbe Detailseite, nur mit anderem
   Überlaufverhalten. Auch die Meta-Spalte bleibt .bh-detail__aside und
   ändert allein ihr Verhalten — zwei Varianten einer Aufgabe, nicht zwei
   Bauteile.

   body:has(…) statt einer Klasse am body: Die Seite erklärt sich dadurch,
   dass sie das Element enthält. Niemand muss an eine zusätzliche Klasse
   denken, und niemand kann sie vergessen.

   DIE KETTE. Jedes Glied braucht min-height: 0, sonst schrumpft ein Flex-
   oder Grid-Element nicht unter seine Inhaltsgröße:

     body → Shell → Inhaltsbereich → --fixed → __body → __main → __pane
                                                                  → __scroll

   Fehlt es an EINER Stelle, wächst der Inhalt über den Bildschirm hinaus,
   __scroll bekommt nie eine eigene Scrollleiste, und das overflow: hidden
   am body schneidet den Rest ab. Siehe GUIDE.md, „Eine Seite, die nicht
   scrollt".

   ══ PFLICHTTEST, BEVOR JEMAND DIESE VARIANTE ALS FERTIG MELDET ══

   Zwei Tickets öffnen: eines mit WENIGEN Antworten und eines mit VIELEN.

     kurz  Die Karte ist so hoch wie ihr Inhalt, das Eingabefeld sitzt
           direkt darunter, die Seite scrollt nicht.
     lang  Der Verlauf bekommt eine EIGENE Scrollleiste, die Karte endet
           an der Fensterkante, das Eingabefeld bleibt sichtbar.

   Dazu bei BEIDEN:
     · Die Unterkanten der zwei Spalten liegen auf EINER Linie.
     · Unter dem Eingabefeld bleibt ein Rand zum Fensterrand, so groß wie
       der Abstand zwischen Kopf und Inhalt (beide --bh-space-5). Nichts
       klebt am unteren Bildschirmrand.

   Fehlt beim langen Ticket die Scrollleiste, wächst die Karte über das
   Fenster hinaus und das Eingabefeld ist unten abgeschnitten — dann ist
   ein Glied der Kette gebrochen. Von unten nach oben suchen: das erste
   Element, das WEDER Flex-Behälter ist NOCH eine begrenzte Höhe hat.

   Das kurze Ticket allein beweist nichts: dort sieht auch eine völlig
   gebrochene Kette richtig aus, weil nichts überläuft. Genau daran sind
   hier vier Fehler vorbeigekommen (0.1.4 Kette, 0.1.5 Symmetrie, 0.1.6
   Polster, 0.1.8 Flex-Behälter) — jeder stand vorher korrekt in diesem
   Kommentar beschrieben.

   WANN DIESE VARIANTE PASST — und wann nicht. Zwei Merkmale, an denen
   sich die Frage ohne Diskussion entscheiden lässt:

     1. WECHSELT MAN ZWISCHEN LESEN UND SCHREIBEN? Die Variante löst ein
        einziges Problem: Das Eingabefeld muss sichtbar bleiben, während
        man den Verlauf liest. Das ist eine Arbeitsansicht — ein Ticket,
        ein Chat, ein Thread, den man bearbeitet. Ein Text, den man
        EINMAL von oben nach unten liest, ist es nicht.

     2. IST DER SCROLLBEREICH EINDEUTIG? Die Kette verlangt GENAU EINEN
        benannten Bereich, der scrollt. Steht über dem Verlauf noch
        etwas, das selbst lang werden kann, gibt es zwei Kandidaten —
        und zwei Scrollbereiche untereinander sind schlechter als eine
        scrollende Seite.

   GEPRÜFT UND ABGELEHNT (2026-09-23), Team Hub:

     post.php   — Der Beitragstext steht über dem Verlauf und kann lang
                  werden. Zwei Kandidaten für den einen Scrollbereich;
                  Merkmal 2 nicht erfüllt. Ein Beitrag wird ausserdem
                  gelesen, nicht bearbeitet (Merkmal 1).
     event.php  — Über dem Verlauf stehen VIER Karten, und es sind die,
                  für die man die Seite öffnet: Rückmeldung, Anwesenheit,
                  Rückblick, Aufgaben. Der Verlauf ist dort die
                  Nebensache. Eine stehende Seite klemmte das Wichtigste
                  oben ein, damit das Unwichtigste unten sichtbar bleibt.

   Beide Seiten hätten die Kette technisch erfüllt — es fehlten nur
   __pane, __scroll und die Klasse. Das ist der Punkt: Die Variante
   passt nicht deshalb nicht, weil sie nicht ginge.

   Was stattdessen gebaut wurde: ein Sprungverweis „Zum Kommentieren"
   im Detailkopf. Eine Zeile Markup, kein Kettenrisiko, und er wirkt
   auch unterhalb der Haltepunkte, wo --fixed ohnehin abgeschaltet ist.

   STATUS (2026-09-21, DESIGN.md §0e): Die Variante wird von genau EINER
   Seite getragen — view_ticket.php im Ticketsystem — und die Sichtprüfung
   läuft noch. Sie ist damit nicht mehr ungeprüft, aber auch noch nicht
   bestätigt. Drei Fehler hat die erste echte Seite schon herausgeholt
   (0.1.4 Kette, 0.1.5 Symmetrie, 0.1.6 Polster); alle drei standen vorher
   in diesem Kommentar als Beschreibung. Wer die Variante als zweiter
   aufnimmt, rechnet mit einem vierten.

   ZWEI HALTEPUNKTE, ZWEI FRAGEN. Die Breite entscheidet, ob zwei Spalten
   nebeneinander passen; die Höhe entscheidet, ob die Kette überhaupt
   aufgeht. Verschiedene Fragen, deshalb zwei Werte — aber EINE Bedingung,
   unter der die Variante gilt: min-width 1024px UND min-height 641px.
   Darunter ist sie wirkungslos, und die Seite scrollt wie jede andere.

   Breite, 1023px — Abweichung vom Bestand, absichtlich: Das Vorbild
   (ticketsystem.bluehorizonrp.com) schaltet die Shell bei 900px ab. Der
   DS-Wert ist der begründetere: Dort wird .bh-detail__body ohnehin
   einspaltig, und zwei Haltepunkte für dieselbe Umschaltung wären eine
   zweite Wahrheit (DESIGN.md §0). Zwischen 900 und 1023px scrollt die
   Seite künftig, statt zu stehen.

   Höhe, 640px — KORREKTUR EINER FRÜHEREN EINORDNUNG: Der Bestand hatte
   einen zweiten Haltepunkt, `@media (max-height: 900px)`, und ich habe ihn
   beim Aufnehmen der Variante als Einzelfall des Projekts abgelegt. Das war
   falsch. Eine Seite, die nicht scrollt, hat ein endliches Höhenbudget;
   unterschreitet das Fenster die Summe ihrer festen Teile, kann keine
   Kette es retten — der Inhalt wird abgeschnitten, weil body: hidden ihn
   abschneidet. Der Haltepunkt ist keine Marotte des Vorbilds, sondern eine
   Bedingung der Variante. Nur der WERT war projekteigen: 900px war
   geraten, hier ist er gerechnet.

   DAS HÖHENBUDGET (Desktop, öffentliche Hülle):

     102px  Leiste: 32 margin + 2×16 Polster + 36 Inhalt + 2 Rahmen
      48px  Abschnittspolster, 2 × --bh-space-5 (unter --fixed)
      76px  .bh-detail__head: 36 Inhalt + 16 padding + 24 margin
       0px  Fußband — unter --fixed ausgeblendet
     ────
     226px  Rahmenwerk

      24px  .bh-composer margin-top          36px  Reiterzeile
       2px  Rahmen                           24px  __body-Polster
      72px  Textfeld, Mindesthöhe            60px  __foot
     ────
     218px  Composer, leer

     176px  Verlauf: zwei einzeilige Einträge à 80px + 16px Polster
     ════
     620px  Mindest-Fensterhöhe  →  Haltepunkt 640px, 20px Luft.
            (Mit 0.1.7 stieg --bh-detail-scroll-min von 160 auf 176, weil
            der Scrollbereich sein senkrechtes Polster dazubekam und
            border-box es mitrechnet. Die Luft schrumpfte damit von einer
            Bedienhöhe auf 20px. Wer noch etwas ans Rahmenwerk hängt,
            verschiebt den Haltepunkt mit — er ist gerechnet, nicht
            gewählt.)

   Wer am Rahmenwerk etwas hinzufügt, rechnet hier nach. Die Zeile, die
   dabei am ehesten kippt, ist der Verlauf: er ist das einzige Glied, das
   nachgibt, und er ist es, dem alles andere seinen Platz wegnimmt.        */

/* OHNE KARTE, OHNE POLSTER. Bis 0.1.10 trug der Pane eine Karte mit
   --flush, und 0.1.6 gab ihr das Polster zurück, das --flush ihr nimmt.
   Beides ist entfallen: Der Verlauf beginnt an derselben Kante wie der
   Kopf darüber, weil .bh-public__section sein Polster schon setzt. Ein
   zweites daneben rückte ihn gegen den Kopf ein.

   Der Abstand nach oben kommt vom margin-bottom des Kopfes, der nach
   unten vom Polster des Abschnitts — beide --bh-space-5, damit die Seite
   oben und unten gleich viel Luft hat. */
/* EINE MEDIENABFRAGE SCHALTET DIE VARIANTE EIN — nicht zwei Blöcke, von
   denen einer sie wieder abschaltet. Der Unterschied ist nicht Geschmack:
   Ein Ausschalt-Block muss jeden genommenen Wert ZURÜCKGEBEN, und wer
   dabei „padding-block: 48px" schreibt, überschreibt damit auch das
   knappere Mobilpolster aus public.css, das gar nicht gemeint war. Was
   nie gesetzt wurde, muss nicht zurückgegeben werden.

   Außerhalb dieser Abfrage ist .bh-detail--fixed schlicht wirkungslos:
   eine gewöhnliche Detailseite, die normal scrollt. Genau das soll auf
   schmalen und auf niedrigen Fenstern geschehen.                          */
@media (min-width: 1024px) and (min-height: 641px) {

body:has(.bh-detail--fixed) {
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
}

.bh-detail--fixed {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;   /* Auto-Margins auf der Querachse heben sonst das stretch auf */
}

/* DIE KETTE REICHT BIS IN DIE HÜLLE. --fixed setzt overflow: hidden am
   body; damit der Inhaltsbereich darunter überhaupt schrumpfen kann,
   braucht jedes Flex-Glied min-height: 0 — sonst hält ihn seine
   Inhaltsgröße auf, --fixed wächst über den Bildschirm hinaus und
   __scroll bekommt nie eine eigene Leiste. Beide Hüllen bringen das nicht
   von sich aus mit: für jede andere Seite wäre es ohne Wirkung, und eine
   Hülle soll nicht wissen müssen, was eines Tages in ihr steht.

   Deshalb steht es hier und nicht in shell.css/public.css: die Bedingung
   gehört der Variante, die sie stellt (DESIGN.md §0). Die Variante greift
   ohnehin schon auf body zu.

   DISPLAY: FLEX IST DER EIGENTLICHE TEIL, min-height: 0 nur die Hälfte.
   0.1.4 setzte hier ausschließlich min-height: 0 — das heißt „darf
   schrumpfen" und sagt nichts darüber, ob das Element überhaupt in einem
   Zusammenhang steht, in dem Schrumpfen vorkommt. Bei .bh-shell__content
   stimmte es, weil das seit shell.css 0.1.1 ohnehin eine Flex-Spalte ist;
   auf dem öffentlichen Weg fehlte die Voraussetzung. .bh-public__main hat
   flex: 1 und ist damit ein Flex-KIND, aber ohne display: flex kein
   Flex-BEHÄLTER — der Abschnitt darin blieb ein Block, und ein Block gibt
   seine begrenzte Höhe nicht weiter. Ab dort war jedes weitere Glied
   richtig gebaut und wirkungslos.

   .bh-public kommt mit in die Liste: es trägt min-height: 100vh, der body
   height: 100dvh. Auf dem Desktop dasselbe, aber min-height: 0 macht es
   exakt so hoch wie der body und nimmt die Frage ganz heraus. Der Fuß ist
   unter --fixed ohnehin ausgeblendet.

   Gefunden beim ersten echten Nutzer — bis dahin hatte die Variante keinen,
   und die Kette war nur beschrieben, nicht durchgezogen. */
body:has(.bh-detail--fixed) .bh-shell__content,
body:has(.bh-detail--fixed) .bh-public,
body:has(.bh-detail--fixed) .bh-public__main,
body:has(.bh-detail--fixed) .bh-public__section {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* SYMMETRIE. Jedes Glied der Spalte sagt ausdrücklich, ob es nachgibt.
   Vorher trug __scroll min-height: 0 und der Composer gar nichts — er war
   dann fest, aber nur als Nebenwirkung der automatischen Mindestgröße von
   Flex-Elementen. Das trug bis zu dem Punkt, an dem das Fenster kleiner
   wurde als er: dann gab er immer noch nicht nach, sondern lief unten aus
   der Karte. Eine Größe, die nur zufällig stimmt, ist keine Größe. */
.bh-detail--fixed > .bh-detail__head { flex: 0 0 auto; }
.bh-detail--fixed > .bh-detail__body { flex: 1 1 auto; min-height: 0; }
.bh-detail--fixed .bh-detail__main   { min-height: 0; }
.bh-detail--fixed .bh-composer       { flex: 0 0 auto; }

/* DAS FUSSBAND UND DAS POLSTER. Beides kostet Höhe, die hier niemand hat:
   Auf einer Seite, die nicht scrollt, steht das Fußband dauerhaft im Bild,
   ohne je gelesen zu werden — Version und Copyright stehen auf jeder
   anderen Seite. Das Abschnittspolster (--bh-section-gap, 2 × 48px) trennt
   Sektionen voneinander; unter --fixed gibt es nur eine. */
body:has(.bh-detail--fixed) .bh-public__footer  { display: none; }
body:has(.bh-detail--fixed) .bh-public__section { padding-block: var(--bh-space-5); }

/* Behälter und Scrollbereich gelten NUR hier: Beide beschreiben, wie sich
   eine Spalte verhält, die eine feste Fensterhöhe füllt. Auf einer normal
   scrollenden Seite hätte max-height: 100% keinen sinnvollen Bezug und
   overflow-y: auto nichts zu verwalten. Die Erklärung zu beiden steht
   unterhalb der Abfrage, bei ihren Namen. */
.bh-detail__pane {
  display: flex;
  flex-direction: column;
  max-height: 100%;
  min-height: 0;
}

.bh-detail__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;

  /* Dünn und in den Flächenfarben. Die Voreinstellung des Systems ist für
     ein Dokumentfenster gedacht und wirkt in einer Spalte wie ein
     Fremdkörper. scrollbar-color nennt zuerst den Griff, dann die Bahn —
     die Bahn bleibt durchsichtig, also die Fläche, auf der sie liegt. */
  scrollbar-width: thin;
  scrollbar-color: var(--bh-border-strong) transparent;

  /* Luft zwischen Inhalt und Leiste. Ohne sie stößt der Zeitstempel, der per
     margin-left: auto ganz nach rechts geht, direkt an den Griff.
     scrollbar-gutter hält den Platz auch frei, wenn gerade nichts zu
     scrollen ist — sonst springt der Inhalt beim Nachladen. */
  padding-right: var(--bh-space-3);
  scrollbar-gutter: stable;
}

/* Die Untergrenze des Verlaufs — siehe .bh-detail__scroll weiter unten.
   Nur hier: auf einer normal scrollenden Seite gibt es nichts, wogegen
   eine Untergrenze schützen müsste. */
.bh-detail--fixed .bh-detail__scroll { min-height: var(--bh-detail-scroll-min); }

/* Die Meta-Spalte scrollt gegen die Shell statt gegen den Viewport. In
   einer Seite, die nicht scrollt, hat sticky nichts, woran es kleben
   könnte, und calc(100vh - …) rechnet gegen die falsche Bezugsgröße. */
.bh-detail--fixed .bh-detail__aside {
  position: static;
  top: auto;
  max-height: 100%;
  overflow-y: auto;
}

/* BEIDE SPALTEN AUF DERSELBEN UNTERKANTE. align-items: start am Gitter ist
   für die normale Detailseite richtig — eine kurze Karte soll nicht auf die
   Länge der Nachbarspalte gezogen werden. Unter --fixed hat die Seite eine
   feste Höhe: die Hauptspalte füllt sie, und ohne stretch endete die
   Meta-Spalte auf halber Strecke, während links der Verlauf bis zum Rand
   lief.

   Die LETZTE Karte nimmt den Rest, nicht alle gleichmäßig: die oberen sind
   so hoch wie ihr Inhalt. Eine Eigenschaftsliste auseinanderzuziehen, nur
   weil Platz da ist, wäre eine Menge ohne Aussage (DESIGN.md §0d). */
/* DAS ANTWORTFELD IST EINE LINIE, KEIN KASTEN — dieselbe Bedingung wie
   der Verlauf ohne Karte, also dieselbe Stelle. Rahmen, Radius, Fläche und
   der Abstand nach oben fallen; was bleibt, ist die Trennlinie. Das
   waagerechte Polster geht mit, damit Reiter, Text und Fuß auf derselben
   Kante stehen wie die Einträge darüber. */
.bh-detail--fixed .bh-composer {
  margin-top: 0;
  border: 0;
  border-top: 1px solid var(--bh-border-subtle);
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.bh-detail--fixed .bh-composer:focus-within {
  border-color: var(--bh-border-subtle);
  box-shadow: none;
}
.bh-detail--fixed .bh-composer.is-internal { border-color: var(--bh-color-warning); }
.bh-detail--fixed .bh-composer > .bh-tabs,
.bh-detail--fixed .bh-composer__body,
.bh-detail--fixed .bh-composer__foot { padding-inline: 0; }

/* Eine Linie über dem Composer reicht. Die zweite zwischen Textfeld und Fuß
   stammt aus der Kastenfassung, wo sie den Fuß vom Feld abgrenzte — im
   flachen Composer zerschneidet sie ihn in zwei Streifen. */
/* Dasselbe gilt für das Polster darunter: im Kasten trennt es den Knopf vom
   Rahmen, ohne Rahmen schiebt es ihn nur über die Unterkante, auf der die
   Meta-Spalte liegt. Oben bleibt es — dort trennt es den Fuß vom Textfeld,
   und das ist keine Kante, sondern ein Nachbar. */
.bh-detail--fixed .bh-composer__foot {
  border-top: 0;
  padding-bottom: 0;
  /* Der Abstand zum Textfeld war die Summe zweier Polster: __body unten
     12px plus __foot oben 12px = 24, während Reiter → Textfeld nur 12
     bekam. Ein Abstand, zwei Stellen — die Summe aus §0c. Er gehört dem
     __body, der die Reihe stapelt; der Fuß gibt seinen ab. */
  padding-top: 0;
}

/* align-content: start dazu. stretch allein macht die Zeile immer so hoch
   wie der Behälter — dann reicht die Meta-Spalte bis zum Fensterrand,
   während die Hauptspalte unter dem Composer endet. Mit start ist die Zeile
   so hoch wie der HÖHERE der beiden Inhalte (nach oben gedeckelt durch
   max-height: 100%), und stretch zieht die andere Spalte darauf. Kurzer
   Vorgang: beide enden unter dem Composer. Langer: beide am Fensterrand. */
.bh-detail--fixed .bh-detail__body {
  align-items: stretch;
  align-content: start;
}
/* <details> IST EIN SONDERFALL. Chrome ≥131 schiebt alles außer <summary>
   in ein ::details-content und macht daraus eine eigene Box — der Panel ist
   dann KEIN Flex-Kind des <details> mehr, flex: 1 greift ins Leere, und die
   Meta-Spalte hört auf halber Strecke auf, obwohl die Regel richtig
   aussieht. Firefox und Safari tun das (noch) nicht. Beide Wege müssen
   tragen; wer ::details-content nicht kennt, übergeht die Regel still. */
.bh-detail--fixed .bh-detail__aside::details-content {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.bh-detail--fixed .bh-detail__aside-panel { flex: 1 1 auto; min-height: 0; }
.bh-detail--fixed .bh-detail__aside-panel > :last-child { flex: 1 1 auto; }

} /* Ende der Einschalt-Abfrage */

/* Der Behälter, der die Spalte füllt und seinen Überlauf selbst verwaltet.
   Muss DIREKTES Grid-Item sein: Prozenthöhen rechnen gegen die Grid-Area,
   und die ist auch bei align-items: start definit. Ein Zwischen-Wrapper
   hätte Inhaltshöhe, und max-height: 100% rechnete gegen eine unbestimmte.

   Die Karte erzwingt keine volle Höhe: kurzer Vorgang → Pane so hoch wie
   sein Inhalt, das Eingabefeld sitzt direkt darunter. Langer Vorgang →
   Pane stößt an die Fensterhöhe, __scroll scrollt in sich, das
   Eingabefeld steht fest. Deshalb max-height statt height. */
/* Der EINE Bereich, der scrollt. Ein eigener Name, weil das Pattern sonst
   raten müsste, was in der Spalte steht.

   min-height: 0 heißt „darf schrumpfen", nicht „darf verschwinden". Unter
   --fixed bekommt er deshalb eine Untergrenze: Er ist das einzige Glied,
   das nachgibt, also nimmt ihm jedes andere seinen Platz weg, bis nichts
   bleibt. Der Wert ist gerechnet, nicht gegriffen — zwei einzeilige
   Einträge:

     1 Rand + 2×16 Polster + 19.5 Kopf + 8 + 19.5 Text = 80px, mal zwei.

   Zwei, weil einer nicht zeigt, dass es eine Liste ist. Ein Längenmaß aus
   dem Inhalt, wie --bh-detail-aside-w und --bh-field-label-w; die
   geschlossenen Skalen aus DESIGN.md §4 betreffen Abstände, Schrift,
   Radien und Schatten, nicht Layoutmaße. Wer eine andere Untergrenze
   braucht, setzt --bh-detail-scroll-min von außen. */
/* ═══ UMBRÜCHE ══════════════════════════════════════════════════════════════ */

@media (max-width: 1023px) {
  /* Meta-Spalte klappt über den Verlauf und ist standardmäßig zu. */
  .bh-detail__body { grid-template-columns: minmax(0, 1fr); }

  .bh-detail__aside {
    position: static;
    order: -1;
    max-height: none;
    overflow: visible;
    gap: 0;
    border: 1px solid var(--bh-border-subtle);
    border-radius: var(--bh-radius-xl);
    background: var(--bh-surface-1);
  }

  .bh-detail__aside-toggle {
    display: flex;
    align-items: center;
    gap: var(--bh-space-2);
    width: 100%;
    min-height: var(--bh-control-height);
    padding: var(--bh-space-2) var(--bh-space-4);
    border: 0;
    border-radius: var(--bh-radius-xl);
    background: none;
    color: var(--bh-text-primary);
    font-family: inherit;
    font-size: var(--bh-text-sm);
    font-weight: var(--bh-weight-semibold);
    cursor: pointer;
    list-style: none;
  }
  .bh-detail__aside-toggle::-webkit-details-marker { display: none; }
  .bh-detail__aside-toggle:hover { background: var(--bh-surface-hover); }
  .bh-detail__aside-toggle:focus-visible {
    outline: var(--bh-focus-width) solid var(--bh-focus-color);
    outline-offset: calc(var(--bh-focus-offset) * -1);
  }
  .bh-detail__aside-toggle::after {
    content: "";
    margin-left: auto;
    width: 8px; height: 8px;
    border-right: 2px solid var(--bh-text-muted);
    border-bottom: 2px solid var(--bh-text-muted);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform var(--bh-transition);
  }
  .bh-detail__aside[open] .bh-detail__aside-toggle::after { transform: rotate(225deg) translate(-2px, -2px); }

  .bh-detail__aside-panel { padding: 0 var(--bh-space-4) var(--bh-space-4); }

  /* Die Karten der Meta-Spalte sind hier schon in einem Rahmen. */
  .bh-detail__aside-panel > .bh-card { border: 0; box-shadow: none; padding-left: 0; padding-right: 0; }
  .bh-detail__aside-panel > .bh-card + .bh-card { border-top: 1px solid var(--bh-border-subtle); border-radius: 0; }
}

@media (min-width: 1024px) {
  /* Oberhalb der Grenze gibt es keinen Umschalter — die Spalte steht immer. */
  .bh-detail__aside-toggle { display: none; }
  .bh-detail__aside-panel  { display: flex; }
}

@media (max-width: 767px) {
  .bh-detail__head { align-items: flex-start; }
  .bh-detail__head-meta { margin-left: 0; width: 100%; justify-content: space-between; }
  .bh-thread__entry-actions { opacity: 1; }
  .bh-composer__foot { flex-wrap: wrap; }
}

@media (prefers-reduced-motion: reduce) {
  .bh-thread__entry-actions { transition: none; }
  .bh-detail__aside-toggle::after { transition: none; }
}

@media print {
  .bh-composer, .bh-detail__head-actions, .bh-thread__entry-actions { display: none !important; }
  .bh-detail__body { grid-template-columns: 1fr; }
  .bh-detail__aside { position: static; max-height: none; }
}
