/* ==========================================================================
   Fachdidaktik Chemie — Grundstil
   Eine Datei, dazu je Theme eine Datei mit den Farb-Tokens.
   Kein Framework, kein Build-Schritt.

   Aufbau
     1. Schrift
     2. Tokens
     3. Grundlagen
     4. Geruest (Satzspiegel)
     5. Seitenleiste
     6. Inhalt
     7. Suchpalette
     8. Schmale Fenster
     9. Bewegung und Druck
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Schrift
   -------------------------------------------------------------------------- */

/* Eine Familie für die ganze Site. Instrument Sans ist eine variable
   Schrift: ein Gewichtsbereich 400–700 und eine Breite 75–100 % in einer
   Datei — das spart fünf Anfragen und macht Zwischengewichte möglich.
   `swap`, damit beim ersten Besuch sofort etwas Lesbares dasteht.

   Monospace gibt es nur noch für echten Code (`code`, `pre`, `kbd`).
   Eine Dateiendung, ein Datum oder eine Anzahl ist kein Code; Mono hat
   dort nur Unruhe gestiftet. Zahlen stehen stattdessen überall auf
   Tabellenziffern. */

@font-face {
	font-family: "Instrument Sans";
	src: url("../fonts/instrument-sans-latin-variable.woff2") format("woff2");
	font-weight: 400 700;
	font-stretch: 75% 100%;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
		U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
		U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Instrument Sans";
	src: url("../fonts/instrument-sans-latin-ext-variable.woff2") format("woff2");
	font-weight: 400 700;
	font-stretch: 75% 100%;
	font-style: normal;
	font-display: swap;
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
		U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
		U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
		U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   2. Tokens
   Die Farbwerte sind die Vorgabe, falls noch kein Theme geladen ist.
   :where() setzt die Spezifitaet auf null, damit jede Theme-Datei gewinnt,
   unabhaengig von der Ladereihenfolge.
   -------------------------------------------------------------------------- */

:where(:root) {
	--bg: #eff1f5;
	--bg-sidebar: #e6e9ef;
	--surface: #e6e9ef;
	--surface-2: #dce0e8;
	--border: #bcc0cc;
	--text: #4c4f69;
	--text-muted: #6c6f85;
	--text-faint: #8c8fa1;
	--accent: #1e66f5;
	/* Der Akzent als TEXTFARBE. Er ist nicht derselbe Wert wie `--accent`:
	   eine Farbe, die als Kante, Unterstrich und Fokusring richtig sitzt,
	   ist als Schrift auf hellem Grund oft zu hell (Ayu Light: 1.9 : 1).
	   Darum fuehrt jede Theme-Datei beide Werte; `--accent-text` haelt
	   4.5 : 1 gegen Grund, Leiste und Flaeche (tools/kontrast.mjs). */
	--accent-text: #024edc;
	--accent-contrast: #ffffff;
	--accent-2: #8839ef;
	--link: #1e66f5;
	--ok: #327c21;
	--warn: #97631b;
	--danger: #d20f39;
	--selection: rgba(30, 102, 245, 0.22);
	/* Dateityp als dezente Farbe am Symbol und an der Formatmarke:
	   PDF rot, Word blau, Excel gruen, PowerPoint ocker. Die Familie ist
	   in allen Themes dieselbe, die Helligkeit kommt aus der Theme-Datei. */
	--datei-pdf: #944f4b;
	--datei-text: #486491;
	--datei-table: #3f6c52;
	--datei-slides: #865a27;
	--shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 4px 12px rgba(0, 0, 0, 0.06);
}

/* Vorgabe fuer dunkle Modi, ebenfalls ohne Spezifitaet: greift nur, solange
   keine Theme-Datei geladen ist. */
:where(:root[data-modus="dunkel"]) {
	--datei-pdf: #e7a79f;
	--datei-text: #9fb8e0;
	--datei-table: #95c0a7;
	--datei-slides: #d9af7e;
}

:root {
	/* Radius gehört an Bedienelemente und schwebende Flächen, nie an
	   Inhalt. Listen sind Zeilen mit einer Linie dazwischen, keine
	   Sammlung gerundeter Kästchen. Drei Stufen, nach Grösse des Elements:
	     --radius-lg  Dialoge und Fenster (Darstellung, Login, Anmeldung,
	                  Suchpalette)
	     --radius     alles in Feldhöhe (34 px) und grösser: Knöpfe,
	                  Felder, Auswahl, Menüs, Kästen
	     --radius-sm  kleiner als Feldhöhe: Symbolknöpfe, Optionen in
	                  Menüs, kbd, code, Fokusring
	   Die Themes ändern nur Farben — Form, Mass und Verhalten sind in
	   allen gleich. */
	--radius-lg: 14px;
	--radius: 8px;
	--radius-sm: 5px;

	/* Typografische Skala, in ganzen Pixeln (docs/DESIGN.md §3). Elf
	   Stufen; wer eine zwoelfte einfuehrt, hat eine Aufgabe uebersehen.
	   Die beiden Zwischenstufen 13.5 und 14.5 traegt die Leiste seit je,
	   sie standen bisher nur als harte Pixelwerte im Stylesheet. */
	--t--3:  0.75rem;    /* 12 px    Hilfsbeschriftung, kbd, Zaehler */
	--t--2:  0.78125rem; /* 12.5 px  Zeilenmeta, Meta, Breadcrumb    */
	--t--1b: 0.84375rem; /* 13.5 px  Leiste: Eintrag und Gruppe      */
	--t--1:  0.875rem;   /* 14 px    Tabellenzelle, Filter           */
	--t-0:   0.875rem;   /* 14 px    Zeilentitel                     */
	--t-0b:  0.90625rem; /* 14.5 px  Leiste: Bereich                 */
	--t-1:   0.9375rem;  /* 15 px    Fliesstext, Zwischentitel       */
	--t-2:   1rem;       /* 16 px    Lede, h2                        */
	--t-3:   1.25rem;    /* 20 px    Wortmarke                       */
	/* Die beiden Titelgrade sind die einzigen, die von der Fensterbreite
	   abhaengen — ueber EINEN Abzug, nicht ueber eigene Werte je Breite.
	   Auf schmalen Fenstern (§33) sind das 24 und 32 px.
	   `--titel-ab` ist der Betrag, `--titel-minus` der Schalter: erst die
	   schmale Breite setzt den einen auf den anderen. Ein Look mit von
	   Haus aus kleineren Titeln stellt `--titel-ab` leiser, sonst faellt
	   dort das Verhaeltnis h1:h2 unter 1.4. */
	--titel-ab: 4px;
	--titel-minus: 0px;
	--t-4:  calc(1.75rem - var(--titel-minus)); /* 28 px  h1            */
	--t-5:  calc(2.25rem - var(--titel-minus)); /* 36 px  h1 Startseite */

	--sans: "Instrument Sans", "Helvetica Neue", Arial, sans-serif;
	/* Nur für echten Code. */
	--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

	/* Satzspiegel: die Leiste gibt die linke Kante vor, der Inhalt
	   lehnt sich mit einer einzigen Abstandskonstante daran an.
	   `--leiste-wahl` ist die am Rand gezogene Breite; steht keine da,
	   gilt die Vorgabe der Layout-Variante (Abschnitt 37). */
	--leiste: var(--leiste-wahl, 380px);
	--rand: 56px;   /* Innenabstand der Inhaltsflaeche, oben wie seitlich */
	--luft: 48px;   /* Abstand zwischen Haupt- und Nebenspalte            */
	--haupt: minmax(0, 1fr); /* fliessend: der Inhalt fuellt das Fenster  */
	--neben: 260px;
	--prosa: 72ch;  /* nur Fliesstext, nicht Tabellen und Listen          */
	/* Fensterbreite, ab der der Inhalt nicht mehr mitwaechst: er behaelt
	   dann die Breite, die er hier hatte, und steht zentriert. Eine
	   durchlaufende Zeile waere sonst laenger als ein Blickfeld.      */
	--deckel: 2560px;

	--zeile: 1.5;
	--zeile-eng: 1.35;

	/* Gewaehlte Zeile (DESIGN.md §4 `--selected`). Die Themes setzen
	   nur Akzent und Grund; die Flaeche wird daraus gemischt, damit sie
	   in jedem Theme stimmt. */
	--selected: color-mix(in srgb, var(--accent) 16%, var(--bg));

	--reihe: 36px; /* Navigationszeile          */
	--feld: 34px;  /* Eingabefeld               */
	--dz-zeile: 40px; /* Dokumentzeile           */

	--raum-1: 0.25rem;
	--raum-2: 0.5rem;
	--raum-3: 0.75rem;
	--raum-4: 1rem;
	--raum-5: 1.5rem;
	--raum-6: 2rem;
	--raum-7: 3rem;

	color-scheme: light dark;
}

/* --------------------------------------------------------------------------
   2b. Uebergang zwischen Seiten

   Ohne das hier zeigt der Browser zwischen zwei Dokumenten kurz seinen
   eigenen Grund — das «Aufblitzen». Die Ueberblendung dauert 120 ms und
   laesst die Seitenleiste stehen: sie ist auf beiden Seiten dieselbe.
   -------------------------------------------------------------------------- */

@view-transition {
	navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
	animation-duration: 120ms;
	animation-timing-function: ease;
}

/* Die Leiste wird nicht mituebergeblendet, sonst flackert sie. */
.seitenleiste {
	view-transition-name: leiste;
}

::view-transition-group(leiste),
::view-transition-old(leiste),
::view-transition-new(leiste) {
	animation: none;
	mix-blend-mode: normal;
}

@media (prefers-reduced-motion: reduce) {
	::view-transition-old(root),
	::view-transition-new(root) {
		animation: none;
	}
}

/* --------------------------------------------------------------------------
   3. Grundlagen
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
}

body {
	margin: 0;
	background: var(--bg);
	color: var(--text);
	font-family: var(--sans);
	font-size: var(--t-1);
	line-height: var(--zeile);
	font-feature-settings: "kern" 1;
	/* Zahlen stehen überall untereinander: in Tabellen, in Zählern, in
	   Datumsangaben. Dafür braucht es kein Mono. */
	font-variant-numeric: tabular-nums;
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
}

::selection {
	background: var(--selection);
}

h1,
h2,
h3,
h4 {
	font-weight: 600;
	line-height: 1.2;
	margin: 0;
	text-wrap: balance;
}

h1 { font-size: var(--t-4); letter-spacing: -0.018em; }
h2 { font-size: var(--t-2); letter-spacing: -0.008em; }
h3 { font-size: var(--t-1); }
h4 { font-size: var(--t-0); }

p,
ul,
ol,
dl,
figure,
blockquote,
pre,
table {
	margin: 0;
}

a {
	color: var(--link);
	text-decoration: underline;
	text-underline-offset: 0.16em;
	text-decoration-thickness: 1px;
	text-decoration-color: color-mix(in srgb, var(--link) 38%, transparent);
}

a:hover {
	text-decoration-color: currentColor;
}

img {
	max-width: 100%;
	height: auto;
}

hr {
	border: 0;
	border-top: 1px solid var(--border);
	margin: var(--raum-6) 0;
}

kbd {
	font-family: var(--mono);
	font-size: 0.8em;
	padding: 0.1em 0.36em;
	border: 1px solid var(--border);
	border-bottom-width: 2px;
	border-radius: var(--radius-sm);
	background: var(--surface);
	color: var(--text-muted);
}

/* `.mono` steht einmal, am Schluss dieser Datei: dieselbe Klasse zweimal
   mit zwei Wahrheiten (hier 0.94em, dort `inherit`) war die Sorte
   Widerspruch, die beim naechsten Fix teurer wird als das Streichen. */

.nowrap { white-space: nowrap; }
.text-leise { color: var(--text-muted); }

/* Tastenkuerzel: ohne Kenntnis des Systems steht «Strg» da. */
.nur-mac { display: none; }
.ist-mac .nur-mac { display: inline; }
.ist-mac .nicht-mac { display: none; }

.visuell-versteckt {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

[hidden] { display: none !important; }

:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: var(--radius-sm);
}

.skiplink {
	position: absolute;
	top: var(--raum-2);
	left: var(--raum-2);
	z-index: 100;
	padding: var(--raum-2) var(--raum-4);
	background: var(--accent);
	color: var(--accent-contrast);
	border-radius: var(--radius);
	text-decoration: none;
	transform: translateY(-200%);
}

.skiplink:focus {
	transform: none;
}

.icon {
	flex: none;
	vertical-align: -0.15em;
}

/* --------------------------------------------------------------------------
   4. Geruest
   Die Leiste steht links, der Satzspiegel beginnt genau einen --rand
   daneben. Nichts ist zentriert: der Text haelt die Kante der Leiste.
   -------------------------------------------------------------------------- */

.shell {
	display: grid;
	grid-template-columns: var(--leiste) minmax(0, 1fr);
	min-height: 100vh;
}

/* Vier benannte Felder — Titelband, Hauptspalte, Nebenspalte, Fuss.
   Titelband, Hauptspalte, Nebenspalte, Fuss. */
.spalte {
	display: grid;
	grid-template-columns: var(--haupt) minmax(0, var(--neben));
	/* Die erste Zeile traegt die Markierung des Sichtmodus. Ohne sie ist
	   die Spur 0 hoch — sie kostet nichts, solange niemand «Ansicht als»
	   gesetzt hat. */
	grid-template-areas:
		"sicht sicht"
		"band  neben"
		"haupt neben"
		"fuss  fuss";
	grid-template-rows: auto auto 1fr auto;
	justify-content: start;
	/* Der Fuss gehört ans Ende der Fläche, nicht unter den Inhalt
	   geklebt: bei einem einzigen Treffer stand er sonst mitten im
	   Bild. Die mittlere Spur (1fr) dehnt sich dafür. */
	min-height: 100vh;
	column-gap: var(--luft);
	padding-inline: var(--rand);
	min-width: 0;
	/* Die Flaeche ist das Fenster — bis `--deckel`. Wer einen breiten
	   Schirm hat, soll ihn nutzen; leerer Raum rechts ist kein
	   Satzspiegel, sondern eine verschenkte Haelfte. Jenseits des
	   Deckels waechst der Inhalt nicht weiter: was das Fenster mehr hat,
	   wird von der Breite abgezogen und als Rand links und rechts
	   verteilt. Der Inhalt ist auf einem 49-Zoll-Schirm damit genau so
	   breit wie bei 2560 px, und er steht zentriert.

	   `width: 100%` gehoert dazu: ohne sie macht `margin-inline: auto`
	   aus dem Rasterkind ein schrumpfendes — es fiel auf seine
	   Inhaltsbreite zusammen, und die Seite sprang beim Aufziehen des
	   Fensters von 2180 px auf 836 px. */
	width: 100%;
	max-width: calc(100% - max(0px, 100vw - var(--deckel)));
	margin-inline: auto;
}

/* `wide` hiess frueher «breiter als der Satzspiegel». Der Inhalt ist
   jetzt ohnehin fliessend; die Klasse bleibt als Schalter fuer Seiten,
   die auch die Nebenspalte nicht brauchen. */
.spalte-breit {
	--haupt: minmax(0, 1fr);
}

/* Seiten ohne Nebenspalte brauchen die zweite Spur nicht. */
.spalte-ohne-neben {
	grid-template-columns: var(--haupt);
	grid-template-areas:
		"sicht"
		"band"
		"haupt"
		"fuss";
}

/* Sichtmodus: «Ansicht als …» ------------------------------------------- */

/* Eine Zeile, keine Box: volle Breite der Inhaltsflaeche, 36 px hoch,
   Flaeche in der Farbe der gewaehlten Zeile, kein Radius, kein Rahmen.
   Sie sitzt ueber dem Titelband, damit sie bei jedem Blick zuerst da ist. */
.sichtband {
	grid-area: sicht;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--raum-4);
	height: 36px;
	/* ueber den Innenabstand der Spalte hinaus, bis an beide Kanten */
	margin-inline: calc(var(--rand) * -1);
	padding-inline: var(--rand);
	background: var(--selected, var(--surface-2));
	color: var(--text);
	font-size: var(--t--1);
	line-height: var(--zeile-eng);
}

.sichtband-text {
	margin: 0;
	min-width: 0;
	overflow: hidden;
}

.sichtband-form {
	margin: 0;
	flex: none;
}

.sichtband-knopf {
	background: none;
	border: 0;
	padding: 0;
	font: inherit;
	font-weight: 500;
	color: var(--text);
	text-decoration: underline;
	text-underline-offset: 3px;
	cursor: pointer;
}

.sichtband-knopf:hover {
	color: var(--accent-text);
}

.sicht-tabelle .gedaempft {
	color: var(--text-muted);
}

.sicht-tabelle .spalte-aktion {
	width: 1%;
	white-space: nowrap;
	text-align: right;
}

.sicht-tabelle tbody tr.ist-sicht {
	background: var(--selected, var(--surface-2));
}

.sicht-tabelle form {
	margin: 0;
}

.titelband {
	grid-area: band;
	/* Oben reicht ein Drittel: der Kopf soll ansagen, nicht Raum fuellen.
	   Alles, was er hoeher ist, fehlt der ersten Zeile der Liste. */
	padding-block: calc(var(--rand) * 0.22) 0;
	min-width: 0;
}

.inhalt {
	grid-area: haupt;
	padding-block: 20px var(--raum-6);
	min-width: 0;
	/* Bezugsgroesse fuer die Abfragen weiter unten: nicht das Fenster
	   zaehlt, sondern der Platz, den der Inhalt wirklich hat — die Leiste
	   ist ja verstellbar. */
	container: inhalt / inline-size;
}

.nebenspalte {
	grid-area: neben;
	padding-block: var(--rand) var(--raum-7);
	align-self: start;
	font-size: var(--t--1);
	line-height: var(--zeile-eng);
	min-width: 0;
}

/* Kopfleiste nur auf schmalen Fenstern */
.topbar {
	display: none;
	align-items: center;
	gap: var(--raum-2);
	padding: 0 var(--raum-3);
	height: 52px;
	border-bottom: 1px solid var(--border);
	background: var(--bg-sidebar);
	position: sticky;
	top: 0;
	z-index: 20;
}

/* Dieselbe Wortmarke wie in der Leiste: ein Grad aus der Skala, ein
   Gewicht, eine Farbe. Zweifarbig auf dem Telefon und einfarbig auf dem
   Schirm waren zwei Marken fuer dieselbe Site. */
.topbar-marke {
	flex: 1;
	min-width: 0;
	display: flex;
	align-items: baseline;
	gap: 0.35em;
	font-size: var(--t-3);
	font-weight: 600;
	color: var(--text);
	text-decoration: none;
	letter-spacing: -0.012em;
	overflow: hidden;
	white-space: nowrap;
}

.topbar-marke b,
.topbar-marke span {
	font-weight: 600;
	color: inherit;
}

.topbar-knopf {
	display: inline-grid;
	place-items: center;
	width: 40px;
	height: 40px;
	padding: 0;
	background: none;
	border: 1px solid transparent;
	border-radius: var(--radius);
	color: var(--text-muted);
	cursor: pointer;
}

.topbar-knopf:hover {
	background: var(--surface-2);
	color: var(--text);
}

.backdrop {
	display: none;
	position: fixed;
	inset: 0;
	z-index: 25;
	border: 0;
	padding: 0;
	background: rgba(0, 0, 0, 0.38);
	cursor: pointer;
}

/* --------------------------------------------------------------------------
   5. Seitenleiste — das praegende Element
   -------------------------------------------------------------------------- */

.seitenleiste {
	position: sticky;
	/* Bezugsrahmen fuer die Griffzone am rechten Rand */
	top: 0;
	z-index: 30;
	display: flex;
	flex-direction: column;
	gap: var(--raum-4);
	height: 100vh;
	overflow-y: auto;
	overflow-x: hidden;
	/* Ohne reservierte Rinne springt die ganze Leiste um die Breite des
	   Scrollbalkens, sobald ein Ast auf- oder zugeht. */
	scrollbar-gutter: stable;
	overscroll-behavior: contain;
	/* Unten polstert nicht die Leiste, sondern ihr klebender Fuss: ein
	   `position: sticky` haelt im Inhaltskasten seines Wirts, und ein
	   Polster hier liesse darunter einen Streifen frei, in dem die
	   scrollende Navigation weiterzeichnet (Befund B73). Das Mass steht
	   als Token, der Fuss traegt es als eigenes Polster. */
	--leiste-polster: var(--raum-4);
	padding: var(--raum-5) var(--raum-4) 0;
	background: var(--bg-sidebar);
	border-right: 1px solid var(--border);
	font-size: var(--t--1);
	line-height: var(--zeile-eng);
}

.leiste-kopf,
.suche-knopf,
.leiste-fuss {
	flex: none;
}

/* Wortmarke: zwei Zeilen an einer schmalen Akzentkante.
   Die Kante ist das einzige Ornament der Seite. */
.leiste-kopf {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--raum-2);
	padding-left: var(--raum-2);
	margin-bottom: var(--raum-2);
}

.marke {
	display: block;
	position: relative;
	padding-left: var(--raum-3);
	text-decoration: none;
	color: var(--text);
	line-height: 1.15;
}

.marke::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.18em;
	bottom: 0.5em;
	width: 3px;
	border-radius: 2px;
	background: var(--accent);
}

/* Die Wortmarke hat EINE Gestalt: ein Grad aus der Skala (--t-3, 20 px),
   ein Gewicht, eine Farbe — in der Leiste wie in der Kopfleiste schmaler
   Fenster. Hier stand frueher ein zweiter, wirkungsloser Grad (17 px),
   den der Look weiter unten ueberschrieb; zwei Wahrheiten im Stylesheet
   sind eine zu viel. */
.marke-haupt,
.marke-neben {
	display: block;
	font-size: var(--t-3);
	font-weight: 600;
	letter-spacing: -0.012em;
	white-space: nowrap;
}

.marke-neben {
	color: var(--text);
}

/* «ETH / UZH» — der Schraegstrich ist derselbe Trenner wie im Pfad. */
.marke-traeger {
	display: block;
	margin-top: 0.3em;
	font-size: var(--t--2);
	color: var(--text-muted);
	white-space: nowrap;
}

.marke-traeger i {
	font-style: normal;
	color: var(--text-faint);
	padding: 0 0.25em;
}

.leiste-schliessen {
	display: none;
	background: none;
	border: 0;
	padding: var(--raum-2);
	color: var(--text-muted);
	cursor: pointer;
	border-radius: var(--radius-sm);
}

/* Suchfeld ---------------------------------------------------------------- */

.suche-knopf {
	display: flex;
	align-items: center;
	gap: var(--raum-2);
	width: 100%;
	height: 40px;
	padding: 0 var(--raum-1) 0 var(--raum-3);
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	color: var(--text-faint);
	font: inherit;
	font-size: var(--t--1);
	text-align: left;
	cursor: pointer;
	transition: border-color 0.12s ease, color 0.12s ease;
}

.suche-knopf:hover {
	border-color: var(--text-faint);
	color: var(--text-muted);
}

.suche-knopf .icon { color: var(--text-faint); }

.suche-knopf-text {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

.suche-kbd {
	flex: none;
	font-family: var(--mono);
	font-size: var(--t--3);
	line-height: 1;
	font-weight: 500;
	padding: 5px 6px;
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	background: var(--surface-2);
	color: var(--text-muted);
}

/* Navigation ------------------------------------------------------------- */

/* Die Navigation darf im Flex-Container nicht schrumpfen, sonst
   ueberlagern sich die Bloecke, sobald die Leiste zu kurz wird.
   Stattdessen scrollt die ganze Leiste. */
.nav {
	flex: none;
}

.nav + .nav {
	margin-top: var(--raum-4);
	padding-top: var(--raum-4);
	border-top: 1px solid var(--border);
}

.nav-titel {
	font-size: var(--t--2);
	font-weight: 600;
	color: var(--text-faint);
	margin: 0 0 var(--raum-1);
	padding-left: var(--raum-2);
}

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

/* Jede Ebene rückt 14 px ein; die Linie zeigt, wie tief man steht. */
.nav-ebene-2,
.nav-ebene-3,
.nav-ebene-4,
.nav-ebene-5 {
	margin-left: 14px;
	padding-left: 10px;
	border-left: 1px solid var(--border);
}

.nav-zeile {
	position: relative;
	display: flex;
	align-items: stretch;
	gap: var(--raum-1);
	min-height: 32px;
}

/* Hover legt nur Farbe auf — keine Kante, kein Sprung. */
.nav-zeile:hover {
	background: var(--hover, var(--surface-2));
}

/* Der aktive Ort trägt den Akzent in der Schrift und eine 2-px-Kante
   links. Ein gefüllter Balken war lauter als alles andere auf der
   Seite und hat mit der Wichtigkeit nichts zu tun. */
.nav-zeile.ist-aktiv {
	box-shadow: inset 2px 0 0 0 var(--accent);
}

/* Den Zustand tragen Farbe und Kante — NICHT das Gewicht. Ein eigenes
   Gewicht fuer den aktiven Eintrag verbreiterte seinen Text, und bei
   jedem Seitenwechsel sprangen die Zeilen um ein paar Pixel. */
.nav-zeile.ist-aktiv > .nav-link {
	color: var(--accent-text);
}

.nav-zeile.ist-aktiv:hover {
	background: var(--hover, var(--surface-2));
}

.nav-link {
	flex: 1;
	min-width: 0;
	display: flex;
	align-items: center;
	padding: 0.3rem var(--raum-2);
	font-size: var(--t--1);
	color: var(--text);
	/* Das Gewicht ist in jedem Zustand dasselbe. Fett würde den Text
	   verbreitern und beim Wechsel der Seite alles verschieben; den
	   Zustand tragen Farbe, Kante und Fläche. */
	font-weight: 500;
	text-decoration: none;
	border-radius: var(--radius-sm);
	overflow-wrap: break-word;
}

.nav-ebene-3 .nav-link {
	font-weight: 400;
}

/* Ein Fachgebiet ist kein Ort, sondern eine Klappe: derselbe Zeilentyp,
   aber ein Knopf statt eines Links. */
.nav-gebiet {
	background: none;
	border: 0;
	font: inherit;
	font-weight: 500;
	text-align: left;
	cursor: pointer;
	color: var(--text-muted);
}

.nav-gebiet:hover {
	color: var(--text);
}

.nav-toggle {
	flex: none;
	display: grid;
	place-items: center;
	width: 1.625rem;
	height: 1.625rem;
	margin-right: var(--raum-1);
	padding: 0;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text-faint);
	cursor: pointer;
}

.nav-toggle:hover {
	color: var(--text);
}

.nav-pfeil {
	transition: transform 0.16s ease;
}

.nav-toggle[aria-expanded="true"] .nav-pfeil {
	transform: rotate(90deg);
}

/* Öffnen und Schliessen laufen mit derselben Dauer und derselben Kurve:
   sonst «pumpt» die Liste, wenn ein Ast zu- und der nächste aufgeht. */
.nav-sub {
	display: grid;
	grid-template-rows: 1fr;
	transition: grid-template-rows 180ms cubic-bezier(.2, 0, 0, 1);
}

.nav-sub[data-open="false"] {
	grid-template-rows: 0fr;
}

.nav-sub-innen {
	overflow: hidden;
	min-height: 0;
}

.nav-sub[data-open="false"] > .nav-sub-innen {
	visibility: hidden;
}

/* Zahlen in der Leiste: eine Zahl, keine Pille. Rechtsbuendig, tabellarisch,
   gedaempft; die Badge fuer offene Anfragen ist die einzige Flaeche. */
.nav-zahl {
	flex: none;
	align-self: center;
	margin-right: var(--raum-2);
	font-size: var(--t--3);
	line-height: 1;
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
}

/* Ein Zähler ist eine Zahl, keine Pille: dieselbe Form wie .nav-zahl
   darüber, nur in der Farbe, die auf das Wartende hinweist. */
.badge {
	flex: none;
	align-self: center;
	margin-right: var(--raum-2);
	font-size: var(--t--3);
	line-height: 1;
	font-weight: 500;
	font-variant-numeric: tabular-nums;
	color: var(--danger);
}

/* Fuss der Leiste -------------------------------------------------------- */

/* Konto, Ansicht und Darstellung bleiben erreichbar, auch wenn die
   Navigation laenger ist als das Fenster: der Fuss klebt an der
   Unterkante der Leiste und traegt dort ihre eigene Flaeche, damit die
   Eintraege nicht durch ihn hindurchscheinen. Das ist der Preis dafuer,
   dass die Leiste als Ganzes scrollt (§5.6) — und er ist kleiner als ein
   zweiter Scrollbalken.

   Das untere Polster der Leiste traegt darum er (siehe `.seitenleiste`):
   so reicht seine Flaeche bis an die Unterkante, und im Streifen darunter
   scheint keine Navigationszeile mehr durch — im Look «karte» endet er
   innerhalb der abgerundeten Kante der Leistenkarte. */
.leiste-fuss {
	margin-top: auto;
	position: sticky;
	bottom: 0;
	z-index: 1;
	padding-top: var(--raum-1);
	padding-bottom: var(--leiste-polster, 0px);
	border-top: 1px solid var(--border);
	background: inherit;
	display: flex;
	flex-direction: column;
	gap: 1px;
}

.leiste-aktion-form { margin: 0; }

.leiste-aktion,
.theme-knopf {
	display: flex;
	align-items: center;
	gap: var(--raum-3);
	width: 100%;
	min-height: var(--reihe);
	padding: var(--raum-1) var(--raum-2);
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text-muted);
	font: inherit;
	font-size: var(--t--1);
	text-align: left;
	text-decoration: none;
	cursor: pointer;
}

.leiste-aktion:hover,
.theme-knopf:hover {
	background: var(--surface-2);
	color: var(--text);
}

.leiste-aktion .icon,
.theme-knopf .icon {
	color: var(--text-faint);
}

.leiste-aktion-text {
	flex: 1;
	min-width: 0;
	display: block;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

/* Konto in einer Zeile; lange Namen kürzen, Abmelden bleibt erreichbar. */
.leiste-konto {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--raum-2);
}
.leiste-konto > .leiste-aktion { flex: 1; min-width: 0; }
.leiste-konto > .leiste-aktion-form { flex: none; }
.leiste-konto .leiste-aktion {
	width: auto;
	min-height: 32px;
	gap: var(--raum-2);
}

/* In der Schlusszeile ist «Darstellung» ein Textknopf, keine Reihe. */
.leiste-schluss .theme {
	flex: none;
}

.leiste-schluss .theme-knopf {
	width: auto;
	min-height: 0;
	gap: var(--raum-2);
	font-size: var(--t--2);
}

/* Theme-Umschalter ------------------------------------------------------- */

.theme {
	position: relative;
}

/* Der Dialog steht in der Mitte. <dialog> bringt Backdrop, Fokusfalle
   und Esc mit; hier geht es nur um Mass und Farbe. */
.darstellung {
	width: min(560px, calc(100vw - 2 * var(--raum-5)));
	max-height: min(84vh, 780px);
	padding: 0;
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	background: var(--bg);
	color: var(--text);
	box-shadow: var(--shadow);
	overflow: hidden;
}

/* Der einzige Dialog ohne Unschaerfe und ohne Abdunkelung: wer hier ein
   Theme ueberfaehrt, soll die Seite dahinter wirklich umschlagen sehen.
   Alle anderen Dialoge behalten den Sammelposten weiter unten. */
.darstellung::backdrop {
	background: transparent;
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
}

/* Weil der Grund unveraendert bleibt, muss der Dialog sich allein ueber
   seinen Schatten abheben: eine Stufe kraeftiger als `--shadow`, mit
   einer feinen Linie als aeusserster Kante. `[open]` steht davor, damit
   die Regel den Sammelposten der Dialoge schlaegt — er setzt fuer alle
   `box-shadow: var(--shadow)`. */
.darstellung[open] {
	box-shadow:
		0 0 0 1px var(--border),
		0 2px 8px rgba(0, 0, 0, 0.18),
		0 24px 64px -12px rgba(0, 0, 0, 0.45);
}

/* Der Kopf ist der Griff: an ihm laesst sich der Dialog verschieben,
   damit er nicht vor der Stelle steht, die man pruefen will. Der
   Schliessknopf bleibt ein Knopf. */
.darstellung-kopf {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--raum-4);
	padding: var(--raum-4) var(--raum-5);
	border-bottom: 1px solid var(--border);
	cursor: move;
	user-select: none;
	-webkit-user-select: none;
	touch-action: none;
}

.darstellung-kopf .panel-schliessen {
	cursor: pointer;
}

/* Auf schmalen Fenstern wird nicht gezogen: dort fuellt der Dialog
   ohnehin die Flaeche. */
@media (max-width: 899px) {
	.darstellung-kopf {
		cursor: default;
		touch-action: auto;
	}
}

/* Alle Dialoge tragen denselben Titel: 16/600 (docs/DESIGN.md §6). */
.darstellung-titel {
	font-size: var(--t-2);
	font-weight: 600;
	margin: 0;
}

.darstellung-korpus {
	display: block;
	max-height: calc(84vh - 4rem);
	overflow-y: auto;
}

.darstellung-spalte {
	padding: var(--raum-4) var(--raum-5) var(--raum-5);
	min-width: 0;
}

.darstellung-spalte + .darstellung-spalte {
	border-left: 1px solid var(--border);
}

.darstellung-spalte > .theme-gruppe-titel {
	font-size: var(--t--1);
	color: var(--text);
	margin-bottom: var(--raum-3);
}

/* Themes als zweispaltiges Raster. Die Namen dürfen nicht abgeschnitten
   werden — sie sind der einzige Hinweis, was der Farbpunkt bedeutet. */
.darstellung .theme-option {
	gap: var(--raum-3);
	padding-inline: var(--raum-2);
	font-size: var(--t--1);
}

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

.theme-gruppe + .theme-gruppe {
	margin-top: var(--raum-3);
}

.theme-gruppe-titel {
	font-size: var(--t--2);
	font-weight: 600;
	color: var(--text-faint);
	padding: 0 var(--raum-2);
	margin: 0 0 var(--raum-1);
}

.theme-option {
	display: flex;
	align-items: center;
	gap: var(--raum-3);
	width: 100%;
	min-height: 30px;
	padding: 0.25rem var(--raum-2);
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text);
	font: inherit;
	font-size: var(--t--1);
	text-align: left;
	cursor: pointer;
}

.theme-option:hover {
	background: var(--surface);
}

.theme-option[aria-pressed="true"] {
	background: color-mix(in srgb, var(--accent) 13%, transparent);
	color: var(--accent-text);
	font-weight: 500;
}

/* Vier Punkte: bg, text, accent, accent-2 */
.theme-vorschau {
	flex: none;
	display: inline-flex;
	gap: 3px;
}

.theme-vorschau span {
	width: 9px;
	height: 9px;
	border-radius: 999px;
	box-shadow: inset 0 0 0 1px rgba(128, 128, 128, 0.35);
}

.theme-name {
	flex: 1;
	min-width: 0;
}

.theme-haken {
	flex: none;
	color: var(--accent-text);
	opacity: 0;
}

.theme-option[aria-pressed="true"] .theme-haken {
	opacity: 1;
}

/* --------------------------------------------------------------------------
   6. Inhalt
   -------------------------------------------------------------------------- */

.brotkrumen {
	font-size: var(--t--2);
	line-height: 1.4;
	color: var(--text-muted);
	margin-bottom: var(--raum-2);
}

.brotkrumen ol {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: 0 var(--raum-2);
	margin: 0;
	padding: 0;
}

.brotkrumen li + li::before {
	content: "/";
	color: var(--text-faint);
	margin-right: var(--raum-2);
}

.brotkrumen a {
	color: var(--text-muted);
	text-decoration: none;
}

.brotkrumen a:hover {
	color: var(--link);
	text-decoration: underline;
}

/* Der Kopf darf die Breite nutzen: ein Titel, der bei 22 Zeichen
   umbricht, sieht auf einem breiten Schirm aus wie ein Fehler. Lesbar
   schmal bleibt nur, was wirklich Fliesstext ist. */
.titelband-innen {
	max-width: none;
}

.titelband h1 {
	max-width: none;
	font-size: var(--t-4);
	font-weight: 600;
	line-height: 1.15;
	letter-spacing: -0.015em;
	text-wrap: balance;
	margin: 0;
}

/* Startseite: der Auftakt darf lauter sein als eine Unterseite — aber
   um eine feste Stufe der Skala (36 px), nicht um einen Betrag, den
   erst die Fensterbreite ausrechnet. Ein `clamp` lieferte 44 px auf
   breiten Schirmen: ein Grad, den sonst nichts auf der Site kennt. */
.titelband-auftakt h1 {
	font-size: var(--t-5);
	letter-spacing: -0.015em;
}

.titelband-auftakt .lead {
	font-size: var(--t-2);
	line-height: 1.42;
	color: var(--text);
	max-width: 52ch;
	margin-top: var(--raum-3);
}

/* Der ursprüngliche Wiki-Text auf Archivseiten. Seine Dateilinks sind
   dort leiser gesetzt, damit sie nicht mit der Materialtabelle
   darüber konkurrieren. */
.altext a {
	color: var(--text);
	text-decoration: none;
	border-bottom: 1px solid var(--border);
}

.altext a:hover {
	color: var(--link);
	border-bottom-color: currentColor;
}

/* Eine Fussnote unter dem Titel, nicht ein Bauteil: normale Schrift,
   13 px, gedämpft. Nie ein Kasten, nie Mono. */
.meta {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0 var(--raum-4);
	font-size: var(--t--2);
	font-weight: 400;
	line-height: 1.45;
	color: var(--text-muted);
	margin-top: var(--raum-2);
}

.meta time {
	font-variant-numeric: normal;
}

/* Die eine Bearbeiten-Handlung der Site (Befund B42). Sie stand mal
   links in der Meta-Zeile, mal rechts im Titelkopf, auf zwei Seiten gar
   nicht. Jetzt gibt es ein Markup (snippets/meta-panel.php) und einen
   Ort: rechts oben auf der Titelzeile, an der rechten Inhaltskante.

   Das Wort «Bearbeiten» ist weg (Entscheid vom 14.09.2026); es steht
   noch im `aria-label` und im `title`, sichtbar ist ein Stift. Ein Wort
   an dieser Stelle war der einzige Text rechts oben und sah aus wie ein
   vergessener Link — das Zeichen ist hier kein Dekor, sondern der Knopf.

   Die Vorlagen rufen das Snippet an drei verschiedenen Stellen des
   Kopfes auf (Meta-Zeile, Angabenzeile, Angabe rechts). Den Ort macht
   darum das CSS und nicht die Vorlage: die Handlung wird aus dem Fluss
   genommen und ins Titelband gehängt. So steht sie auf jeder Seite in
   derselben Zeile, ohne dass eine Vorlage davon wissen muss. */
.titelband-innen:has(.themenkopf-aktionen) {
	position: relative;
}

.themenkopf-aktionen {
	position: absolute;
	inset-block-start: 0;
	inset-inline-end: 0;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	/* Eine Titelzeile hoch: so liegt die Mitte des Zeichens auf der
	   Mitte des H1. */
	block-size: calc(var(--t-4) * 1.2);
}

/* Steht ein Knopf auf der Titelzeile (Praktikum: «Anmelden»), ist die
   Zeile so hoch wie der Knopf, und der Titel steht mittig darin
   (praktika.css). Dann misst das Zeichen dieselbe Höhe — sonst lägen
   die beiden Mitten je nach Look bis zu drei Pixel auseinander. */
.titelband-innen:has(.themenkopf .knopf) .themenkopf-aktionen {
	block-size: max(var(--feld), calc(var(--t-4) * 1.2));
}

/* Was sonst auf der Titelzeile steht — Gefäss «Grundlagenfach», «n
   Teilnehmende», der Knopf «Anmelden» —, endet eine Trefferfläche plus
   --raum-3 vor der Kante. Die Handlung liegt ausserhalb des Flusses und
   würde es sonst überdecken. */
.titelband-innen:has(.themenkopf-aktionen) > .themenkopf,
.titelband-innen:has(.themenkopf-aktionen) > h1 {
	padding-inline-end: calc(2rem + var(--raum-3));
}

/* Träger, in denen nichts als die Handlung steht, geben ihren Kasten
   auf: er stünde als leere Zeile im Kopf und kostete eine Zeilenhöhe.
   `display: contents` und nicht `none` — die Handlung selbst soll ja
   bleiben, sie hängt nur nicht mehr in diesem Kasten. */
.meta:has(> .themenkopf-aktionen:only-child),
.angabe-rechts:has(> .themenkopf-aktionen:only-child),
.themenkopf-angaben:has(> .themenkopf-aktionen:only-child),
.themenkopf-angaben:has(> .angabe-rechts:only-child > .themenkopf-aktionen:only-child) {
	display: contents;
}

/* Trefferfläche 32 × 32 px um ein 19-px-Zeichen. Die Titelzeile wird
   davon nicht höher — die Handlung steht ja nicht in ihr. 70 % Deckung
   halten das Zeichen leiser als den Titel und bleiben über 3:1 gegen
   den Grund; wer darauf zeigt, bekommt die volle Farbe. */
.meta-panel {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 2rem;
	block-size: 2rem;
	color: color-mix(in srgb, var(--accent-text) 70%, transparent);
	text-decoration: none;
}

.meta-panel .icon {
	inline-size: 19px;
	block-size: 19px;
	vertical-align: baseline;
}

.meta-panel:hover,
.meta-panel:focus-visible {
	color: var(--accent-text);
}

/* Die Lede ist der erste Satz, nicht eine Fussnote: volle Tinte. */
.lead {
	font-size: var(--t-2);
	line-height: 1.45;
	color: var(--text);
	max-width: 60ch;
	margin-top: var(--raum-1);
}

/* Abstand ist die einzige Gliederung, die nichts kostet — aber er kostet
   Bildschirm. EIN Abstand zwischen Abschnitten (--raum-6, 32 px), 16 px
   zwischen Blöcken; mehr heisst nur, dass man scrollen muss, um zwei
   Dinge zu vergleichen. Einzelwerte von 28 oder 36 px darf hier nichts
   mehr setzen: der Abschnittsabstand ist eine Regel, keine Sammlung. */
main > * + * {
	margin-top: var(--raum-6);
}

section > * + * {
	margin-top: 16px;
}

/* Abschnittsüberschrift ohne Linie: den Abschnitt trennt der Abstand,
   nicht ein Strich. Ein Strich unter jedem Titel ist Dekor.
   Grad und Abstand sind fuer JEDE Abschnittsueberschrift dieselben:
   16/600, oben --raum-6, unten --raum-2 (docs/DESIGN.md §3). Eine
   Ueberschrift, die stattdessen ein kleiner Block oder eine Spalte
   beschriftet, ist keine Abschnittsueberschrift und bleibt klein. */
.inhalt section > h2 {
	margin-top: var(--raum-6);
	margin-bottom: var(--raum-2);
	font-size: var(--t-2);
	font-weight: 600;
	letter-spacing: -0.008em;
}

/* Prosa und Blocks -------------------------------------------------------- */

.prosa {
	max-width: var(--prosa);
	font-size: var(--t-1);
	line-height: var(--zeile);
}

/* Zwischentitel im Fliesstext: 15/600, eng am Text. Keine Linien, keine
   eigenen Abstände nach Gutdünken. */
.prosa h2,
.prosa h3 {
	margin: 20px 0 4px;
	font-size: var(--t-1);
	font-weight: 600;
	line-height: 1.3;
	letter-spacing: 0;
}

.prosa > * + * {
	margin-top: var(--raum-4);
}

.prosa h2 {
	margin-top: var(--raum-7);
}

.prosa h3 {
	margin-top: var(--raum-6);
}

.prosa ul,
.prosa ol {
	padding-left: 1.35em;
}

.prosa li + li {
	margin-top: var(--raum-1);
}

/* Im Archiv stehen rohe URLs aus dem alten Wiki im Text. Auf einem
   Telefon sprengen sie sonst die Spalte. */
.prosa a {
	overflow-wrap: anywhere;
}

.prosa .zitat,
blockquote.zitat {
	border-left: 2px solid var(--border);
	padding-left: var(--raum-4);
	color: var(--text-muted);
}

blockquote.zitat footer {
	font-size: var(--t--1);
	margin-top: var(--raum-2);
}

.code,
pre.code {
	font-family: var(--mono);
	font-size: var(--t--1);
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	padding: var(--raum-3) var(--raum-4);
	overflow-x: auto;
	line-height: 1.5;
}

:not(pre) > code {
	font-family: var(--mono);
	font-size: 0.9em;
	background: var(--surface);
	border-radius: var(--radius-sm);
	padding: 0.1em 0.3em;
}

.bild {
	margin: 0;
}

.bild img {
	display: block;
}

.bild figcaption {
	font-size: var(--t--1);
	color: var(--text-muted);
	margin-top: var(--raum-2);
}

.trenner {
	max-width: var(--prosa);
}

/* Tabellen ---------------------------------------------------------------- */

.tabelle-rahmen {
	overflow-x: auto;
}

/* So breit wie nötig, nie breiter als der Platz. `max-content` misst,
   was die Spalten wirklich brauchen; erst wenn das mehr ist als die
   Fläche, greift der Deckel und die Textspalten brechen um. Eine
   Tabelle mit vier kurzen Spalten läuft damit nicht mehr über 2000 px
   auseinander, und eine mit einer Textspalte nutzt die Fläche wie
   vorher. `table-layout` bleibt `auto` — die Spaltenbreite entscheidet
   der Inhalt, nicht eine Prozentzahl im Markup. */
.tabelle {
	width: max-content;
	max-width: 100%;
	border-collapse: collapse;
	font-size: var(--t--1);
	line-height: 1.45;
}

.tabelle th,
.tabelle td {
	text-align: left;
	vertical-align: top;
	padding: var(--raum-3) var(--raum-4) var(--raum-3) 0;
	border-bottom: 1px solid var(--border);
}

.tabelle th:last-child,
.tabelle td:last-child {
	padding-right: 0;
}

.tabelle thead th {
	padding-top: 0;
	padding-bottom: var(--raum-2);
	border-bottom: 1px solid var(--text-faint);
	font-weight: 600;
	font-size: var(--t--2);
	color: var(--text-muted);
	white-space: nowrap;
}

.tabelle td.spalte-datum,
.tabelle th.spalte-datum {
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
	width: 1%;
}

.tabelle tbody tr:last-child td {
	border-bottom: 0;
}

.tabelle tbody tr:hover {
	background: var(--surface);
}

.termin-titel {
	display: block;
	font-weight: 500;
	color: var(--text);
}

.termin-beschrieb,
.termin-themen {
	display: block;
	color: var(--text-muted);
}

/* Der Abstand trennt zwei Zeilen — vor der ersten trennt er nichts und
   schöbe nur die oberste Textzeile vom Datum daneben weg. */
.termin-beschrieb:not(:first-child),
.termin-themen:not(:first-child) {
	margin-top: var(--raum-1);
}

.termin-dateien {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--raum-1);
}

.termin-dateien li {
	display: flex;
	align-items: baseline;
	gap: var(--raum-2);
}

/* Seitenlisten ------------------------------------------------------------ */

/* Listen von Einträgen sind kein Fliesstext: sie nutzen die Fläche. */
.seitenliste {
	list-style: none;
	margin: 0;
	padding: 0;
}

.inhalt-breit .seitenliste {
	max-width: none;
}

/* Trennlinie, Hoverfläche und Text beginnen auf derselben Kante wie der
   Titel der Seite. Ein Zeilenpolster nach aussen (negativer Rand) schiebt
   die Linien 12 px aus der Textspalte heraus — dann steht die Liste
   sichtbar neben ihrem eigenen Titel. Dasselbe gilt für .mb-zeile,
   .mb-kopf, .mb-detail, .browser-gruppe, .dz und .dz-kopf. */
.seitenliste > li {
	position: relative;
	padding: var(--raum-4) 0;
	border-bottom: 1px solid var(--border);
}

/* Die erste Zeile bekommt KEINE Oberlinie. Steht die Liste — wie auf
   /personen — unmittelbar unter dem Seitentitel, laese sich diese Linie
   als Unterstreichung des Titels (docs/DESIGN.md §6: verboten). Die
   Liste schliesst unten mit einer Linie ab, das genuegt. */

.seitenliste > li:hover {
	background: var(--hover, var(--surface-2));
}

.seitenliste > li > a {
	font-size: var(--t-0);
	font-weight: 600;
	color: var(--text);
	text-decoration: none;
}

.seitenliste > li > a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.seitenliste > li:hover > a {
	color: var(--link);
}

.seitenliste p {
	color: var(--text-muted);
	font-size: var(--t--1);
	line-height: 1.45;
	margin-top: var(--raum-1);
	max-width: 70ch;
}

.seitenliste-typ {
	color: var(--text-faint);
	font-size: var(--t--2);
	margin-left: var(--raum-3);
	font-variant-numeric: tabular-nums;
}

.seitenliste-chips {
	position: relative;
	z-index: 1;
	margin-top: var(--raum-2);
}

.einfache-liste {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--raum-2);
	max-width: var(--prosa);
}

/* Startseite: Bereiche als zweispaltige Liste, ohne Karten ---------------- */

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

.bereiche > li {
	position: relative;
	padding: var(--raum-4) 0;
	border-top: 1px solid var(--border);
}

.bereiche > li > a {
	display: inline-block;
	font-size: var(--t-1);
	font-weight: 600;
	color: var(--text);
	text-decoration: none;
	letter-spacing: -0.008em;
}

.bereiche > li > a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.bereiche > li:hover > a {
	color: var(--link);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

.bereiche p {
	color: var(--text-muted);
	font-size: var(--t--1);
	line-height: 1.45;
	margin-top: var(--raum-1);
	max-width: 44ch;
}

/* Meldungen auf der Startseite ------------------------------------------- */

.meldungen {
	list-style: none;
	margin: 0;
	padding: 0;
	max-width: var(--prosa);
}

.meldungen li {
	display: grid;
	grid-template-columns: 6.5rem minmax(0, 1fr);
	gap: var(--raum-4);
	padding: var(--raum-3) 0;
	border-bottom: 1px solid var(--border);
}

.meldung-inhalt {
	min-width: 0;
	display: grid;
	gap: var(--raum-1);
}

.meldung-kopf {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--raum-2) var(--raum-3);
}

/* Die Art der Meldung steht als Zeichen da, nicht als Wort: «Material»
   in Mono neben jedem Titel war Beschriftung ohne Ertrag. */
.meldung-marke {
	flex: none;
	display: inline-grid;
	place-items: center;
	width: 22px;
	height: 22px;
	align-self: center;
	color: var(--text-muted);
	background: var(--surface-2);
}

.meldung-icon {
	width: 14px;
	height: 14px;
}

.meldung-titel {
	font-weight: 600;
	color: var(--text);
	text-decoration: none;
	min-width: 0;
	overflow-wrap: anywhere;
}

a.meldung-titel:hover {
	color: var(--link);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

.meldung-text {
	color: var(--text-muted);
	font-size: var(--t--1);
	line-height: 1.45;
	max-width: 70ch;
}

.meldung-text > :last-child {
	margin-bottom: 0;
}

.meldung-meta {
	font-size: var(--t--2);
	color: var(--text-muted);
}

.meldungen-mehr {
	margin-top: var(--raum-4);
	font-size: var(--t--1);
}

/* Kompakt: ohne Marken, engere Zeilen — für Randspalten. */
.aktuelles-kompakt .meldungen li {
	grid-template-columns: 5.5rem minmax(0, 1fr);
	padding-block: var(--raum-2);
	gap: var(--raum-3);
}

.aktuelles-kompakt .meldung-text {
	font-size: var(--t--2);
}

.meldungen li:first-child {
	border-top: 1px solid var(--border);
}

.meldungen time {
	font-variant-numeric: tabular-nums;
	color: var(--text-muted);
	font-size: var(--t--2);
	padding-top: 0.24em;
	white-space: nowrap;
}

.meldung-link {
	display: inline-block;
	font-size: var(--t--1);
	margin-left: var(--raum-2);
}

/* Chips ------------------------------------------------------------------- */

.chips {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--raum-2);
	margin: 0;
	padding: 0;
}

.chip {
	display: inline-flex;
	align-items: center;
	min-height: 30px;
	padding: 0 0.7rem;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	color: var(--text-muted);
	font-size: var(--t--1);
	text-decoration: none;
	line-height: 1.3;
}

a.chip:hover,
.chip-knopf:hover {
	border-color: var(--text-faint);
	color: var(--text);
}

.chip-knopf {
	font-family: inherit;
	cursor: pointer;
}

/* Ein aktiver Filter ist ein Zustand, kein Ausrufezeichen: dünne Kante,
   Akzent nur in der Schrift. Eine gefüllte Pille schrie lauter als der
   Treffer, den sie erzeugt hat. */
.chip-knopf.ist-aktiv {
	background: none;
	border-color: var(--border);
	color: var(--accent-text);
	font-weight: 500;
}

.chip-knopf.ist-aktiv:hover {
	border-color: var(--accent);
	color: var(--accent-text);
}

/* leise Variante fuer Fachthemen in Ergebnislisten */
.chips-leise .chip {
	min-height: 22px;
	padding: 0 0.5rem;
	background: none;
	border-color: var(--border);
	color: var(--text-faint);
	font-size: var(--t--2);
}

/* Nebenspalte ------------------------------------------------------------- */

.aside-block + .aside-block {
	margin-top: var(--raum-5);
	padding-top: var(--raum-5);
	border-top: 1px solid var(--border);
}

.aside-block h2 {
	font-size: var(--t--2);
	font-weight: 600;
	color: var(--text-faint);
	letter-spacing: 0;
	margin-bottom: var(--raum-2);
}

.aside-liste {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--raum-2);
}

/* Die Nebenspalte spricht leiser als der Text. */
.nebenspalte .chip {
	min-height: 24px;
	padding: 0 0.5rem;
	background: none;
	font-size: var(--t--2);
	color: var(--text-muted);
}

.portraet {
	display: block;
	width: 100%;
}

.aside-block,
.aside-block * {
	min-width: 0;
}

/* Lange Quellen-URLs duerfen die schmale Spalte nicht aufsprengen. */
.nebenspalte a,
.datenliste dd {
	overflow-wrap: anywhere;
}

.datenliste,
.beschreibung {
	display: grid;
	margin: 0;
}

.datenliste dt {
	font-size: var(--t--2);
	color: var(--text-faint);
}

.datenliste dd {
	margin: 0 0 var(--raum-3);
}

.datenliste dd:last-child {
	margin-bottom: 0;
}

.beschreibung {
	max-width: var(--prosa);
	border-top: 1px solid var(--border);
}

.beschreibung dt {
	font-weight: 600;
	padding-top: var(--raum-3);
}

.beschreibung dd {
	margin: var(--raum-1) 0 var(--raum-3);
	color: var(--text-muted);
	border-bottom: 1px solid var(--border);
	padding-bottom: var(--raum-3);
}

/* Formulare und Knoepfe --------------------------------------------------- */

/* Ein Formular ist eine Eingabemaske, kein Fliesstext: 560 px breit,
   Felder in zwei Spalten, 34 px hoch. Untereinander gestapelt in voller
   Textbreite braucht dieselbe Anmeldung dreimal so viel Bildschirm. */
.formular {
	display: grid;
	gap: 12px;
	max-width: 560px;
}

.formular-raster {
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

.formular-raster .feld-breit,
.formular-raster .feld-aktionen,
.formular-raster .datenschutz,
.formular-raster .meldung {
	grid-column: 1 / -1;
}

.formular-schmal {
	max-width: 26rem;
}

.feld {
	display: grid;
	gap: 4px;
	min-width: 0;
}

.feld label {
	font-size: var(--t--2);
	font-weight: 500;
	color: var(--text);
}

.feld-hilfe {
	font-size: var(--t--3);
	line-height: 1.4;
	color: var(--text-muted);
}

/* Der Datenschutzsatz steht als eine Zeile direkt über dem Knopf. */
.datenschutz {
	margin: 0;
}

.feld-fehler {
	font-size: var(--t--2);
	color: var(--danger);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="url"],
input[type="number"],
input[type="date"],
select {
	height: 34px;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="url"],
input[type="number"],
input[type="date"],
textarea,
select {
	width: 100%;
	padding: 0 var(--raum-3);
	background: var(--bg);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	font: inherit;
	font-size: var(--t--1);
}

textarea {
	padding: var(--raum-2) var(--raum-3);
	line-height: 1.45;
	min-height: 0;
	max-height: 96px;
	resize: vertical;
}

input::placeholder,
textarea::placeholder {
	color: var(--text-faint);
}

input:hover,
textarea:hover,
select:hover {
	border-color: var(--text-faint);
}

input:focus,
textarea:focus,
select:focus {
	outline: 2px solid var(--accent);
	outline-offset: -1px;
	border-color: var(--accent);
}

input[aria-invalid="true"],
.feld-ungueltig input {
	border-color: var(--danger);
}

/* Schreibgeschützte Felder bleiben lesbar, zeigen aber, dass sie
   feststehen: Grund wie die Seite, kein Fokusrahmen beim Zeiger. */
input[readonly] {
	background: var(--bg-sidebar);
	color: var(--text-muted);
}

input[readonly]:hover {
	border-color: var(--border);
}

/* Dateiwahl: gleiche Höhe wie die übrigen Felder. Knopf und Zustand
   des Feldes zeichnet der Browser; eng gesetzt, damit «Keine
   ausgewählt» neben dem Knopf ganz dasteht und nicht gekürzt wird. */
input[type="file"] {
	width: 100%;
	height: 34px;
	padding: 0 var(--raum-2);
	background: var(--bg);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	font: inherit;
	font-size: var(--t--3);
	line-height: 32px;
}

input[type="file"]::file-selector-button {
	margin: 0 var(--raum-2) 0 0;
	padding: 0 var(--raum-2);
	height: 24px;
	background: var(--surface);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	font: inherit;
	font-size: var(--t--3);
	cursor: pointer;
}

.feld-aktionen {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--raum-3);
}

.knopf {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--raum-2);
	min-height: var(--feld);
	padding: 0 var(--raum-5);
	background: var(--surface);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	font: inherit;
	font-size: var(--t--1);
	font-weight: 500;
	text-decoration: none;
	cursor: pointer;
}

.knopf:hover {
	border-color: var(--text-faint);
}

.knopf-haupt {
	background: var(--accent);
	border-color: var(--accent);
	color: var(--accent-contrast);
}

.knopf-haupt:hover {
	background: color-mix(in srgb, var(--accent) 86%, var(--text));
	border-color: color-mix(in srgb, var(--accent) 86%, var(--text));
}

.knopf-leise {
	background: none;
	border-color: transparent;
	color: var(--text-muted);
	padding-inline: var(--raum-3);
}

.knopf-leise:hover {
	background: var(--surface);
	border-color: transparent;
	color: var(--text);
}

.alternative {
	border-top: 1px solid var(--border);
	padding-top: var(--raum-4);
	display: grid;
	gap: var(--raum-4);
}

.alternative summary {
	cursor: pointer;
	font-size: var(--t--1);
	color: var(--text-muted);
	width: fit-content;
}

.alternative summary:hover {
	color: var(--text);
}

/* Hinweise ---------------------------------------------------------------- */

.hinweis {
	color: var(--text-muted);
	font-size: var(--t--1);
	max-width: var(--prosa);
}

/* Eine Meldung ist ein Satz, kein Kasten: keine Fläche, kein Balken.
   Fehler in der Statusfarbe, Hinweise in Tinte. */
.meldung {
	padding: 0;
	border: 0;
	background: none;
	max-width: var(--prosa);
	font-size: var(--t--1);
	line-height: 1.5;
}

.meldung-fehler {
	color: var(--danger);
}

.abgabe-kasten,
.anmeldung {
	padding: var(--raum-5) 0 0;
	border-top: 1px solid var(--border);
	max-width: var(--prosa);
}

.funktion {
	font-size: var(--t-1);
	color: var(--text-muted);
}

.externer-link {
	font-size: var(--t--1);
	overflow-wrap: anywhere;
}

/* Fuss -------------------------------------------------------------------- */

.fuss {
	grid-area: fuss;
	margin-top: var(--raum-7);
	padding: var(--raum-5) 0 var(--raum-6);
	border-top: 1px solid var(--border);
	color: var(--text-muted);
	font-size: var(--t--1);
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--raum-3) var(--raum-5);
}

.fuss a {
	color: var(--text-muted);
	text-decoration-color: color-mix(in srgb, var(--text-muted) 35%, transparent);
}

.fuss a:hover {
	color: var(--link);
}

/* --------------------------------------------------------------------------
   7. Suchpalette
   Die Palette wohnt in assets/css/suche.css (Klassen .suchpalette-*).
   Hier stand frueher eine zweite Fassung unter .palette-*; sie wurde von
   niemandem mehr benutzt und ist entfernt.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   8. Schmale Fenster
   -------------------------------------------------------------------------- */

/* Die Nebenspalte braucht Platz; vorher rutscht sie unter den Text. */
@media (max-width: 1180px) {
	.spalte,
	.spalte-breit {
		grid-template-columns: minmax(0, var(--haupt));
		grid-template-areas:
			"sicht"
			"haupt"
			"neben"
			"fuss";
		grid-template-rows: auto auto auto auto;
	}

	.nebenspalte {
		padding-block: 0 var(--raum-6);
		max-width: var(--haupt);
	}

	.aside-block:first-child {
		padding-top: var(--raum-5);
		border-top: 1px solid var(--border);
	}
}

@media (max-width: 1024px) {
	:root {
		--rand: 40px;
	}
}

@media (max-width: 900px) {
	/* Die Schriftskala bleibt dieselbe wie auf dem Schirm. Sie hier je
	   Stufe anders zu setzen, brachte 18, 22 und 26 px ins Spiel — Grade,
	   die in keiner Skala stehen, und eine Hierarchie, in der h2 (22) fast
	   so gross war wie h1 (26). Schmaler wird nur, was von der Breite
	   abhaengt: die Raender und die beiden Titelgrade (§33). */
	:root {
		--rand: 20px;
		--luft: 0px;
	}

	.shell {
		grid-template-columns: minmax(0, 1fr);
	}

	.topbar {
		display: flex;
		grid-column: 1 / -1;
	}

	.seitenleiste {
		position: fixed;
		top: 0;
		bottom: 0;
		left: 0;
		width: min(320px, 88vw);
		height: auto;
		transform: translateX(-100%);
		transition: transform 0.2s ease;
		box-shadow: var(--shadow);
		border-right: 1px solid var(--border);
	}

	.leiste-schliessen {
		display: block;
	}

	.shell[data-sidebar="offen"] .seitenleiste {
		transform: none;
	}

	.shell[data-sidebar="offen"] .backdrop {
		display: block;
	}

	.inhalt {
		padding-block: var(--raum-5) var(--raum-6);
	}

	/* Schmal traegt auch der Auftakt den normalen Titelgrad; er faellt
	   mit ihm weiter auf 24 px (§33). */
	.titelband-auftakt h1 {
		font-size: var(--t-4);
	}

	.titelband-auftakt .lead {
		font-size: var(--t-1);
	}

	.bereiche {
		grid-template-columns: minmax(0, 1fr);
	}

	.bereiche > li:last-child {
		border-bottom: 1px solid var(--border);
	}

	.meldungen li {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--raum-1);
	}

	.tabelle th,
	.tabelle td {
		padding-right: var(--raum-3);
	}
}

@media (max-width: 520px) {
	.palette {
		padding: 0;
	}

	.palette-fenster {
		width: 100%;
		height: 100%;
		border-radius: 0;
		border: 0;
	}

	.palette-koerper {
		max-height: none;
	}

	.feld-aktionen .knopf {
		width: 100%;
	}
}

/* --------------------------------------------------------------------------
   9. Bewegung und Druck
   -------------------------------------------------------------------------- */

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

@media print {
	.seitenleiste,
	.topbar,
	.palette,
	.backdrop,
	.skiplink,
	.meta-panel,
	.shell,
	.spalte {
		display: block;
	}

	.inhalt,
	.nebenspalte,
	.fuss {
		max-width: none;
		padding: 0;
	}

	.nebenspalte {
		margin-top: 2rem;
		border-top: 1px solid #999;
		padding-top: 1rem;
	}

	:root {
		--haupt: none;
		--prosa: none;
		--rand: 0px;
	}

	body {
		background: #fff;
		color: #000;
		font-size: 11pt;
	}

	a {
		color: #000;
		text-decoration: underline;
	}

	/* Ziel der Links ausschreiben, das Papier kennt kein Klicken. */
	.inhalt a[href^="http"]::after,
	.inhalt a[href^="/"]::after {
		content: " (" attr(href) ")";
		font-size: 9pt;
		color: #444;
		word-break: break-all;
	}

	.mat-eintrag,
	.seitenliste > li,
	.bereiche > li {
		break-inside: avoid;
	}

	.tabelle thead {
		display: table-header-group;
	}
}

/* --------------------------------------------------------------------------
   10. Materialbrowser
   Das wichtigste Bauteil: Typleiste, Suchfeld, Zeilen, Vorschau-Panel.
   Die Ansicht der Liste aendert Dichte und Spalten — die Mechanik
   bleibt dieselbe.
   -------------------------------------------------------------------------- */

.browser {
	/* Die Vorschau muss ein A4-PDF lesbar zeigen: knapp die Hälfte, aber
	   nie unter 560 px. Darunter ist eine PDF-Seite nur noch ein Bild. */
	--panel: clamp(560px, 46%, 50%);
	--mb-typ: 108px;
	--mb-groesse: 4.25rem;
	/* Der Titel bekommt, was übrig bleibt; Autor und Jahr sind so breit
	   wie ihr Inhalt und fallen weg, wenn er fehlt. Vorher waren sie fest
	   und haben dem Titel den Platz genommen. */
	--mb-spalten:
		var(--mb-typ) minmax(0, 1fr) minmax(0, max-content) minmax(0, max-content)
		auto var(--mb-groesse) 18px;
	--mb-zeile: 44px;
}

.browser-titel {
	margin-bottom: var(--raum-3);
}

/* Kopf: Typleiste links, Suche rechts ------------------------------------ */

.browser-kopf {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--raum-3) var(--raum-5);
	padding-bottom: var(--raum-3);
}

.browser-typen {
	display: flex;
	flex-wrap: wrap;
	gap: var(--raum-2);
	min-width: 0;
}

/* Die Typleiste des Browsers, die Reiter des Eingangs und die Typleiste
   des Bereichsfilters (.bf-knopf) tun dasselbe und sehen darum gleich
   aus: Textknöpfe, der Unterstrich ist der Zustand. Keine Pillen — sie
   versprechen eine Fläche, die es nicht gibt. `.typ-knopf` stand bis
   hierher zweimal in dieser Datei, mit zwei verschiedenen Formen; jetzt
   einmal. */
.typ-knopf {
	display: inline-flex;
	align-items: baseline;
	gap: 0.4em;
	min-height: 30px;
	padding: 0 var(--raum-2);
	background: none;
	border: 0;
	color: var(--text-muted);
	font: inherit;
	font-size: var(--t--1);
	cursor: pointer;
	white-space: nowrap;
}

.typ-knopf:hover {
	color: var(--text);
	box-shadow: inset 0 -1px 0 0 var(--text-faint);
}

/* Die Zahl neben dem Typ ist eine Hilfsbeschriftung: ein Grad aus der
   Skala, kein `em`-Bruchteil des Nachbarn (der ergab 11.48 px). */
.typ-zahl {
	font-variant-numeric: tabular-nums;
	font-size: var(--t--3);
	color: var(--text-faint);
}

.typ-knopf.ist-aktiv {
	color: var(--accent-text);
	box-shadow: inset 0 -2px 0 0 var(--accent);
}

.typ-knopf.ist-aktiv .typ-zahl {
	color: inherit;
}

.browser-suche {
	position: relative;
	display: flex;
	align-items: center;
	flex: 0 1 18rem;
	min-width: 12rem;
}

.browser-suche-icon {
	position: absolute;
	left: 0.6rem;
	color: var(--text-faint);
	pointer-events: none;
}

.browser-suche input {
	height: 34px;
	padding-left: 2rem;
	font-size: var(--t--1);
}

.browser-sprungliste {
	font-size: var(--t--1);
	color: var(--text-muted);
	padding-bottom: var(--raum-3);
	display: flex;
	flex-wrap: wrap;
	gap: var(--raum-3);
}

/* Korpus: Liste und Panel nebeneinander ---------------------------------- */

.browser-korpus {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 0;
	align-items: start;
}

.browser.ist-offen .browser-korpus,
.browser.ist-split .browser-korpus {
	grid-template-columns: minmax(0, 1fr) var(--panel);
	gap: var(--raum-5);
}

/* Auf schmaleren Schirmen nimmt das Panel der Liste die Spalten weg —
   dann fallen Autor, Jahr und die Kopfzeile weg. Im Split-View auf
   breiten Schirmen ist dafür Platz, dort bleibt alles stehen. */
.browser.ist-offen:not(.ist-split) .mb-meta,
.browser.ist-offen:not(.ist-split) .mb-kopf {
	display: none;
}

.browser.ist-offen:not(.ist-split) .mb-zeile {
	grid-template-columns: var(--mb-typ) minmax(0, 1fr) auto var(--mb-groesse) 18px;
}

.browser.ist-offen:not(.ist-split) {
	--mb-typ: 24px;
}

.browser.ist-offen:not(.ist-split) .mb-typ-kurz,
.browser.ist-offen:not(.ist-split) .mb-typ-lang {
	display: none;
}

/* Split-View: das Panel steht dauerhaft rechts und zeigt, solange nichts
   gewählt ist, nur einen Hinweis — geladen wird erst auf Klick. */
.browser.ist-split .browser-panel {
	--panel: 40%;
}

.panel-leer {
	display: grid;
	place-items: center;
	min-height: 12rem;
	padding: var(--raum-5);
	border: 1px dashed var(--border);
	color: var(--text-muted);
	font-size: var(--t--1);
	text-align: center;
}

.browser-liste {
	min-width: 0;
	border-top: 1px solid var(--border);
}

/* Die Zwischentitel stammen aus dem alten Wiki: ungleichmässig und
   nicht redaktionell gesetzt. Sie ordnen, sollen aber leiser sein als
   die Zeilen, die sie ordnen. */
.browser-gruppe {
	padding-block: var(--raum-5) var(--raum-2);
	padding-inline: 0;
	font-size: var(--t--2);
	font-weight: 500;
	color: var(--text-muted);
}

.browser-gruppe:first-child {
	padding-top: var(--raum-3);
}

/* Zeile ------------------------------------------------------------------- */

.mb-eintrag {
	border-bottom: 1px solid var(--border);
}

.mb-zeile {
	display: grid;
	grid-template-columns: var(--mb-spalten);
	align-items: center;
	gap: 0 var(--raum-3);
	min-height: var(--mb-zeile);
	padding: var(--raum-2) 0;
	list-style: none;
	cursor: pointer;
	font-size: var(--t--1);
	line-height: 1.3;
}

.mb-zeile::-webkit-details-marker { display: none; }
.mb-zeile::marker { content: ""; }

.mb-zeile:hover {
	background: var(--surface);
}

.mb-zeile:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: -2px;
}

.mb-eintrag.ist-gewaehlt > .mb-zeile {
	background: var(--surface);
	box-shadow: inset 2px 0 0 0 var(--accent);
}

.mb-typ {
	display: flex;
	align-items: center;
	gap: var(--raum-2);
	min-width: 0;
	color: var(--text-muted);
}

.mb-typ-kurz {
	font-size: 10px;
	font-weight: 500;
	color: var(--text-muted);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.mb-typ-lang { display: none; }

/* Eigene Spalten für Beschrieb und Abschnitt gibt es erst, wenn wirklich
   Platz da ist; sonst stehen sie unter dem Titel bzw. nur im Panel. */
.mb-gruppe-zelle { display: none; }

.mb-haupt {
	min-width: 0;
}

/* Zwei Zeilen sind erlaubt — lieber umbrechen als abschneiden. Die
   Ellipse kommt erst auf sehr schmalen Schirmen zum Zug. */
.mb-titel {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	font-weight: 600;
	color: var(--text);
	overflow-wrap: anywhere;
}

.mb-zeile:hover .mb-titel,
.ist-gewaehlt .mb-titel {
	color: var(--link);
}

.mb-beschrieb {
	display: block;
	margin-top: 1px;
	font-size: var(--t--2);
	color: var(--text-muted);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Autor und Jahr sind auf breiten Schirmen eigene Spuren des Rasters.
   Steht das Vorschau-Panel offen, wird die Liste schmal — dann fallen
   sie weg, damit der Titel lesbar bleibt. */
.mb-meta {
	display: contents;
}

.mb-autor,
.mb-jahr {
	font-size: var(--t--2);
	color: var(--text-muted);
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.mb-jahr {
	font-variant-numeric: tabular-nums;
}

.mb-formate {
	display: flex;
	gap: 4px;
}

/* Die Formatmarke ist der Download. Ein Klick darauf laedt die Datei,
   ohne dass die Vorschau aufgeht. */
/* Eine Formatangabe ist ein Wort, kein Etikett. Umrandete Mono-Kästchen
   waren dieselbe Kartenoptik wie die Bögen um die Listeneinträge. */
.mb-marke {
	position: relative;
	display: inline-flex;
	align-items: center;
	height: 20px;
	font-size: var(--t--2);
	line-height: 1.3;
	color: var(--text-muted);
	text-decoration: none;
	white-space: nowrap;
}

/* Die Trefferfläche ist grösser als das Wort: 24 × 24 px auf dem Schirm,
   44 × 44 unter 700 px — dieselbe Technik und dasselbe Mass wie am
   Klappenknopf (materialliste.css §7). Sie liegt als unsichtbare Fläche
   über der Marke und ändert nichts an der Zeile: nicht ihre Höhe, nicht
   die Spur «Format», nicht die Grundlinie. Ein Polster an der Marke
   selbst hätte all das verschoben.
   `width: max(100%, …)` statt eines festen Überhangs: «ZIP» ist
   schmaler als «DOCX», und eine feste Zugabe machte das eine Ziel gross
   genug und das andere nicht. */
.mb-marke::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	translate: -50% -50%;
	width: max(100%, 24px);
	height: 24px;
}

.mb-marke + .mb-marke {
	margin-left: var(--raum-2);
}

/* Unter 700 px ist der Zeiger ein Finger: 44 × 44. Damit zwei Marken
   nebeneinander nicht DIESELBE Fläche beanspruchen — ein Tipp auf «PDF»
   lüde sonst die DOCX —, rückt der Abstand zwischen ihnen mit. 22 px
   sind genau die halbe Zugabe der schmalsten Marke auf jeder Seite. */
@media (max-width: 700px) {
	.mb-marke::after {
		width: max(100%, 44px);
		height: 44px;
	}

	.mb-marke + .mb-marke {
		margin-left: 22px;
	}
}

.mb-marke:hover {
	border-color: var(--accent);
	color: var(--accent-text);
}

.mb-groesse {
	font-variant-numeric: tabular-nums;
	font-size: var(--t--2);
	color: var(--text-muted);
	text-align: right;
	white-space: nowrap;
}

.mb-chevron {
	display: grid;
	place-items: center;
	color: var(--text-muted);
}

.mb-pfeil {
	transition: transform 0.16s ease;
}

.mb-eintrag[open] .mb-pfeil {
	transform: rotate(90deg);
}

/* Das Detail im Markup ist die Fassung ohne JavaScript; mit JavaScript
   wandert sein Inhalt ins Panel. */
.mb-detail {
	display: grid;
	gap: var(--raum-3);
	padding: var(--raum-4) 0 var(--raum-5);
	background: var(--surface);
	font-size: var(--t--1);
}

.mb-detail-kopf {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--raum-3);
}

.mb-detail-titel {
	font-weight: 600;
}

.mb-detail-typ {
	font-size: var(--t--2);
	color: var(--text-muted);
}

.mb-detail-beschrieb {
	max-width: 62ch;
	line-height: 1.5;
}

.mb-angaben {
	display: grid;
	grid-template-columns: 7rem minmax(0, 1fr);
	gap: var(--raum-1) var(--raum-3);
	margin: 0;
	font-size: var(--t--2);
}

.mb-angaben dt {
	color: var(--text-muted);
}

.mb-angaben dd {
	margin: 0;
}

.mb-aktionen {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--raum-2);
}

.mb-marke-groesse {
	font-size: 10px;
	color: var(--text-muted);
}

/* Mit JavaScript übernimmt das Panel; das inline-Detail bleibt stumm. */
.js-browser .mb-detail {
	display: none;
}

/* Vorschau-Panel ---------------------------------------------------------- */

.browser-panel {
	/* Volle Höhe des Fensters, eigener Scrollbereich: die Liste links
	   scrollt unabhängig weiter. */
	position: sticky;
	top: 0;
	display: grid;
	grid-template-rows: auto auto auto auto;
	align-content: start;
	gap: var(--raum-3);
	height: 100vh;
	max-height: 100vh;
	padding: var(--raum-4);
	border-left: 1px solid var(--border);
	background: var(--surface);
	min-width: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
}

.panel-kopf {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--raum-3);
}

.panel-titel {
	font-weight: 600;
	line-height: 1.3;
	min-width: 0;
	overflow-wrap: anywhere;
}

.panel-schliessen {
	flex: none;
	display: grid;
	place-items: center;
	width: 32px;
	height: 32px;
	padding: 0;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text-muted);
	cursor: pointer;
}

.panel-schliessen:hover {
	background: var(--surface-2);
	color: var(--text);
}

.panel-vorschau {
	min-height: 0;
	display: grid;
}

.panel-pdf {
	width: 100%;
	height: min(58vh, 620px);
	border: 1px solid var(--border);
	background: var(--bg);
}

.panel-bild {
	width: 100%;
	height: auto;
	max-height: 58vh;
	object-fit: contain;
	border: 1px solid var(--border);
	background: var(--bg);
}

.panel-video {
	width: 100%;
	max-height: 58vh;
	background: #000;
}

.panel-keine {
	display: grid;
	place-items: center;
	min-height: 8rem;
	padding: var(--raum-5);
	border: 1px dashed var(--border);
	color: var(--text-muted);
	font-size: var(--t--1);
	text-align: center;
}

.panel-angaben {
	min-height: 0;
	overflow-y: auto;
	display: grid;
	gap: var(--raum-3);
	font-size: var(--t--1);
}

.panel-angaben .mb-detail-kopf {
	display: none; /* der Titel steht schon im Panelkopf */
}

/* --------------------------------------------------------------------------
   Schmale Fenster: das Panel wird zum Blatt über der Liste.
   -------------------------------------------------------------------------- */

@media (max-width: 900px) {
	.browser {
		--mb-spalten: 22px minmax(0, 1fr) auto 20px;
		--mb-zeile: 52px;
	}

	.mb-zeile {
		grid-template-areas:
			"typ haupt formate chevron"
			".   meta  meta    .";
		align-items: start;
		padding-block: var(--raum-3);
	}

	.mb-typ { grid-area: typ; padding-top: 2px; }
	.mb-typ-kurz, .mb-typ-lang { display: none; }

/* Eigene Spalten für Beschrieb und Abschnitt gibt es erst, wenn wirklich
   Platz da ist; sonst stehen sie unter dem Titel bzw. nur im Panel. */
.mb-gruppe-zelle { display: none; }
	.mb-haupt { grid-area: haupt; }

	.mb-titel {
		-webkit-line-clamp: 3;
	}

	.mb-beschrieb {
		white-space: normal;
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
	}

	.mb-formate { grid-area: formate; }
	.mb-chevron { grid-area: chevron; padding-top: 3px; }

	.mb-autor,
	.mb-jahr,
	.mb-groesse {
		grid-area: meta;
		display: inline;
		text-align: left;
		margin-right: var(--raum-3);
	}

	.mb-autor:empty,
	.mb-jahr:empty,
	.mb-groesse:empty { display: none; }

	.browser.ist-offen .browser-korpus {
		grid-template-columns: minmax(0, 1fr);
		gap: 0;
	}

	.browser-panel {
		position: fixed;
		inset: 0;
		z-index: 60;
		max-height: none;
		border: 0;
		border-radius: 0;
		background: var(--bg);
		grid-template-rows: auto auto 1fr;
		padding: var(--raum-4);
		overflow-y: auto;
	}

	.panel-pdf,
	.panel-bild,
	.panel-video {
		height: 50vh;
		max-height: none;
	}

	.browser-suche {
		flex: 1 1 100%;
	}
}

@media print {
	.browser-kopf,
	.browser-panel,
	.mb-chevron {
		display: none !important;
	}

	.mb-detail {
		display: block !important;
	}

	.mb-eintrag {
		break-inside: avoid;
	}
}

/* --------------------------------------------------------------------------
   Siehe-auch-Zeile
   -------------------------------------------------------------------------- */

.verweise {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--raum-2);
	max-width: var(--prosa);
	font-size: var(--t--1);
}

.verweise-titel {
	color: var(--text-muted);
}

.verweise-trenner {
	color: var(--text-muted);
}

.mehr-zahl {
	font-size: var(--t--2);
	color: var(--text-muted);
}

/* Jedes <details> traegt eine Gestaltung: der Standardmarker des Browsers
   und sein Rahmen sind nie Absicht. Wer ein eigenes Zeichen setzt,
   ueberschreibt das hier. */
summary {
	cursor: pointer;
	list-style: none;
}

summary::-webkit-details-marker {
	display: none;
}

summary::marker {
	content: "";
}

summary:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: var(--radius-sm);
}

/* --------------------------------------------------------------------------
   11. Zugeklappter Textabschnitt
   Auf Themenseiten steht das Material oben; der laengere Text folgt
   darunter und laesst sich wegklappen.
   -------------------------------------------------------------------------- */

.mehr {
	max-width: var(--prosa);
	border-top: 1px solid var(--border);
	padding-top: var(--raum-4);
}

.mehr-titel {
	display: flex;
	align-items: center;
	gap: var(--raum-2);
	width: fit-content;
	padding: var(--raum-1) 0;
	font-size: var(--t-1);
	font-weight: 600;
	color: var(--text);
	cursor: pointer;
	list-style: none;
}

.mehr-titel::-webkit-details-marker { display: none; }
.mehr-titel::marker { content: ""; }

.mehr-titel::before {
	content: "";
	width: 8px;
	height: 8px;
	border-right: 1.6px solid var(--text-faint);
	border-bottom: 1.6px solid var(--text-faint);
	transform: rotate(-45deg);
	transition: transform 0.16s ease;
}

.mehr[open] > .mehr-titel::before {
	transform: rotate(45deg);
}

.mehr-titel:hover {
	color: var(--link);
}

.mehr > .prosa {
	margin-top: var(--raum-4);
}

/* Die Ueberschriften im aufgeklappten Text duerfen nicht lauter sein
   als der Abschnittstitel selbst. */
.mehr .prosa h2 {
	font-size: var(--t-1);
	margin-top: var(--raum-5);
}

@media print {
	.mehr > .prosa { display: block !important; }
}

/* --------------------------------------------------------------------------
   12. Layout-Zeilen im Menü «Darstellung»
   -------------------------------------------------------------------------- */










/* --------------------------------------------------------------------------
   13. Bausteine, die nur einzelne Richtungen zeigen
   Sie stehen immer im Markup — welche Richtung sie einblendet, entscheidet
   allein die Gestaltung.
   -------------------------------------------------------------------------- */

/* Kopfzeile der Materialliste — die Ansicht «Tabelle» zeigt sie. */
.mb-kopf {
	display: none;
	grid-template-columns: var(--mb-spalten);
	align-items: center;
	gap: 0 var(--raum-3);
	padding: 0 0 var(--raum-2);
	font-size: var(--t--2);
	font-weight: 600;
	color: var(--text-muted);
}

/* Symbol der Bereiche auf der Startseite. */
.bereich-icon {
	display: grid;
	place-items: center;
	width: 36px;
	height: 36px;
	color: var(--text-faint);
}

/* Symbol vor den Hauptbereichen. */
.nav-icon {
	display: inline-flex;
	flex: none;
	margin-right: var(--raum-2);
	color: var(--text-muted);
}

/* «Katalyse und Reaktionsgeschwindigkeit» darf umbrechen, aber zwischen
   den Wörtern. `overflow-wrap` trennte mitten im Wort: «…geschwindigkei /
   t». Silbentrennung macht daraus einen sauberen Umbruch, und ein Wort,
   das auch dafür zu lang ist, schrumpft die Schrift nicht — es steht
   eben in zwei Zeilen. */
.nav-text {
	min-width: 0;
	hyphens: auto;
	overflow-wrap: normal;
	word-break: normal;
}

/* --------------------------------------------------------------------------
   14. Anmeldung
   Ein Feld, Enter. Keine Knöpfe, keine Auswahl — der Weg ist eindeutig.
   -------------------------------------------------------------------------- */

.login-formular {
	max-width: 24rem;
	gap: var(--raum-4);
}

.login-formular .feld label {
	font-size: var(--t-0);
}

.login-formular input {
	font-size: var(--t-1);
}

.login-formular #login-code {
	letter-spacing: 0.12em;
	font-size: var(--t-2);
	text-align: center;
}

.meldung-hinweis {
	color: var(--text);
}

.login-alternative {
	margin-top: var(--raum-5);
	font-size: var(--t--1);
}

.login-alternative a {
	color: var(--text-muted);
}

.login-alternative a:hover {
	color: var(--link);
}

/* --------------------------------------------------------------------------
   15. Chips ohne Treffer
   Sichtbar, damit man sieht, was es gibt — aber stumm.
   -------------------------------------------------------------------------- */

.chip-knopf.ist-leer,
.chip-knopf[disabled] {
	color: var(--text-faint);
	border-style: dashed;
	cursor: default;
}

.chip-knopf.ist-leer:hover,
.chip-knopf[disabled]:hover {
	border-color: var(--border);
	color: var(--text-faint);
}

/* --------------------------------------------------------------------------
   16. Menü «Darstellung»
   Die Regeln des Dialogs stehen in Abschnitt 5 bei der Seitenleiste,
   gleich neben dem Knopf, der ihn öffnet. Hier blieb nur der Hinweis
   auf Kirby.
   -------------------------------------------------------------------------- */

/* Die letzte Zeile der Leiste: Darstellung links, Kirby rechts, eine
   Linie darüber. Beides 13 px im selben Sans wie alles andere — der
   Hinweis auf Kirby war in Mono das lauteste Element der Seite. */
.leiste-schluss {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--raum-3);
	margin-top: var(--raum-2);
	padding-top: var(--raum-2);
	border-top: 1px solid var(--border);
}

.leiste-kirby {
	flex: none;
	font-size: var(--t--2);
	color: var(--text-muted);
	text-decoration: none;
	white-space: nowrap;
}

.leiste-kirby:hover {
	color: var(--link);
	text-decoration: underline;
}

/* --------------------------------------------------------------------------
   17. Semesterübersicht
   Drei Ansichten derselben Termine: Semester (zwei Spalten, das ganze
   Halbjahr auf einen Blick), Tabelle, Liste. Welche die Vorgabe ist,
   entscheidet die Zahl der Termine — ab acht das Semester.
   -------------------------------------------------------------------------- */

.termine-kopf {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--raum-3) var(--raum-5);
	margin-bottom: var(--raum-4);
}

/* `baseline`, nicht `center`: Umschalter und Kalenderlink sitzen auf der
   Grundlinie des Titels «Termine». */
.termine-werkzeuge {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--raum-3) var(--raum-5);
}

/* Der Ansichtswechsel ist eine Textzeile, keine Schaltergruppe: dieselbe
   Form wie die Typleiste über den Dokumentlisten (`.bf-knopf`, Abschnitt
   32) — Textknöpfe, der aktive mit Unterstrich. Kein Rahmen, keine
   Fläche, keine Pille; in allen vier Looks dasselbe, weil keine Klasse
   mehr im Spiel ist, die ein Look zur Pille macht. */
.termine-ansichten {
	display: inline-flex;
	align-items: baseline;
	gap: var(--raum-1);
	flex-wrap: wrap;
}

.termin-ansicht-knopf {
	padding: 0 var(--raum-2);
	background: none;
	border: 0;
	color: var(--text-muted);
	font: inherit;
	font-size: var(--t--1);
	cursor: pointer;
	white-space: nowrap;
}

.termin-ansicht-knopf:hover {
	color: var(--text);
	box-shadow: inset 0 -1px 0 0 var(--text-faint);
}

.termin-ansicht-knopf.ist-aktiv {
	color: var(--accent-text);
	box-shadow: inset 0 -2px 0 0 var(--accent);
}

/* Der Kalender ist ein Textlink, kein Knopf: das Zeichen steht links vom
   Wort und hängt am Text, nicht in einer Fläche. */
.termine-ics {
	font-size: var(--t--1);
	color: var(--text-muted);
	text-decoration: none;
	white-space: nowrap;
}

.termine-ics .icon {
	margin-right: 0.35em;
	color: var(--text-faint);
}

.termine-ics:hover,
.termine-ics:hover .icon {
	color: var(--text);
}

.termine-ics:hover {
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

/* Datum eines Termins ----------------------------------------------------- */

/* Zwei Zeilen: oben die Zahl, darunter der Tag ausgeschrieben. Die Zahl
   trägt keinen eigenen Schriftgrad — sie erbt ihn samt Zeilenhöhe von der
   Zeile und sitzt damit in jeder Ansicht, jedem Look und beiden Layouts
   auf der Grundlinie der ersten Textzeile daneben. */
.termin-datum-zahl,
.termin-wochentag {
	display: block;
}

.termin-datum-zahl {
	font-variant-numeric: tabular-nums;
}

.termin-wochentag {
	font-size: var(--t--1);
	color: var(--text-muted);
	white-space: nowrap;
}

/* Unterlagen eines Termins ------------------------------------------------ */

/* Eine Formatmarke allein («PDF PDF PDF») sagt bei vierzehn Terminen
   nichts. Jede Unterlage steht darum als Zeile: Zeichen, Titel, Format —
   dieselbe Sprache wie in der Dokumentliste, in allen drei Ansichten. */
/* Zwei Spuren: das Zeichen so breit wie es ist, der Text nimmt den Rest.
   Umbricht der Titel, hängen die Folgezeilen unter der ersten und nicht
   unter dem Zeichen. */
.termin-datei {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	gap: var(--raum-2);
	align-items: start;
	color: var(--text);
	text-decoration: none;
}

.termin-datei-typ {
	margin-top: 0.15em;
	color: var(--text-faint);
}

/* Titel und Formatmarke sind EIN Textfluss. Als zweites Flex- oder
   Rasterkind sass die Marke am rechten Rand der Zelle, sobald der Titel
   umbrach — sie gehört aber hinter das letzte Wort. */
.termin-datei-text {
	min-width: 0;
	/* `break-word`, nicht `anywhere`: `anywhere` erlaubt den Umbruch an
	   jeder Stelle — auch zwischen dem letzten Wort und der Marke, die
	   dann allein auf der nächsten Zeile stünde. So bricht nur, was
	   sonst überliefe. */
	overflow-wrap: break-word;
}

/* Dieselbe Gestalt wie die Formatmarke einer Dokumentzeile:
   12.5 px, mit der gemeinsamen Textfarbe aus der Formatregel unten. */
.termin-endung {
	margin-left: 0.4em;
	font-size: var(--t--2);
	color: var(--text-faint);
	white-space: nowrap;
}

.termin-datei:hover .termin-datei-titel {
	color: var(--link);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

.termin-datei:hover .termin-datei-typ {
	color: var(--link);
}

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

.termin-zeile.ist-vergangen td {
	color: var(--text-muted);
}

/* Der nächste Termin: das ganze Feld dezent in der Akzentfarbe (20 %),
   folgt so jedem Farbthema. Ersetzt den Strich oben. */
.termin-zeile.ist-naechster td {
	background: color-mix(in srgb, var(--accent) 20%, transparent);
}

.termin-zeile.ist-vergangen .termin-datei,
.termin-zeile.ist-vergangen .termin-titel {
	color: var(--text-muted);
}

/* Semester ---------------------------------------------------------------- */

/* Das ganze Halbjahr auf einen Blick: erste Hälfte links, zweite rechts.
   Beide Zellen eines Paares stehen nacheinander im Markup und landen so in
   derselben Grid-Zeile — dadurch sind sie von selbst gleich hoch. Zwei
   unabhängige Spalten wären es nicht. */
/* Fünf Spuren, nicht zwei: je Semesterhälfte das Datum (so breit wie es
   ist) und der Inhalt (der Rest), dazwischen die Rinne mit der Trennlinie.
   Die Zellen sind Subgrids darin — damit misst der Browser die Datumsspur
   über alle Zeilen einer Hälfte, und die Inhalte beginnen in jeder Zeile
   an derselben Kante. Ein fester Wert bräche, sobald «Donnerstag» länger
   ausfällt als gedacht. */
.termine-raster {
	display: grid;
	grid-template-columns:
		max-content minmax(0, 1fr)
		var(--raum-5)
		max-content minmax(0, 1fr);
}

.termine-zelle {
	display: grid;
	grid-template-columns: subgrid;
	gap: var(--raum-1) 0;
	align-content: start;
	/* Anker für die waagrechte Linie der rechten Hälfte (unten). */
	position: relative;
	min-width: 0;
	padding: var(--raum-3) 0;
	border-bottom: 1px solid var(--border);
	font-size: var(--t--1);
	line-height: 1.45;
}

/* Kein Rahmen ums Ganze, keine Fläche: eine Linie je Zeile und die eine
   senkrechte Linie zwischen den Semesterhälften. Sie steht am Anfang der
   rechten Hälfte; links davon die Rinne, rechts davon dasselbe Mass als
   Polster — so liegt die Linie genau in der Mitte.

   Beide waagrechten Linien enden darum gleich weit von ihr entfernt: die
   linke Zelle hört eine Rinne vor der Senkrechten auf, die rechte
   beginnt ein Polster dahinter. Die rechte Linie kann deshalb keine
   `border-bottom` sein — die liefe über das Polster bis an die
   Senkrechte heran und stiesse links an sie an, während rechts 24 px
   Luft blieben. Sie ist ein `::after`, das erst am Polster anfängt. */
.termine-raster > .termine-zelle:nth-child(odd) {
	grid-column: 1 / span 2;
}

.termine-raster > .termine-zelle:nth-child(even) {
	grid-column: 4 / span 2;
	padding-left: var(--raum-5);
	border-left: 1px solid var(--border);
	border-bottom: 0;
}

.termine-raster > .termine-zelle:nth-child(even)::after {
	content: "";
	position: absolute;
	/* Gemessen wird ab dem Polsterkasten, also hinter der Senkrechten:
	   das Polster steht hier noch einmal als Mass, nicht als Rechnung. */
	inset-inline-start: var(--raum-5);
	inset-inline-end: 0;
	inset-block-end: 0;
	border-block-end: 1px solid var(--border);
}

/* Zwei Spalten: die letzte Rasterzeile braucht keine Linie darunter. Die
   Regel gilt nur dort — in einer Spalte ordnet `order` die Zellen um, dann
   liegt die letzte Zeile anderswo. */
@media (min-width: 901px) {
	.termine-raster > .termine-zelle:nth-last-child(-n + 2) {
		border-bottom: 0;
	}

	.termine-raster > .termine-zelle:nth-child(even):nth-last-child(-n + 2)::after {
		content: none;
	}
}

/* Bei ungerader Zahl fehlt rechts der letzte Termin; die Leerstelle trägt
   die senkrechte Linie weiter, damit sie nicht auf halber Höhe endet. */
.termine-zelle.ist-leerzelle {
	padding-block: 0;
}

/* Kein eigener Schriftgrad, keine eigene Zeilenhöhe: das Datum erbt beide
   von der Zelle und steht damit auf derselben Grundlinie wie die erste
   Textzeile daneben. Der Abstand zum Inhalt steht hier und nicht als
   Rasterlücke — so zählt er zur Datumsspur und misst in jeder Zeile
   gleich. */
.termine-zelle-datum {
	padding-right: var(--raum-3);
	color: var(--text-muted);
	white-space: nowrap;
}

.termine-zelle-inhalt {
	display: grid;
	gap: var(--raum-1);
	align-content: start;
	min-width: 0;
}

.termine-zelle.ist-vergangen,
.termine-zelle.ist-vergangen .termin-titel,
.termine-zelle.ist-vergangen .termin-datei {
	color: var(--text-muted);
}

.termine-zelle.ist-naechster {
	background: color-mix(in srgb, var(--accent) 20%, transparent);
}

.termine-zelle.ist-naechster .termine-zelle-datum {
	color: var(--accent-text);
}

/* Auf breiten Schirmen darf die Zelle atmen — aber nur in der Breite: die
   Höhe ist gebucht, das ganze Semester soll ohne Scrollen dastehen. */
@media (min-width: 1920px) {
	.termine-raster {
		grid-template-columns:
			max-content minmax(0, 1fr)
			var(--raum-7)
			max-content minmax(0, 1fr);
	}

	.termine-raster > .termine-zelle:nth-child(even) {
		padding-left: var(--raum-7);
	}

	.termine-raster > .termine-zelle:nth-child(even)::after {
		inset-inline-start: var(--raum-7);
	}

	.termine-zelle-datum {
		padding-right: var(--raum-4);
	}
}

/* Zeitleiste --------------------------------------------------------------- */

/* Wie beim Semesterraster führt die Liste die Spuren, die Zeilen sind
   Subgrids darin: das Datum so breit wie es ist, über alle Zeilen gleich. */
.zeitleiste {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: max-content minmax(0, 1fr);
}

.zeitleiste-punkt {
	display: grid;
	grid-column: 1 / -1;
	grid-template-columns: subgrid;
	padding: var(--raum-3) 0;
	border-bottom: 1px solid var(--border);
}

.zeitleiste-punkt.ist-vergangen {
	color: var(--text-muted);
}

.zeitleiste-datum {
	padding-right: var(--raum-4);
	color: var(--text-muted);
}

.zeitleiste-inhalt {
	display: grid;
	gap: var(--raum-1);
	min-width: 0;
}

.zeitleiste-heute {
	display: flex;
	grid-column: 1 / -1;
	align-items: center;
	gap: var(--raum-3);
	padding: var(--raum-2) 0;
	font-size: var(--t--2);
	color: var(--accent-text);
}

.zeitleiste-heute::after {
	content: "";
	flex: 1;
	height: 1px;
	background: var(--accent);
}

/* Kanban ------------------------------------------------------------------- */

.kanban {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--raum-4);
	align-items: start;
}

.kanban-spalte {
	display: grid;
	gap: var(--raum-2);
	align-content: start;
	min-width: 0;
}

.kanban-titel {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--raum-2);
	padding-bottom: var(--raum-2);
	border-bottom: 1px solid var(--text-muted);
	font-size: var(--t--2);
	font-weight: 600;
	color: var(--text-muted);
}

.kanban-zahl {
	color: var(--text-muted);
}

.kanban-leer {
	font-size: var(--t--2);
	color: var(--text-muted);
	padding: var(--raum-2) 0;
}

/* Die einzige Stelle mit Karten — und auch hier ohne Schatten. */
/* Kein Kasten je Termin: eine Linie trennt, der Abstand gruppiert. */
.kanban-karte {
	display: grid;
	gap: var(--raum-2);
	padding: var(--raum-3) 0;
	border-bottom: 1px solid var(--border);
	font-size: var(--t--1);
	min-width: 0;
}

.kanban-karte.ist-vergangen {
	color: var(--text-muted);
	background: none;
}

.kanban-datum {
	font-variant-numeric: tabular-nums;
	font-size: var(--t--2);
	color: var(--text-muted);
}

/* Kalender ----------------------------------------------------------------- */

.kalender-kopf {
	display: flex;
	align-items: center;
	gap: var(--raum-3);
	margin-bottom: var(--raum-3);
}

.kalender-titel {
	font-weight: 600;
	min-width: 12ch;
}

.kalender-schritt {
	display: grid;
	place-items: center;
	width: 30px;
	height: 30px;
	padding: 0;
	background: none;
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	color: var(--text-muted);
	cursor: pointer;
}

.kalender-schritt:hover:not(:disabled) {
	border-color: var(--text-muted);
	color: var(--text);
}

.kalender-schritt:disabled {
	opacity: 0.4;
	cursor: default;
}

.kalender-zurueck {
	transform: rotate(180deg);
}

.kalender-raster {
	display: grid;
	grid-template-columns: repeat(7, minmax(0, 1fr));
	gap: 1px;
	background: var(--border);
	border: 1px solid var(--border);
	overflow: hidden;
}

.kalender-wochentag {
	padding: var(--raum-2);
	background: var(--surface);
	font-size: var(--t--2);
	font-weight: 600;
	color: var(--text-muted);
}

.kalender-zelle {
	display: grid;
	align-content: start;
	gap: var(--raum-1);
	min-height: 5.5rem;
	padding: var(--raum-2);
	background: var(--bg);
	min-width: 0;
}

.kalender-zelle.ist-leer {
	background: var(--surface);
}

.kalender-zelle.ist-heute {
	box-shadow: inset 0 0 0 2px var(--accent);
}

.kalender-tag {
	font-variant-numeric: tabular-nums;
	font-size: var(--t--2);
	color: var(--text-muted);
}

.kalender-eintrag {
	font-size: var(--t--2);
	line-height: 1.3;
	padding: 3px 5px;
	background: color-mix(in oklab, var(--accent) 14%, var(--surface));
	color: var(--text);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

@media (max-width: 900px) {
	.kanban {
		grid-template-columns: minmax(0, 1fr);
	}

	/* Eine Spalte: Datum über Inhalt. Die Spur des Datums misst dann den
	   ganzen Streifen, die Zeile stapelt ihre beiden Teile. */
	.zeitleiste {
		grid-template-columns: minmax(0, 1fr);
	}

	.zeitleiste-punkt {
		gap: var(--raum-1);
	}

	.zeitleiste-datum {
		padding-right: 0;
	}

	/* Unter 900 px steht das Semester in einer Spalte; die senkrechte
	   Linie hat dann nichts mehr zu trennen. */
	.termine-raster {
		grid-template-columns: max-content minmax(0, 1fr);
	}

	.termine-raster > .termine-zelle:nth-child(odd),
	.termine-raster > .termine-zelle:nth-child(even) {
		grid-column: 1 / span 2;
		padding-inline: 0;
		border-left: 0;
		/* Ohne Senkrechte und ohne Polster gibt es nichts mehr
		   auszurichten: die Linie ist wieder eine gewöhnliche
		   `border-bottom`, damit die Regeln der letzten Zeile unten
		   greifen wie bei den ungeraden Zellen. */
		border-bottom: 1px solid var(--border);
	}

	.termine-raster > .termine-zelle:nth-child(even)::after {
		content: none;
	}

	/* Im Markup stehen die Zellen paarweise (links, rechts) — in einer
	   Spalte gehören sie wieder in die Reihenfolge des Semesters. Getrennt
	   wird dann jede Zeile ausser der letzten; welche das ist, hängt
	   daran, ob rechts eine Leerstelle steht (ungerade Terminzahl). */
	.termine-raster > .termine-zelle {
		order: var(--nr, 0);
	}

	.termine-raster > .termine-zelle:last-child,
	.termine-raster:has(> .ist-leerzelle) > .termine-zelle:nth-last-child(3) {
		border-bottom: 0;
	}

	.termine-zelle.ist-leerzelle {
		display: none;
	}

	.kalender-zelle {
		min-height: 3.5rem;
		padding: var(--raum-1);
	}

	.kalender-eintrag {
		font-size: 10px;
	}
}

@media print {
	.termine-ansichten,
	.termine-ics {
		display: none !important;
	}

	.termine-ansicht[hidden] {
		display: none !important;
	}
}

/* --------------------------------------------------------------------------
   18. Weiche Navigation
   -------------------------------------------------------------------------- */

/* Erscheint erst, wenn eine Antwort länger als 150 ms braucht. */
.ladebalken {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 2px;
	background: var(--accent);
	transform-origin: left;
	animation: ladebalken 1.6s ease-out;
	z-index: 40;
}

.spalte {
	position: relative;
}

@keyframes ladebalken {
	from { transform: scaleX(0.05); }
	to   { transform: scaleX(0.92); }
}

@media (prefers-reduced-motion: reduce) {
	.ladebalken { animation: none; transform: scaleX(0.5); }
}

/* Der Titel bekommt beim Seitenwechsel den Fokus; ein Ring gehört dort
   nicht hin, er ist kein Bedienelement. */
h1[tabindex="-1"]:focus {
	outline: none;
}

/* --------------------------------------------------------------------------
   19. Seitenleiste: Breite, Griff, Schiene
   Die Breite steht als --leiste am <html> — vom Server oder aus dem
   localStorage, in jedem Fall vor dem ersten Paint.
   -------------------------------------------------------------------------- */

.shell {
	transition: grid-template-columns 200ms cubic-bezier(.2, 0, 0, 1);
}

.seitenleiste {
	transition: transform 200ms cubic-bezier(.2, 0, 0, 1);
}

/* Beim Ziehen darf nichts nachlaufen. */
.leiste-zieht .shell,
.leiste-zieht .seitenleiste {
	transition: none;
}

.leiste-zieht {
	cursor: col-resize;
	user-select: none;
}

/* Griffzone am rechten Rand ------------------------------------------------ */

.leiste-griff {
	position: absolute;
	top: 0;
	right: -3px;
	width: 6px;
	height: 100%;
	cursor: col-resize;
	z-index: 5;
	touch-action: none;
}

.leiste-griff::before {
	content: "";
	position: absolute;
	inset: 0 2px;
	background: var(--accent);
	opacity: 0;
	transition: opacity 0.12s ease;
}

.leiste-griff:hover::before,
.leiste-griff:focus-visible::before,
.leiste-zieht .leiste-griff::before {
	opacity: 0.7;
}

.leiste-griff:focus-visible {
	outline: none;
}

/* Einklappknopf ------------------------------------------------------------ */

.leiste-einklappen {
	display: grid;
	place-items: center;
	width: 26px;
	height: 26px;
	flex: none;
	padding: 0;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text-muted);
	cursor: pointer;
}

.leiste-einklappen:hover {
	background: var(--surface-2);
	color: var(--text);
}

.leiste-einklappen-pfeil {
	transform: rotate(180deg);
}

/* Schiene ------------------------------------------------------------------ */

.schiene {
	display: none;
	position: sticky;
	top: 0;
	z-index: 29;
	height: 100vh;
	flex-direction: column;
	align-items: center;
	gap: var(--raum-2);
	padding: var(--raum-3) 0;
	background: var(--bg-sidebar);
	border-right: 1px solid var(--border);
	overflow: hidden;
}

.schiene-knopf {
	display: grid;
	place-items: center;
	width: 32px;
	height: 32px;
	flex: none;
	padding: 0;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text-muted);
	cursor: pointer;
	text-decoration: none;
}

.schiene-knopf:hover {
	background: var(--surface-2);
	color: var(--text);
}

.schiene-knopf.ist-aktiv {
	color: var(--accent-text);
	background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* Nur «Katalog» führt Symbole in der Navigation; nur dort sind sie ohne
   Beschriftung zu erkennen. */
.schiene-nav {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2px;
	margin-top: var(--raum-3);
	padding-top: var(--raum-3);
	border-top: 1px solid var(--border);
}

/* Eingeklappt --------------------------------------------------------------- */

[data-leiste="zu"] .shell {
	grid-template-columns: 44px minmax(0, 1fr);
}

[data-leiste="zu"] .schiene {
	display: flex;
}

[data-leiste="zu"] .seitenleiste {
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	width: var(--leiste);
	transform: translateX(-100%);
}

[data-leiste="zu"] .leiste-griff {
	display: none;
}

/* Hover-Peek: die Leiste schwebt über dem Inhalt und schiebt nichts. */
[data-leiste="zu"].leiste-peek .seitenleiste {
	transform: none;
	box-shadow: var(--shadow);
	z-index: 31;
}

@media (prefers-reduced-motion: reduce) {
	.shell,
	.seitenleiste {
		transition: none;
	}
}

/* Unter 900 px gibt es weder Griff noch Schiene: dort ist die Leiste ein
   Off-Canvas-Menü. */
@media (max-width: 900px) {
	.schiene,
	[data-leiste="zu"] .schiene,
	.leiste-griff,
	.leiste-einklappen {
		display: none !important;
	}

	[data-leiste="zu"] .shell {
		grid-template-columns: minmax(0, 1fr);
	}

	[data-leiste="zu"] .seitenleiste {
		width: min(320px, 88vw);
	}
}

/* --------------------------------------------------------------------------
   20. Gemeinsame Bausteine der Formularseiten
   Praktikumsanmeldung, Eingang, Kontenverwaltung und Speicherübersicht
   stammen aus verschiedenen Plugins. Ihre Bausteine stehen hier einmal,
   damit sie in allen drei Layout-Varianten gleich aussehen.
   -------------------------------------------------------------------------- */

/* Pflichtfeldzeichen: eine Angabe, kein Alarm. */
.pflicht {
	color: var(--text-muted);
	margin-left: 0.15em;
}

/* Honigtopf: für Menschen und Vorleseprogramme unsichtbar, für Bots da.
   Dieselbe Technik wie .visuell-versteckt, eigener Name, weil es keine
   Ansage ist, sondern eine Falle. */
.falle {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* Meldungen: dieselbe Form wie .meldung-fehler und .meldung-hinweis. */
.meldung-ok {
	border-left-color: var(--ok);
	background: color-mix(in srgb, var(--ok) 8%, transparent);
}

.meldung-ok > * + *,
.meldung-fehler > * + *,
.meldung-hinweis > * + * {
	margin-top: var(--raum-2);
}

/* Statusmarken: Anfragen, Abgaben, Konten — überall dieselbe Skala. */
.status,
.status-marke {
	font-size: var(--t--2);
	white-space: nowrap;
	color: var(--text-muted);
}

.status-neu {
	color: var(--accent-text);
}

.status-bestaetigt,
.status-aktiv {
	color: var(--ok);
}

.status-abgelehnt,
.status-gesperrt {
	color: var(--danger);
}

.status-erledigt,
.status-inaktiv {
	color: var(--text-muted);
}

/* Knopfvarianten */
.knopf-gefahr {
	background: var(--danger);
	border-color: var(--danger);
	color: var(--bg);
}

.knopf-gefahr:hover {
	background: color-mix(in srgb, var(--danger) 84%, var(--text));
	border-color: color-mix(in srgb, var(--danger) 84%, var(--text));
}

.knopf.ist-beschaeftigt {
	opacity: 0.6;
	cursor: progress;
}

/* --------------------------------------------------------------------------
   Sortierbare Tabellen
   Dieselbe Kopfzeile wie der Materialbrowser: klein, halbfett, gedämpft,
   kräftige Linie darunter. Der Sortierpfeil ist das einzige Zusätzliche.
   -------------------------------------------------------------------------- */

.tabelle-sortierbar th {
	padding: 0;
}

.sortknopf {
	display: flex;
	align-items: center;
	gap: var(--raum-1);
	width: 100%;
	padding: 0 var(--raum-4) var(--raum-2) 0;
	background: none;
	border: 0;
	color: inherit;
	font: inherit;
	font-size: var(--t--2);
	font-weight: 600;
	text-align: left;
	cursor: pointer;
}

.sortknopf:hover {
	color: var(--text);
}

.sortpfeil {
	color: var(--text-muted);
}

.tabelle-sortierbar th[aria-sort="ascending"] .sortpfeil::before { content: "\2191"; }
.tabelle-sortierbar th[aria-sort="descending"] .sortpfeil::before { content: "\2193"; }

.tabelle-sortierbar th[aria-sort="ascending"] .sortknopf,
.tabelle-sortierbar th[aria-sort="descending"] .sortknopf {
	color: var(--accent-text);
}

/* Kennzahlen über einer Tabelle: keine Kacheln, eine Reihe von Angaben. */
.kennzahlen {
	display: flex;
	flex-wrap: wrap;
	gap: var(--raum-3) var(--raum-6);
	margin: 0 0 var(--raum-5);
	padding-bottom: var(--raum-4);
	border-bottom: 1px solid var(--border);
}

.kennzahlen > div {
	display: grid;
	gap: 2px;
}

.kennzahlen dt {
	font-size: var(--t--2);
	color: var(--text-muted);
}

.kennzahlen dd {
	margin: 0;
	font-variant-numeric: tabular-nums;
	font-size: var(--t-1);
}

/* Reiter (Eingang) — dieselbe Form wie die Typleiste des Browsers und
   des Bereichsfilters: ein Wort, der Unterstrich ist der Zustand. */
.eingang-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--raum-2);
	margin-bottom: var(--raum-4);
}

.eingang-tab {
	display: inline-flex;
	align-items: baseline;
	gap: 0.4em;
	min-height: 30px;
	padding: 0 var(--raum-2);
	color: var(--text-muted);
	font-size: var(--t--1);
	text-decoration: none;
	white-space: nowrap;
}

.eingang-tab:hover {
	color: var(--text);
	box-shadow: inset 0 -1px 0 0 var(--text-faint);
}

.eingang-tab.ist-aktiv,
.eingang-tab[aria-current="page"] {
	color: var(--accent-text);
	box-shadow: inset 0 -2px 0 0 var(--accent);
}

.eingang-tab-zahl {
	font-size: var(--t--3);
	color: var(--text-faint);
}

.eingang-tab.ist-aktiv .eingang-tab-zahl,
.eingang-tab[aria-current="page"] .eingang-tab-zahl {
	color: inherit;
}

@media (max-width: 760px) {
	.darstellung {
		width: 100vw;
		max-width: none;
		height: 100vh;
		max-height: none;
		border: 0;
		border-radius: 0;
	}

	.darstellung-korpus {
		grid-template-columns: minmax(0, 1fr);
		max-height: none;
	}

	.darstellung-spalte + .darstellung-spalte {
		border-left: 0;
		border-top: 1px solid var(--border);
	}

	.theme-raster {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* --------------------------------------------------------------------------
   21. Suchfeld der Ergebnisseite
   Dieselbe Form wie das Feld in der Seitenleiste und in der Palette:
   ein Feld, ein Symbol darin, kein Knopf daneben.
   -------------------------------------------------------------------------- */

.suchfeld {
	position: relative;
	display: flex;
	align-items: center;
	max-width: 34rem;
	margin-bottom: var(--raum-5);
}

.suchfeld-icon {
	position: absolute;
	left: var(--raum-3);
	color: var(--text-muted);
	pointer-events: none;
}

.suchfeld input {
	height: 48px;
	padding-left: 2.6rem;
	font-size: var(--t-1);
}

/* Die Trefferzahl ist eine Angabe, keine Ansage. */
.suchseite-zahl {
	font-size: var(--t--2);
	color: var(--text-muted);
	margin-bottom: var(--raum-4);
}

.suchtreffer-meta {
	margin-top: var(--raum-2);
}

/* Die Fundstelle wird leise hervorgehoben, nicht angestrichen. */
.suchtreffer mark,
.suchpalette mark,
.suchtreffer-titel mark {
	background: color-mix(in oklab, var(--accent) 18%, transparent);
	color: inherit;
	border-radius: 2px;
	padding: 0 1px;
}

/* --------------------------------------------------------------------------
   23. Vorschau-Panel nimmt die rechte Fläche
   Solange die Vorschau steht, gibt es rechts nichts anderes: keine
   Nebenspalte, kein Rest. Vorher lag das Panel gequetscht zwischen Liste
   und Nebenspalte und war für ein A4-PDF zu schmal.
   -------------------------------------------------------------------------- */

.panel-offen .nebenspalte {
	display: none;
}

.panel-offen .spalte,
.panel-offen .spalte-breit {
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas:
		"sicht"
		"band"
		"haupt"
		"fuss";
}

/* Die übernommenen Angaben stehen unter den Dokumentangaben. */
.panel-neben:not(:empty) {
	padding-top: var(--raum-3);
	border-top: 1px solid var(--border);
	font-size: var(--t--2);
}

.panel-neben .aside-block + .aside-block {
	margin-top: var(--raum-3);
	padding-top: var(--raum-3);
}

.panel-neben h2 {
	font-size: var(--t--2);
	color: var(--text-muted);
	margin-bottom: var(--raum-1);
}

@media (max-width: 900px) {
	.panel-offen .nebenspalte {
		display: block;
	}

	.browser-panel {
		height: auto;
		max-height: none;
	}
}

/* --------------------------------------------------------------------------
   24. Startseite: Meldungen und Termine nebeneinander
   Eine Spalte Meldungen neben einer schmalen Spalte Termine. Darunter die
   Bereiche über die ganze Breite. Erst ab 1200 px — enger gedrängt lesen
   sich zwei Spalten schlechter als eine.
   -------------------------------------------------------------------------- */

.start-raster {
	display: grid;
	gap: var(--raum-6);
}

@media (min-width: 1200px) {
	.start-raster:not(.start-raster-einspaltig) {
		grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
		gap: var(--luft);
		align-items: start;
	}
}

.start-haupt,
.start-neben {
	min-width: 0;
}

/* Der Feed bleibt lesbar schmal — auch wenn er allein steht. Sonst
   wächst die Fläche mit dem längsten Satz statt mit dem Inhalt. */
.start-haupt .meldungen {
	max-width: var(--prosa);
}

/* Termine als Zeilenliste, nicht als Tabelle: drei Spalten Kopfzeile für
   fünf Zeilen wären mehr Gerüst als Inhalt. */
.terminliste {
	list-style: none;
	margin: 0;
	padding: 0;
}

.terminzeile {
	display: grid;
	grid-template-columns: 5.5rem minmax(0, 1fr);
	gap: var(--raum-1) var(--raum-3);
	align-items: baseline;
	padding: var(--raum-3) 0;
	border-bottom: 1px solid var(--border);
}

.termin-datum {
	font-size: var(--t--2);
	color: var(--text-muted);
	white-space: nowrap;
}

.termin-inhalt {
	min-width: 0;
	display: grid;
	gap: 2px;
}

.termin-titel {
	font-weight: 500;
	overflow-wrap: anywhere;
}

.termin-kurs {
	font-size: var(--t--2);
	color: var(--text-muted);
	text-decoration: none;
	justify-self: start;
}

.termin-kurs:hover {
	color: var(--link);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

/* --------------------------------------------------------------------------
   25. Navigation: Zeilen, die umbrechen dürfen
   Ein Bereich wie «Katalyse und Reaktionsgeschwindigkeit» passt nicht in
   eine Zeile. Er bricht um, ohne dass die Liste springt: die Zeilenhöhe
   ist ein Mindestmass, keine feste Höhe.
   -------------------------------------------------------------------------- */

.nav-zeile {
	align-items: stretch;
}

.nav-link {
	align-items: center;
	line-height: 1.3;
	padding-block: 0.3rem;
}

.nav-toggle {
	align-self: center;
}

/* --------------------------------------------------------------------------
   27. Breite Schirme: Fliesstext steht nie allein
   Ein Satz braucht 80 Zeichen, eine Liste nicht. Sobald der Inhalt Platz
   für zwei lesbare Spalten hat, bekommt er sie — sonst steht rechts von
   jeder Aufzählung ein halber Bildschirm Leere.

   Bezug ist die Breite des Inhalts (`@container inhalt`), nicht die des
   Fensters: die Seitenleiste ist verstellbar und einklappbar.
   -------------------------------------------------------------------------- */

@container inhalt (min-width: 1500px) {
	.seitenliste,
	.meldungen,
	.terminliste,
	.personenliste,
	.verweise {
		columns: 2;
		column-gap: var(--luft);
		max-width: none;
	}

	.seitenliste > li,
	.meldungen > li,
	.terminliste > li,
	.personenliste > li {
		break-inside: avoid;
	}

	/* Prosa bleibt lesbar, darf aber etwas weiter laufen. */
	.prosa {
		max-width: 88ch;
	}
}

@container inhalt (min-width: 2100px) {
	.seitenliste,
	.meldungen,
	.terminliste,
	.personenliste {
		columns: 3;
	}
}

/* --------------------------------------------------------------------------
   28. Textseiten: Prosa links, was dazugehört rechts
   Die einzige zulässige zweite Spalte auf einer Inhaltsseite — und nur,
   wenn sie etwas zu zeigen hat. Ohne Unterseiten oder Verweise läuft die
   Prosa breiter und die Listen darunter stehen mehrspaltig.
   -------------------------------------------------------------------------- */

.textseite {
	display: grid;
	gap: var(--luft);
	align-items: start;
}

@container inhalt (min-width: 1500px) {
	.textseite-zwei {
		grid-template-columns: minmax(0, 88ch) minmax(0, 1fr);
	}

	/* In der zweiten Spalte steht die Liste einspaltig — sie ist ja
	   bereits die zweite Spalte. */
	.textseite-neben .seitenliste,
	.textseite-neben .verweise {
		columns: auto;
	}
}

.textseite-prosa,
.textseite-neben {
	min-width: 0;
}

.textseite-solo .prosa {
	max-width: 90ch;
}

/* --------------------------------------------------------------------------
   29. Filterzeile
   Eine Zeile, 44 px. Links suchen, dann die Facetten als Knöpfe, rechts
   die Trefferzahl und die Sortierung. Was ein Filter anbietet, steht im
   Popover — nicht dauerhaft auf der Seite. Vier aufgeklappte Chipreihen
   waren 400 px, bevor der erste Treffer sichtbar wurde.
   -------------------------------------------------------------------------- */

.filterleiste {
	display: grid;
	gap: var(--raum-2);
}

/* Die Liste folgt dicht auf die Leiste: der erste Treffer soll auf einem
   1440x900-Schirm ohne Scrollen sichtbar sein. Die Leiste steht dafür
   seit B93 IM Strom der Liste (Abschnitt 32); der Abstand ist darum ihr
   eigener Aussenrand und keine Nachbarregel mehr. */
.dokumente-strom > .filterleiste {
	margin-bottom: var(--raum-2);
}

/* Eine Zeile, 44 px — und wenn der Platz nicht reicht, eine zweite. Was
   sie nicht darf: in sich scrollen. Ein `overflow-x` ungleich `visible`
   zwingt den Browser, auch `overflow-y` zu beschneiden; das absolut
   gesetzte .facette-popover verschwindet dann hinter der Knopfzeile und
   der Filter ist unbedienbar. */
.filterzeile {
	display: flex;
	align-items: center;
	gap: var(--raum-2);
	min-height: 44px;
	flex-wrap: wrap;
}

.fz-suche {
	position: relative;
	flex: 0 1 22rem;
	min-width: 12rem;
	display: flex;
	align-items: center;
}

.fz-suche-icon {
	position: absolute;
	left: 0.6rem;
	color: var(--text-faint);
	pointer-events: none;
}

.fz-suche input {
	width: 100%;
	height: var(--feld);
	padding-left: 2rem;
}

.fz-facetten {
	display: flex;
	align-items: center;
	gap: var(--raum-1);
	flex: 0 1 auto;
	flex-wrap: wrap;
	min-width: 0;
}

.facette {
	position: relative;
}

/* Ein Schalter neben dem Suchfeld: gleiche Feldhöhe, gleicher Radius,
   derselbe 1-px-Rahmen. Ohne Rahmen liest er sich als Text, nicht als
   etwas, das man drücken kann. */
.facette-knopf {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	height: var(--feld);
	padding: 0 0.6rem;
	border: 1px solid var(--border);
	border-radius: var(--radius);
	background: var(--bg);
	color: var(--text-muted);
	font-size: var(--t--1);
	cursor: pointer;
	list-style: none;
	white-space: nowrap;
}

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

.facette-knopf:hover {
	background: var(--surface-2);
	color: var(--text);
}

.facette-knopf.ist-aktiv {
	color: var(--accent-text);
	border-color: var(--accent);
	background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* «Typ · 1» statt eines blauen Kreises: die Zahl sagt, wie viele Werte
   gewählt sind — das ist eine Angabe, kein Alarm. */
.facette-zahl {
	font-size: var(--t--2);
	color: var(--accent-text);
}

.facette-zahl::before {
	content: "· ";
	color: var(--text-faint);
}

.facette-pfeil {
	width: 12px;
	height: 12px;
	transform: rotate(90deg);
	color: var(--text-faint);
}

.facette[open] > .facette-knopf {
	background: var(--surface-2);
	color: var(--text);
}

.facette[open] .facette-pfeil {
	transform: rotate(-90deg);
}

/* Ein geschlossenes <details> behaelt in neueren Browsern die Masse
   seiner Kinder (`content-visibility: hidden`). Ein absolut gesetztes
   Popover verbreitert damit die Seite, obwohl es niemand sieht. */
.facette:not([open]) .facette-popover {
	display: none;
}

.facette-popover {
	position: absolute;
	z-index: 40;
	top: calc(100% + 4px);
	left: 0;
	min-width: 17rem;
	max-width: min(28rem, 90vw);
	max-height: min(26rem, 60vh);
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: var(--raum-2);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	background: var(--surface);
	box-shadow: 0 12px 32px -12px rgba(0, 0, 0, 0.35);
}

.facette-suche {
	position: sticky;
	top: 0;
	padding-bottom: var(--raum-2);
	background: var(--surface);
}

.facette-suche input {
	width: 100%;
	height: 32px;
}

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

.facette-gruppe {
	padding: var(--raum-3) var(--raum-2) var(--raum-1);
	font-size: var(--t--2);
	color: var(--text-faint);
}

.facette-wert > a {
	display: grid;
	grid-template-columns: 16px minmax(0, 1fr) auto;
	align-items: center;
	gap: var(--raum-2);
	min-height: 32px;
	padding: 0 var(--raum-2);
	border-radius: var(--radius-sm);
	color: var(--text);
	text-decoration: none;
	font-size: var(--t--1);
}

.facette-wert > a:hover,
.facette-wert > a:focus-visible {
	background: var(--surface-2);
}

.facette-haken {
	width: 14px;
	height: 14px;
	opacity: 0;
	color: var(--accent-text);
}

.facette-wert[aria-selected="true"] > a {
	color: var(--accent-text);
}

.facette-wert[aria-selected="true"] .facette-haken {
	opacity: 1;
}

.facette-name {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.facette-anzahl {
	font-size: var(--t--2);
	color: var(--text-faint);
}

/* Ein Wert ohne Treffer verschwindet nicht — sonst weiss niemand, dass
   es ihn gibt. Er wird nur stumm. */
.facette-wert.ist-leer > a {
	color: var(--text-faint);
	pointer-events: none;
}

.fz-ergebnis {
	display: flex;
	align-items: center;
	gap: var(--raum-3);
	min-width: 0;
	flex: none;
}

.filterzeile .ansicht {
	margin-left: auto;
}

.fz-zahl {
	font-size: var(--t--1);
	color: var(--text-muted);
	white-space: nowrap;
}

.fz-sort {
	height: var(--feld);
	padding-block: 0;
	font-size: var(--t--1);
	color: var(--text-muted);
	max-width: 12rem;
}

.filterleiste.ist-laden .fz-zahl {
	opacity: 0.5;
}

/* Was gerade gilt, steht als eigene Zeile unter der Leiste — und nur
   dann. Jeder Chip nimmt seinen Filter wieder weg. */
.filter-aktiv {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--raum-2);
	margin: 0;
}

.filter-aktiv .filter-zuruecksetzen {
	margin-left: var(--raum-3);
	font-size: var(--t--1);
	color: var(--text-muted);
}

.filter-aktiv .filter-zuruecksetzen:hover {
	color: var(--link);
}

/* Das Kreuz kommt aus dem Stylesheet, damit der Chip vom Server und der
   vom Skript gebaute gleich aussehen. */
.chip-entfernen {
	gap: 0.35rem;
	text-decoration: none;
}

.chip-entfernen::after {
	content: "\00d7";
	font-size: 1.1em;
	line-height: 1;
	opacity: 0.8;
}


/* --------------------------------------------------------------------------
   30. Dokumentzeile
   Eine Zeile ist eine Zeile: auf der Themenseite wie in der Bibliothek.
   Fünf Fragen in fünf Spuren — was, welcher Typ, von wem, von wann,
   welche Formate.

   EIN Raster für Kopf und alle Zeilen: `.dokumente-strom` führt die
   Spuren, die Kopfzeile, die Liste und jede Zeile sind Subgrids darin
   (`grid-template-columns: subgrid`). Damit misst der Browser jede Spur
   über ALLE Zeilen UND den Kopf; die Kanten stimmen, ohne dass jemand
   Breiten rechnet. Vorher standen Kopf und Zeilen in getrennten Rastern,
   deren Spuren PHP aus Zeichenzahlen ableitete — das stimmte für eine
   Schrift und eine Breite, und die Site hat vier Looks.

   Was die Breite entscheidet:
     · Knopf und Zeichen: ihre eigene Grösse (18 px, 15 px),
     · Typwort, Autor, Stufe, Fachthema, Thema: `fit-content(<Deckel>)` —
       so viel wie nötig, nie mehr als der Deckel,
     · Jahr, Format, Grösse, Hochgeladen: `auto` — sie sind kurz,
     · Titel: `minmax(14rem, 64ch)` — er bekommt den Rest bis zum Deckel,
     · zuletzt eine leere Spur `1fr`: sie nimmt, was übrig bleibt.
   Die Kopfzeile zählt mit: eine Beschriftung bricht darum nie um.

   Die leere Spur am Ende ist das Mittel gegen die leere Mitte: Ohne sie
   war der Titel das einzige `1fr` und bekam JEDEN Überschuss — bei
   2560 px klaffte zwischen dem Ende des längsten Titels und der
   Autorenspalte ein Loch von 1006 px, und die Zeile zerfiel in zwei
   Hälften. Jetzt hört der Titel bei 64 Zeichen auf, die Angaben dahinter
   bleiben dicht am Text, und die überzählige Breite steht rechts als
   Rand (docs/DESIGN.md §2: der Inhalt wird nicht breiter, er wird mehr).
   `width: fit-content` am Strom wäre der naheliegende Weg und geht
   NICHT: der Strom ist der Abfragebehälter (`container-type:
   inline-size`), und Inline-Grössen-Containment heisst gerade, dass
   seine Breite nicht mehr aus dem Inhalt kommen darf — mit
   `fit-content` fiele er auf null zusammen.

   In der Ansicht «Tabelle» ist jede Zeile einzeilig und gleich hoch. Der
   Kontextsatz steht dort in der Klappe (materialliste.css §4); ein zu
   langer Titel wird mit Ellipse gekürzt und steht vollständig im
   `title`. Die Ansichten «Liste» und «Raster» (Abschnitt 37) stellen die
   Zeile um und zeigen den Satz wieder.
   -------------------------------------------------------------------------- */

.dokumente {
	/* Die Spurenliste steht einmal hier und gilt für den Strom wie für
	   den Ersatzweg ohne Subgrid. Die Reihenfolge ist die des Markups:
	   Klappe, Zeichen, Typwort, Titel, Autor, Jahr, Stufe, Fachthema,
	   Thema, Format, Grösse, Hochgeladen. Eine Spalte, die diese Liste
	   nicht zeigt, hat keine Zelle — ihre Spur misst dann null.
	   Die dreizehnte Spur trägt keine Zelle: sie ist der Rand, in den
	   die überzählige Breite läuft (siehe Kopfkommentar). */
	--dz-spuren:
		auto
		auto
		fit-content(12rem)
		[dz-titel] minmax(14rem, 64ch)
		fit-content(18rem)
		auto
		fit-content(10rem)
		fit-content(16rem)
		fit-content(18rem)
		auto
		auto
		auto
		[dz-rand] minmax(0, 1fr);
	/* Die Luft zwischen zwei Spalten steht an der Zelle, nicht als Lücke
	   im Raster: eine Lücke zählt auch dort, wo die Spur leer ist, und
	   zehn ausgeblendete Spalten summierten sich zu einem Loch. */
	--dz-luft: var(--raum-3);
	--dz-luft-eng: var(--raum-2);
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--luft);
	align-items: start;
}

/* Der Strom traegt den Container: schiebt sich das Panel ein, wird er
   schmaler, und die Zeilen geben Spalten ab. Laege der Container an
   `.dokumente`, merkte die Zeile davon nichts. */
.dokumente-strom {
	min-width: 0;
	container: dokumente / inline-size;
}

/* `.dz-meta` klammert alle Zellen ausser Titel, Zeichen und Knopf
   zusammen — im Spaltenraster ist es aber KEIN Kasten: `display:
   contents` löst es auf, und jede Zelle steht einzeln im Subgrid, in
   ihrer Spur. Der Wrapper existiert für den Blockmodus am Ende dieses
   Abschnitts: dort wird er zur Metazeile unter dem Titel, und nur als
   ein Kasten können die Angaben in EINEM Satz umbrechen. */
.dz-meta {
	display: contents;
}

/* Eine Spalte, die das Template nicht gewählt hat, steht auch nicht im
   Raster. */
.dokumente:not(.zeigt-typwort) .dz-typwort,
.dokumente:not(.zeigt-autor) .dz-autor,
.dokumente:not(.zeigt-jahr) .dz-jahr,
.dokumente:not(.zeigt-stufe) .dz-stufe,
.dokumente:not(.zeigt-thema) .dz-thema,
.dokumente:not(.zeigt-ort) .dz-ort,
.dokumente:not(.zeigt-formate) .dz-formate,
.dokumente:not(.zeigt-mass) .dz-mass {
	display: none;
}

/* ---- Das eine Raster --------------------------------------------------- */

[data-ansicht="tabelle"] .dokumente-strom {
	display: grid;
	grid-template-columns: var(--dz-spuren);
	align-content: start;
}

/* Alles, was im Strom steht — Gruppe, Kopfzeile, Liste, Gruppenkopf,
   Hinweis, «weitere anzeigen» —, nimmt die Breite der Spalten, aber
   NICHT den leeren Rand ganz rechts: `-2` ist die Linie davor. Damit
   enden Kopflinie, Zeilentrennlinie und die Fläche unter dem Zeiger
   dort, wo der Inhalt endet, statt als leere Linie über den halben
   Schirm zu laufen. */
[data-ansicht="tabelle"] .dokumente-strom > * {
	grid-column: 1 / -2;
}

/* Innerhalb einer Gruppe oder Liste ist der Rand schon abgezogen: ihr
   Subgrid führt nur die zwölf Spalten, `-1` ist dort dessen Ende. */
[data-ansicht="tabelle"] .ml-gruppe > *,
[data-ansicht="tabelle"] .dz-liste > * {
	grid-column: 1 / -1;
}

[data-ansicht="tabelle"] .ml-gruppe,
[data-ansicht="tabelle"] .dz-liste,
[data-ansicht="tabelle"] .dz-kopf,
[data-ansicht="tabelle"] .dz {
	display: grid;
	grid-template-columns: subgrid;
}

/* Ohne Subgrid bleibt die Seite lesbar: Kopf und Zeilen bekommen
   dieselben Spuren, nur eben jede für sich. Die Kanten stimmen dann
   nicht auf ein halbes Pixel — alles andere schon. (Chrome ab 117,
   Safari ab 16, Firefox ab 71 brauchen diesen Weg nicht.) */
@supports not (grid-template-columns: subgrid) {
	[data-ansicht="tabelle"] .dokumente-strom,
	[data-ansicht="tabelle"] .ml-gruppe,
	[data-ansicht="tabelle"] .dz-liste {
		display: block;
	}

	[data-ansicht="tabelle"] .dz-kopf,
	[data-ansicht="tabelle"] .dz {
		grid-template-columns: var(--dz-spuren);
	}
}

/* Jede Zelle steht in ihrer Spur, weil das Stylesheet sie dorthin setzt —
   nicht, weil sie an der richtigen Stelle im Markup steht. Sonst rutschte
   die halbe Zeile, sobald eine Spalte wegfällt. */
[data-ansicht="tabelle"] .dz-auf,
[data-ansicht="tabelle"] .dz-auf-leer          { grid-column: 1; }
[data-ansicht="tabelle"] .dz-typ               { grid-column: 2; }
[data-ansicht="tabelle"] .dz-typwort,
[data-ansicht="tabelle"] .dz-kopf [data-sort="typ"]    { grid-column: 3; }
[data-ansicht="tabelle"] .dz-haupt,
[data-ansicht="tabelle"] .dz-kopf [data-sort="titel"]  { grid-column: 4; }
[data-ansicht="tabelle"] .dz-autor,
[data-ansicht="tabelle"] .dz-kopf [data-sort="autor"]  { grid-column: 5; }
[data-ansicht="tabelle"] .dz-jahr,
[data-ansicht="tabelle"] .dz-kopf [data-sort="jahr"]   { grid-column: 6; }
[data-ansicht="tabelle"] .dz-stufe,
[data-ansicht="tabelle"] .dz-kopf [data-sort="stufe"]  { grid-column: 7; }
[data-ansicht="tabelle"] .dz-thema,
[data-ansicht="tabelle"] .dz-kopf [data-sort="thema"]  { grid-column: 8; }
[data-ansicht="tabelle"] .dz-ort,
[data-ansicht="tabelle"] .dz-kopf [data-sort="ort"]    { grid-column: 9; }
[data-ansicht="tabelle"] .dz-formate,
[data-ansicht="tabelle"] .dz-kopf [data-sort="format"] { grid-column: 10; }
[data-ansicht="tabelle"] .dz-mass,
[data-ansicht="tabelle"] .dz-kopf [data-sort="mass"]   { grid-column: 11; }
[data-ansicht="tabelle"] .dz-datum,
[data-ansicht="tabelle"] .dz-kopf [data-sort="datum"]  { grid-column: 12; }

/* Und jede in derselben Zeile. Ohne diese Angabe entscheidet die
   automatische Platzierung, und die geht der Reihe nach durch das
   Markup: steht der Titel (Spur 4) vor dem Typwort (Spur 3), ist der
   Zeiger beim Typwort schon an Spur 4 vorbei, und das Typwort rutscht in
   eine zweite Rasterzeile — 18 px unter der Grundlinie des Titels und
   damit unter die Zeile selbst. Genau das trat ein, als die Angaben in
   `.dz-meta` hinter den Titel wanderten. Die Spur setzt das Stylesheet;
   die Zeile setzt es jetzt auch. */
[data-ansicht="tabelle"] .dz-auf,
[data-ansicht="tabelle"] .dz-auf-leer,
[data-ansicht="tabelle"] .dz-typ,
[data-ansicht="tabelle"] .dz-typwort,
[data-ansicht="tabelle"] .dz-haupt,
[data-ansicht="tabelle"] .dz-autor,
[data-ansicht="tabelle"] .dz-jahr,
[data-ansicht="tabelle"] .dz-stufe,
[data-ansicht="tabelle"] .dz-thema,
[data-ansicht="tabelle"] .dz-ort,
[data-ansicht="tabelle"] .dz-formate,
[data-ansicht="tabelle"] .dz-mass,
[data-ansicht="tabelle"] .dz-datum {
	grid-row: 1;
}

/* Die Luft je Zelle: linksbündige Spalten schieben nach rechts,
   rechtsbündige nach links. Die letzte Spalte hat darum keinen
   Nachlauf, die erste keinen Vorlauf. */
[data-ansicht="tabelle"] .dz-auf,
[data-ansicht="tabelle"] .dz-auf-leer,
[data-ansicht="tabelle"] .dz-typ {
	margin-inline-end: var(--dz-luft-eng);
}

[data-ansicht="tabelle"] .dz-typwort,
[data-ansicht="tabelle"] .dz-haupt,
[data-ansicht="tabelle"] .dz-autor,
[data-ansicht="tabelle"] .dz-jahr,
[data-ansicht="tabelle"] .dz-stufe,
[data-ansicht="tabelle"] .dz-thema,
[data-ansicht="tabelle"] .dz-ort,
[data-ansicht="tabelle"] .dz-kopf [data-sort="typ"],
[data-ansicht="tabelle"] .dz-kopf [data-sort="titel"],
[data-ansicht="tabelle"] .dz-kopf [data-sort="autor"],
[data-ansicht="tabelle"] .dz-kopf [data-sort="jahr"],
[data-ansicht="tabelle"] .dz-kopf [data-sort="stufe"],
[data-ansicht="tabelle"] .dz-kopf [data-sort="thema"],
[data-ansicht="tabelle"] .dz-kopf [data-sort="ort"] {
	margin-inline-end: var(--dz-luft);
}

[data-ansicht="tabelle"] .dz-formate,
[data-ansicht="tabelle"] .dz-mass,
[data-ansicht="tabelle"] .dz-datum,
[data-ansicht="tabelle"] .dz-kopf [data-sort="format"],
[data-ansicht="tabelle"] .dz-kopf [data-sort="mass"],
[data-ansicht="tabelle"] .dz-kopf [data-sort="datum"] {
	margin-inline-start: var(--dz-luft);
}

/* KEIN `content-visibility: auto` auf den Zeilen — gemessen und
   verworfen (14.09.2026, ~/Code/LEISTUNG.md). `content-visibility: auto`
   bringt Grössen-Containment mit, und ein Subgrid, das ein eigenes
   Formatierungsumfeld aufmachen muss, ist keines mehr: es fällt auf ein
   eigenes Raster zurück. Auf `/bibliothek` (562 Zeilen) sprangen die
   Spaltenkanten damit von 0.00 px auf 339.66 px (Chromium) und
   323.58 px (WebKit) — die Abnahme in DESIGN §7 verlangt 0.5.
   Dazu kommt, dass der Gewinn nur in einer Engine anfällt: Layoutzeit
   23.6 → 4.8 ms in Chromium, 78 → 75 ms in WebKit. Auf iOS ist jeder
   Browser WebKit; dort wäre es reine Kante ohne Nutzen. Wer die 562
   Zeilen billiger machen will, muss an ihre Zahl (Seitenschaltung,
   «weitere anzeigen»), nicht an ihr Containment.
   -------------------------------------------------------------------- */

/* ---- Eine Grundlinie, keine Mittellinie -------------------------------
   Die Textzellen einer Zeile sitzen auf EINER Grundlinie. Zentriert
   sassen sie es nicht: Typwort, Autor, Grösse und Datum stehen in
   12.5 px, der Titel in 14 px, und zwei verschieden grosse Schriften
   haben zentriert verschiedene Grundlinien — gemessen 1.61 px
   Unterschied, über vierzig Zeilen ein Flimmern, das man sieht, ohne es
   benennen zu können.

   `align-items: baseline` an der Zeile richtet alle Textspuren
   aneinander aus. Die Spuren mit Zeichen und Knopf nehmen sich aus:
   ein Symbol hat keine Grundlinie, es hat eine Mitte. `align-content`
   bleibt `center`, damit die Zeile ihre 40 px behält und der Textblock
   darin mittig steht. (docs/DESIGN.md §5.3)
   ---------------------------------------------------------------------- */

[data-ansicht="tabelle"] .dokumente-strom .dz {
	align-items: baseline;
}

/* Der Titel steht in `.dz-haupt`. Als Raster mit `align-content: center`
   leitet der Browser dessen Grundlinie aus der Lage der Spur ab und
   nicht aus der Textzeile — gemessen 0.62 px daneben, der letzte Rest
   des Versatzes. In der Tabelle steht in `.dz-haupt` ohnehin nur der
   Titel (der Kontextsatz gehört dort in die Klappe), und die Grundlinie
   eines Blockkastens IST die seiner ersten Zeile. */
[data-ansicht="tabelle"] .dokumente-strom .dz-haupt {
	display: block;
}

[data-ansicht="tabelle"] .dz-auf,
[data-ansicht="tabelle"] .dz-auf-leer,
[data-ansicht="tabelle"] .dz-typ {
	align-self: center;
}

/* Die Formatmarken sind Text, kein Symbol: ihre Grundlinie ist die der
   Zeile. `.dz-formate` ist ein Flexkasten — seine Grundlinie kommt von
   der ersten Marke darin, und die Marken stehen untereinander ebenfalls
   auf einer. */
[data-ansicht="tabelle"] .dz-formate {
	align-self: baseline;
	align-items: baseline;
}

/* Der waagrechte Einzug gehört der Liste, nicht der Zeile: ein Polster
   am Subgrid rechnet sich aus der ersten und der letzten Spur heraus,
   und die Zeile stünde um dieses Mass neben ihrer Kopfzeile. Gemeldet
   und hier zurückgenommen: `looks/karte.css` gibt der Zeile
   `padding-inline: var(--raum-2)`, `looks/labor.css` ein `padding-left`
   mit ausgleichendem negativem Rand. Im Spaltenraster braucht es
   beides nicht — die Fläche der Liste trägt den Einzug schon. */
[data-ansicht="tabelle"] .dokumente-strom .dz {
	padding-inline: 0;
	margin-inline: 0;
}

.dz-kopf {
	padding: 0 0 var(--raum-2);
	border-bottom: 1px solid var(--border);
	font-size: var(--t--2);
	color: var(--text-faint);
}

/* Eine Beschriftung bricht nie um: sie ist kürzer als jede Angabe
   darunter, und ein Umbruch im Kopf macht aus der Tabelle eine Treppe. */
.dz-kopf button {
	white-space: nowrap;
}

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

.dz {
	display: grid;
	align-items: center;
	align-content: center;
	min-height: var(--dz-zeile);
	padding: 9px 0;
	border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
	font-size: var(--t--1);
	line-height: 1.35;
	scroll-margin: var(--raum-6);
}

/* In der Tabelle ist jede Zeile einzeilig und gleich hoch: die Höhe
   macht `--dz-zeile`, nicht der Inhalt. Was länger ist als seine Spalte,
   wird gekürzt; was gar nicht in die Zeile passt (der Kontextsatz),
   steht in der Klappe. */
[data-ansicht="tabelle"] .dokumente-strom .dz {
	padding-block: 0;
}

/* Die ganze Zeile ist anklickbar, und der Zeiger sagt es. Ein Klick auf
   den Titel lädt die Datei, ein Klick daneben öffnet die Vorschau
   (dokumentliste.js) — zwei Handlungen in einer Zeile, von denen die
   zweite bisher unsichtbar war. Kein `title`-Hinweis dazu: 562 Zeilen
   mit demselben Tooltip sind Rauschen, und im Kopf des Panels steht
   «Öffnen» ohnehin. Nur Listen, die das Skript wirklich bindet, bekommen
   den Zeiger — ohne JavaScript tut der Klick daneben nichts. */
[data-dokumentliste] .dz {
	cursor: pointer;
}

/* Hover ist eine Fläche über die ganze Zeile, ohne Radius. */
.dz:hover,
.dz:focus-visible,
.dz.ist-gewaehlt {
	background: var(--hover, var(--surface-2));
	outline: none;
}

/* Kernmaterial ist dieselbe Zeile, nur mit halbfettem Titel — kein
   eigener Behälter und, in der Tabelle, auch keine eigene Höhe: eine
   Liste mit zwei Zeilenhöhen liest sich wie zwei Listen. */
.dz-kern {
	min-height: 44px;
	padding-block: 11px;
}

[data-ansicht="tabelle"] .dokumente-strom .dz-kern {
	min-height: var(--dz-zeile);
	padding-block: 0;
}

.dz-kern .dz-titel {
	font-weight: 600;
}

.dz-typ {
	display: inline-grid;
	place-items: center;
	align-self: center;
	color: var(--text-faint);
}

.dz-icon {
	width: 15px;
	height: 15px;
}

/* Die feinen Angaben: kurz, einzeilig, und nie breiter als ihr Deckel.
   `overflow: hidden` ist dabei nicht nur Kosmetik — erst dadurch greift
   `fit-content()` an der Spur: ohne es wäre die kleinste Grösse einer
   nicht umbrechenden Zelle ihre volle Länge, und der Deckel bliebe
   wirkungslos. */
.dz-typwort,
.dz-autor,
.dz-jahr,
.dz-stufe,
.dz-thema,
.dz-ort {
	font-size: var(--t--2);
	color: var(--text-muted);
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.dz-haupt {
	min-width: 0;
	display: grid;
	gap: 1px;
	align-content: center;
}

/* Der Titel bricht an der Silbe, nie mitten im Wort. «Honorarformul /
   ar Praktika» ist kein Umbruch, sondern ein Fehler. */
.dz-titel {
	color: var(--text);
	font-weight: 500;
	text-decoration: none;
	hyphens: auto;
	overflow-wrap: normal;
	word-break: normal;
}

/* In der Tabelle bleibt die Zeile einzeilig: der Titel wird gekürzt,
   vollständig steht er im `title` und im Vorschaupanel. Die Ansichten
   «Liste» und «Raster» zeigen ihn ungekürzt. */
[data-ansicht="tabelle"] .dz-titel {
	display: block;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Der Kontextsatz steht in der Tabelle in der Klappe, nicht in der
   Zeile (materialliste.css §4). Die Ersatzzeile für schmale Container
   (`.dz-unter-spalten`) bleibt davon unberührt — sie tritt an die
   Stelle der weggefallenen Spalten, nicht an die des Satzes. */
[data-ansicht="tabelle"] .dokumente-strom .dz-unter:not(.dz-unter-spalten) {
	display: none;
}

.dz:hover .dz-titel,
.dz.ist-gewaehlt .dz-titel {
	color: var(--link);
}

/* Der Kontextsatz wird nicht gekürzt, er bricht: höchstens zwei Zeilen,
   der vollständige Satz steht im title-Attribut. */
.dz-unter {
	font-size: var(--t--2);
	color: var(--text-muted);
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

/* Nur auf schmalen Fenstern — dort ersetzt sie die Spalten. */
.dz-unter-spalten {
	display: none;
	color: var(--text-faint);
}

.dz-unter-spalten:empty {
	display: none;
}

.dz-ort a {
	color: inherit;
	text-decoration: none;
}

.dz-ort a:hover {
	color: var(--link);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

.dz-formate {
	display: flex;
	gap: var(--raum-2);
	justify-content: flex-end;
	align-self: center;
}

.dz-mass {
	font-size: var(--t--2);
	color: var(--text-faint);
	white-space: nowrap;
	text-align: right;
}

/* Gruppenkopf im selben Strom: kein zugeklappter Behälter, nur eine
   Überschrift mit Zähler. */
/* Der Gruppenkopf klebt: wer weit unten in den «weiteren Unterlagen»
   steht, soll sehen, worin er gerade liest. */
.dz-gruppe {
	display: flex;
	align-items: baseline;
	gap: 8px;
	margin: 24px 0 4px;
	padding: 0 0 6px 10px;
	border-bottom: 1px solid var(--border);
	font-size: 13.5px;
	font-weight: 600;
	color: var(--text);
	letter-spacing: 0;
}

.dz-gruppe-erste {
	margin-top: 4px;
}

.dz-gruppe-zahl {
	font-size: 12.5px;
	font-weight: 400;
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
}

.dz-mehr {
	display: block;
	width: 100%;
	padding: var(--raum-3) 0;
	background: none;
	border: 0;
	border-bottom: 1px solid var(--border);
	color: var(--text-muted);
	font: inherit;
	font-size: var(--t--1);
	text-align: left;
	cursor: pointer;
}

.dz-mehr:hover {
	color: var(--link);
}

/* Die Tastenkürzel stehen an der Zeile, an der sie gelten. */
.dz-tasten {
	display: none;
	grid-column: 1 / -1;
	gap: var(--raum-3);
	padding-top: var(--raum-1);
	font-size: var(--t--2);
	color: var(--text-faint);
}

.dz:focus-visible .dz-tasten {
	display: flex;
}

.dz-tasten kbd {
	font-size: 10px;
}

/* --- Die Spalten fallen von rechts -------------------------------------
   Reicht der Platz nicht, wird nicht gequetscht, sondern weggelassen —
   in fester Reihenfolge, und für Kopfzeile und Zeilen gleichzeitig. Die
   Spur einer Spalte ohne Zellen misst null; es bleibt kein Loch zurück.
   ---------------------------------------------------------------------- */

@container dokumente (max-width: 980px) {
	.dz-jahr,
	.dz-stufe,
	.dz-thema,
	.dz-ort,
	.dz-kopf [data-sort="jahr"],
	.dz-kopf [data-sort="stufe"],
	.dz-kopf [data-sort="thema"],
	.dz-kopf [data-sort="ort"] {
		display: none;
	}
}

@container dokumente (max-width: 780px) {
	.dz-typwort,
	.dz-autor,
	.dz-mass,
	.dz-datum,
	.dz-kopf [data-sort="typ"],
	.dz-kopf [data-sort="autor"],
	.dz-kopf [data-sort="mass"],
	.dz-kopf [data-sort="datum"] {
		display: none;
	}

	.dz-unter-spalten {
		display: block;
	}
}

/* Auf dem Telefon ist die Zeile ein zweizeiliger Block: Zeichen und
   Titel oben, darunter EINE Metazeile mit allem, was in der Tabelle in
   Spalten stünde — «Skript · A. Bärtsch · 2025 · PDF · 1,2 MB». Der
   Titel behaelt die volle Breite und wird hier nicht gekuerzt — die
   Zeile darf umbrechen, weil sie ohnehin keine Tabelle mehr ist.

   Zwei Textbloecke, nicht fuenf: vorher standen Typwort, Ersatzzeile und
   Formatmarken je auf einer eigenen Zeile, und eine dreizeilige Zeile
   mit einem Wort pro Zeile ist keine Liste mehr, sondern eine Treppe.
   Die Angaben werden dafuer NICHT ein zweites Mal ausgegeben: dieselben
   Zellen stehen in `.dz-meta`, das oben im Abschnitt `display:
   contents` traegt und hier zum Kasten wird (dokumentzeile.php).

   Pfeil und Zeichen sitzen auf der ERSTEN Textzeile, nicht in der Mitte
   der ganzen Zeile: bricht der Titel um, wanderte der Pfeil sonst nach
   unten, das Zeichen blieb oben, und die beiden standen nebeneinander
   auf verschiedenen Hoehen. Beide bekommen darum `align-self: start`
   und die Hoehe der ersten Titelzeile (`--dz-erstzeile`), in der sie
   ihr Zeichen zentrieren. (docs/DESIGN.md §5.3)

   Die Schwelle liegt bei 480 px, nicht mehr bei 560: Knopf (18), Zeichen
   (24), Titel (14 rem = 224) und Formatmarken (~60) samt Luft brauchen
   360 px — bei 480 ist die einzeilige Zeile also noch eine Tabelle, und
   sie soll es bleiben. Der Unterschied ist nicht akademisch: mit
   offenem Vorschaupanel behaelt die Liste auf einem 1440-px-Schirm rund
   500 px, und bei 560 waere sie genau dort in den Blockmodus gefallen —
   ein Ansichtswechsel als Nebenwirkung des Oeffnens. (docs/DESIGN.md
   §5.3) */
@container dokumente (max-width: 480px) {
	/* Zweizeilige Zeilen haben keine Spalten mehr — dann hat auch die
	   Kopfzeile nichts zu beschriften. Oberhalb bleibt sie stehen: sie
	   misst im selben Raster mit und passt darum immer. */
	[data-ansicht="tabelle"] .dz-kopf {
		display: none;
	}

	[data-ansicht="tabelle"] .dz {
		/* Die erste Titelzeile: Pfeil und Zeichen sind so hoch wie sie
		   und zentrieren ihr Zeichen darin. Ein fester Pixelwert waere
		   im Look «lesesaal» (15 px Grundschrift) daneben. */
		--dz-erstzeile: calc(var(--t-0) * 1.35);
		grid-template-columns: 24px minmax(0, 1fr);
		grid-template-areas:
			"typ haupt"
			"typ meta";
		align-items: start;
		align-content: start;
		row-gap: 2px;
	}

	/* Polster und Mindesthoehe stehen mit dem Strom im Selektor, und das
	   ist kein Zierat: die Tabellenregel weiter oben
	   (`… .dokumente-strom .dz { padding-block: 0 }`) wiegt schwerer als
	   der blosse `.dz` und nahm dem Blockmodus sein Polster gleich wieder
	   weg — gemessen 0 px, wo hier 8 stehen sollten. Dasselbe galt fuer
	   `.dz-kern`, das dort seine eigene Zeilenhoehe bekommt.

	   Auf dem Telefon ist die Zeile selbst ein Ziel fuer den Finger (ein
	   Tipp daneben zeigt die Vorschau): 44 px, auch wenn Titel und
	   Angaben je einzeilig bleiben. Das Polster gehoert zum Titel — es
	   traegt seine Trefferflaeche (siehe `.dz-titel::after` unten). */
	[data-ansicht="tabelle"] .dokumente-strom .dz {
		min-height: 44px;
		padding-block: var(--raum-2);
	}

	/* `grid-area` setzt Zeile UND Spalte — ein `grid-column: auto`
	   daneben nahm die Spalte gleich wieder weg, und die Zelle wurde
	   automatisch plaziert. Fuer Zeichen und Titel ging das zufaellig
	   gut; die Formatmarken landeten in Spalte 1 unter dem Zeichen und
	   liefen aus ihrer 18-px-Spur heraus — 42 px links vom Titel, zu dem
	   sie gehoeren. Jetzt stehen sie ohnehin im Satz der Metazeile. */
	/* Das Zeichen spannt beide Zeilen und steht oben: so haengt es an
	   der ersten Titelzeile, egal wie viele Zeilen Titel und Angaben
	   brauchen. Den Pfeil setzt materialliste.css §7 auf dasselbe Mass. */
	[data-ansicht="tabelle"] .dz-typ {
		grid-area: typ;
		align-self: start;
		height: var(--dz-erstzeile);
	}

	[data-ansicht="tabelle"] .dz-haupt { grid-area: haupt; }

	/* ---- Die Metazeile ------------------------------------------------
	   Ein Satz, kein Raster: «Skript · A. Bärtsch · 2025 · PDF · 1,2 MB»,
	   und wird er zu lang, bricht er um — zwischen zwei Angaben, nicht
	   mitten in einer. Darum ein Flexkasten mit Umbruch statt reinem
	   Fliesstext: «51 KB» soll nicht als «51» und «KB» auf zwei Zeilen
	   stehen. Die Zellen legen dafuer ihre Tabellenform ab (Deckel,
	   Ellipse, rechtsbuendig); sie richten sich an EINER Grundlinie aus
	   wie in der Tabelle (docs/DESIGN.md §5.3).

	   Was die Liste als Spalte nicht zeigt (`.zeigt-…`), steht hier
	   trotzdem: im Blockmodus gibt es keine Spalten, die leer blieben —
	   die frueher gezeigte Ersatzzeile machte es genauso.
	   -------------------------------------------------------------------- */

	[data-ansicht="tabelle"] .dz-meta {
		grid-area: meta;
		display: flex;
		flex-wrap: wrap;
		align-items: baseline;
		column-gap: 0.4em;
		row-gap: 0;
		min-width: 0;
		font-size: var(--t--2);
		line-height: 1.35;
		color: var(--text-muted);
	}

	/* Bleibt nichts zu sagen, steht auch keine Zeile da — sonst kostete
	   der Zeilenabstand Hoehe fuer einen leeren Kasten. */
	[data-ansicht="tabelle"] .dz-meta:not(:has(> .dz-meta-teil)) {
		display: none;
	}

	/* `display` steht hier, weil die Spaltenabfragen weiter oben dieselben
	   Zellen fallen lassen (780 px: Typwort, Autor, Grösse; 980 px:
	   Jahr). Im Blockmodus gibt es keine Spalte, die sie fallen liesse —
	   sie stehen im Satz. */
	[data-ansicht="tabelle"] .dz-meta > .dz-typwort,
	[data-ansicht="tabelle"] .dz-meta > .dz-autor,
	[data-ansicht="tabelle"] .dz-meta > .dz-jahr,
	[data-ansicht="tabelle"] .dz-meta > .dz-mass {
		display: block;
		overflow: visible;
		text-align: inherit;
		margin-inline: 0;
		font-size: inherit;
		color: inherit;
	}

	/* Typwort und Autor duerfen in sich umbrechen, wenn sie allein schon
	   breiter sind als die Spalte; Jahr und Groesse nie — «51 KB» ist
	   EINE Angabe. (Die Grundregel setzt `nowrap`, hier wird sie fuer die
	   beiden langen Angaben zurueckgenommen.) */
	[data-ansicht="tabelle"] .dz-meta > .dz-typwort,
	[data-ansicht="tabelle"] .dz-meta > .dz-autor {
		white-space: normal;
	}

	/* Nichts steht in der Metazeile, was leer waere: eine leere Zelle
	   traegt die Marke nicht und bleibt ausgeblendet — sonst stuende ein
	   Mittelpunkt vor nichts. */
	[data-ansicht="tabelle"] .dz-meta > :not(.dz-meta-teil) {
		display: none;
	}

	/* Die Formatmarken behalten ihre Farbe und ihre Klasse — sie bleiben
	   der Download. Nur ihre feste Hoehe legen sie ab: im Satz gilt die
	   Grundlinie der Zeile, nicht die Mitte eines 20-px-Kaestchens. */
	[data-ansicht="tabelle"] .dz-meta > .dz-formate {
		display: flex;
		flex-wrap: wrap;
		justify-content: flex-start;
		align-self: baseline;
		margin-inline: 0;
		/* Ohne eigene Luecke: zwischen zwei Marken steht der Abstand von
		   `.mb-marke + .mb-marke`, und der Mittelpunkt dahinter bekommt
		   denselben Vorlauf wie jeder andere im Satz. Mit Luecke stuende
		   er 8 px weiter weg als vor der naechsten Angabe. */
		gap: 0;
	}

	[data-ansicht="tabelle"] .dz-meta .mb-marke {
		height: auto;
		line-height: inherit;
	}

	/* Der Mittelpunkt haengt HINTEN an der Angabe, nicht vorn an der
	   naechsten: bricht die Zeile, endet sie mit dem Trenner und beginnt
	   mit einem Wort. Welche Angabe die letzte ist, entscheidet das
	   Markup (`dz-meta-teil`) — leere Zellen stehen trotzdem darin, und
	   bei `.dz-formate` traegt `:empty` nicht, weil der Behaelter seine
	   Zeilenumbrueche als Textknoten fuehrt. */
	[data-ansicht="tabelle"] .dz-meta > .dz-meta-teil:has(~ .dz-meta-teil)::after {
		content: "·";
		margin-inline-start: 0.4em;
		color: var(--text-faint);
	}

	[data-ansicht="tabelle"] .dz-titel {
		position: relative;
		font-size: var(--t-0);
		white-space: normal;
		overflow: visible;
	}

	/* Der Titel ist auf dem Telefon ein Ziel fuer den Finger. Seine
	   Flaeche reicht ueber die ganze Titelspur — als Block tut sie das
	   ohnehin — und dazu ueber das Polster der Zeile bis an die
	   Metazeile heran. Weiter hinunter darf sie NICHT: dort liegen die
	   Formatmarken, und zwei Ziele uebereinander (Datei oeffnen gegen
	   Datei laden) sind schlimmer als ein kleines. 44 px erreichen in
	   einer zweizeiligen Zeile nur der Klappenpfeil, die Marken und die
	   Zeile selbst; fuer den Titel brauchte es 88 px Zeilenhoehe, und
	   dann waere die Liste eine Kachelreihe. */
	[data-ansicht="tabelle"] .dz-titel::after {
		content: "";
		position: absolute;
		inset: calc(-1 * var(--raum-2)) 0 -1px;
	}

	/* Die Ersatzzeile tritt an die Stelle weggefallener SPALTEN. Im
	   Blockmodus gibt es keine, und sie waere eine zweite Metazeile mit
	   denselben Woertern. */
	[data-ansicht="tabelle"] .dokumente-strom .dz-unter-spalten {
		display: none;
	}
}

/* --------------------------------------------------------------------------
   31. Kopf der Themenseite
   Drei Zeilenhöhen, mehr nicht: Titel mit Gefäss rechtsbündig, Lede,
   eine Angabenzeile. Alles, was der Kopf höher ist, fehlt der ersten
   Dokumentzeile.
   -------------------------------------------------------------------------- */

.themenkopf {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--raum-5);
	flex-wrap: wrap;
}

.themenkopf-titel {
	font-size: 2rem;
	line-height: 1.1;
	margin: 0;
	min-width: 0;
}

/* Titel und Untertitel sind EIN Block im Flex des Kopfes: nebeneinander
   gesetzt riss `space-between` sie auseinander, und der Untertitel stand
   rechts, wo «n Teilnehmende» und der Stift stehen. */
.themenkopf-titelblock {
	min-width: 0;
}

/* Der Untertitel des Kurses («Experimentierkurs»): eine zweite Zeile
   unter dem Titel, nicht daneben. Er gehört zum Titel und hält darum
   nur --raum-1 Abstand — mehr, und er läse sich als Lede. Keine
   Versalien, keine Pille (docs/DESIGN.md §6). */
.themenkopf-untertitel {
	margin: var(--raum-1) 0 0;
	font-size: var(--t-2);
	font-weight: 400;
	line-height: var(--zeile-eng);
	color: var(--text-muted);
}

/* Das Gefäss gehört zur Identität des Themas und füllt genau den Platz,
   den die «Zuletzt geändert»-Kiste verschwendet hat. */
.themenkopf-gefaess {
	flex: none;
	margin: 0;
	font-size: var(--t--1);
	color: var(--text-muted);
}

.themenkopf .lead,
.titelband-innen > .lead {
	margin-top: var(--raum-1);
}

.themenkopf-angaben {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--raum-3) var(--raum-5);
	flex-wrap: wrap;
	margin-top: var(--raum-2);
	font-size: var(--t--2);
	color: var(--text-muted);
	line-height: 1.4;
}

.angabe {
	display: flex;
	align-items: baseline;
	gap: var(--raum-3);
	min-width: 0;
}

.angabe-label {
	flex: none;
	color: var(--text-faint);
}

.angabe-wert {
	min-width: 0;
}

.angabe-rechts {
	margin-left: auto;
}

/* --------------------------------------------------------------------------
   32. Bereichsfilter
   Eine Zeile über der Liste: Typen als Textknöpfe mit Unterstrich als
   Zustand, überzählige hinter «+ Filter», rechts die Bereichssuche.
   Keine Pillen — sie versprechen eine Fläche, die es nicht gibt.

   Die Zeile ist so breit wie die Liste, nicht wie der Inhalt (Befund
   B93). Erreicht wird das nicht mit einer Breitenangabe, sondern mit dem
   Ort: die Leiste steht als erste Zeile IM Raster des Stroms und spannt
   dort — wie Kopf und Liste — von der ersten Spur bis `-2`, also bis vor
   den leeren Rand (Abschnitt 30). Damit endet sie auf dasselbe Pixel wie
   die Liste, in jeder Ansicht, in jedem Look und auch dann, wenn das
   Vorschaupanel der Liste Platz wegnimmt.

   Ein Rechenweg über die Breite gäbe es nicht: der Strom ist der
   Abfragebehälter (`container-type: inline-size`), seine Breite kommt
   also von aussen und nie vom Inhalt — weder er noch ein Vorfahr kann
   sich an den Spalten messen (Abschnitt 30).

   `contain: inline-size` an der Leiste kehrt die Richtung um: sie nimmt
   die Breite der Spuren an, aber sie misst sie nicht mit. Ohne das
   könnte eine lange Typreihe die Spalten der Tabelle auseinanderziehen —
   die Leiste soll der Liste folgen, nicht sie führen.
   -------------------------------------------------------------------------- */

.dokumente-strom > .bereichsfilter,
.dokumente-strom > .filterleiste {
	contain: inline-size;
}

.bereichsfilter {
	display: flex;
	align-items: center;
	gap: var(--raum-2) var(--raum-3);
	min-height: 40px;
	margin-bottom: var(--raum-3);
	padding-bottom: var(--raum-2);
	border-bottom: 1px solid var(--border);
	flex-wrap: wrap;
}

/* Mit Skript ist die Leiste EINE Zeile — in jeder Breite und auch neben
   dem offenen Vorschaupanel. Was nicht passt, klappt zum Knopf «Typ»
   zusammen, statt in eine zweite Zeile zu rutschen. */
.bereichsfilter[data-bf-mass] {
	flex-wrap: nowrap;
}

/* Ohne JavaScript brechen die Reiter um — sie scrollen nicht in sich,
   und weggelassen werden sie auch nicht: ohne Skript gibt es das
   Dropdown nicht, das sie ersetzen könnte.

   Mit Skript ist die Leiste eindimensional. `data-bf-mass` setzt
   dokumentliste.js, sobald es den Balken misst: die Reiter stehen dann
   in EINER Zeile, und passen sie nicht neben den Ansichtswechsel,
   klappen sie zum Knopf «Typ» zusammen. Der Beschnitt ist die
   Rückversicherung für den einen Bildaufbau zwischen Messung und
   Umschalten; das Popover steht nicht mehr darin, sondern daneben
   (`.bf-menu`) — es kann darum nicht weggeschnitten werden. */
.bf-typen {
	display: flex;
	align-items: center;
	gap: var(--raum-1);
	min-width: 0;
	flex: 0 1 auto;
	flex-wrap: wrap;
}

.bereichsfilter[data-bf-mass] .bf-typen {
	flex-wrap: nowrap;
	overflow: hidden;
}

/* 32 px hoch wie der Ansichtswechsel daneben: beide Leisten stehen
   `align-items: center` in derselben Zeile, und nur bei gleicher
   Kastenhöhe liegen auch ihre Unterstriche auf einer Linie. 32 ist
   dabei das Mass der Trefferfläche, nicht des Textes. */
.bf-knopf {
	display: inline-flex;
	align-items: baseline;
	gap: 0.35em;
	height: 32px;
	padding: 0 var(--raum-2);
	background: none;
	border: 0;
	color: var(--text-muted);
	font: inherit;
	font-size: var(--t--1);
	cursor: pointer;
	white-space: nowrap;
}

.bf-knopf:hover {
	color: var(--text);
	box-shadow: inset 0 -1px 0 0 var(--text-faint);
}

.bf-knopf.ist-aktiv {
	color: var(--accent-text);
	box-shadow: inset 0 -2px 0 0 var(--accent);
}

.bf-zahl {
	font-size: var(--t--2);
	color: var(--text-faint);
}

.bf-knopf.ist-aktiv .bf-zahl {
	color: inherit;
}

/* Der zusammengeklappte Zustand der Typleiste: EIN Knopf «Typ · Alle»
   bzw. «Typ · Skript, Vorlage». Er steht als einziger in der Zeile —
   ein Rahmen wie bei den Facetten der Bibliothek wäre hier die einzige
   Kante im Feld. Er bleibt darum ein Textknopf und trägt dieselbe Marke
   wie ein Reiter: Unterstrich statt Fläche. */
.bf-menu {
	min-width: 0;
	flex: 0 1 auto;
}

.bf-menu .facette-knopf {
	max-width: 100%;
	height: 32px;
	padding: 0 var(--raum-2);
	border: 0;
	border-radius: 0;
	background: none;
}

/* Weder Fläche noch Radius — auch nicht beim Zeigen und nicht im
   offenen Zustand: das Idiom dieser Zeile ist der Unterstrich
   (docs/DESIGN.md §5.3). Die Facettenknöpfe der Bibliothek bringen
   beides mit; hier stünde es als einziges Feld in einer Reihe von
   Textknöpfen. */
.bf-menu .facette-knopf:hover,
.bf-menu[open] > .facette-knopf {
	background: none;
	color: var(--text);
	box-shadow: inset 0 -1px 0 0 var(--text-faint);
}

.bf-menu .facette-knopf.ist-aktiv {
	color: var(--accent-text);
	box-shadow: inset 0 -2px 0 0 var(--accent);
}

/* Solange nichts gewählt ist, steht dort «Typ · Alle» — eine Angabe,
   keine Wahl. Erst die Wahl bekommt die Akzentfarbe. */
.bf-menu .facette-knopf:not(.ist-aktiv) .facette-zahl {
	color: var(--text-muted);
}

/* Die Auswahl kann lang werden («Typ · Skript, Vorlage, Video»); sie
   kürzt sich, statt die Zeile zu sprengen. */
.bf-menu .facette-zahl {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.bf-menu .facette-wert > button {
	display: grid;
	grid-template-columns: 16px minmax(0, 1fr) auto;
	align-items: center;
	gap: var(--raum-2);
	width: 100%;
	min-height: 32px;
	padding: 0 var(--raum-2);
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text);
	font: inherit;
	font-size: var(--t--1);
	text-align: left;
	cursor: pointer;
}

.bf-menu .facette-wert > button:hover {
	background: var(--surface-2);
}

.bf-menu .facette-wert[aria-selected="true"] > button {
	color: var(--accent-text);
}

.bf-menu .facette-wert[aria-selected="true"] .facette-haken {
	opacity: 1;
}

/* Ansicht und Bereichssuche stehen zusammen rechts; die Typleiste
   nimmt den Platz links. (Nur hier — Form und Mass von `.ansicht`
   stehen einmal, in Abschnitt 37.) */
.bereichsfilter .ansicht {
	margin-left: auto;
}

.bf-suche {
	position: relative;
	display: flex;
	align-items: center;
	flex: 0 1 16rem;
	min-width: 2.25rem;
}

.bf-suche-icon {
	position: absolute;
	left: 0.55rem;
	color: var(--text-faint);
	pointer-events: none;
}

.bf-suche input {
	width: 100%;
	height: 32px;
	padding-left: 1.9rem;
	border-color: transparent;
	background: none;
}

.bf-suche input:hover {
	border-color: var(--border);
}

.bf-suche input:focus {
	background: var(--bg);
}

@container dokumente (max-width: 560px) {
	.bf-suche {
		flex-basis: 100%;
		margin-left: 0;
	}
}

/* Auf schmalen Fenstern spannt das Popover ueber die ganze Leiste,
   statt rechts hinauszulaufen. */
@media (max-width: 700px) {
	.facette {
		position: static;
	}

	.filterleiste,
	.bereichsfilter {
		position: relative;
	}

	.facette-popover {
		left: 0;
		right: 0;
		max-width: none;
	}
}

/* --------------------------------------------------------------------------
   33. Schmale Fenster: der Kopf darf nicht die halbe Seite kosten
   Auf 400 px zaehlt jede Zeile. Ein 38-px-Titel nimmt drei Dokumente weg.

   Kleiner wird genau EIN Wert: `--titel-minus`. Er zieht beide
   Titelgrade um denselben Betrag herunter — h1 von 28 auf 24 px, der
   Auftakt der Startseite von 36 auf 32 (und ueber die 900-px-Regel
   ohnehin schon auf den normalen Titelgrad). Alles andere behaelt den
   Grad, den es auf dem Schirm hat; h2 bleibt bei 16, damit die
   Hierarchie h1:h2 auch hier 1.5 : 1 betraegt.
   -------------------------------------------------------------------------- */

@media (max-width: 560px) {
	:root {
		--titel-minus: var(--titel-ab);
	}

	.titelband h1,
	.themenkopf-titel {
		line-height: 1.15;
	}

	.titelband {
		padding-block: var(--raum-3) 0;
	}

	.lead {
		font-size: var(--t-0);
		margin-top: var(--raum-2);
	}

	.themenkopf-angaben {
		gap: var(--raum-1) var(--raum-3);
	}

	/* Die Angabe «Geändert am …» ist auf dem Telefon die unwichtigste
	   Zeile der Seite. */
	.angabe-rechts {
		display: none;
	}

	.filterzeile,
	.bereichsfilter {
		min-height: 0;
	}
}

/* Auf dem Telefon wird aus der Filterzeile ein Block: Suchfeld über den
   Facetten. Waagrechtes Scrollen wäre kürzer, verlöre aber die Popover
   der Facetten — ein Überlauf-Beschnitt schneidet sie weg (Filterzeile
   und Typleiste haben denselben Aufbau). */
@media (max-width: 560px) {
	.filterzeile {
		flex-wrap: wrap;
		gap: var(--raum-2);
	}

	.fz-suche {
		flex: 1 1 9rem;
		min-width: 8rem;
	}

	.fz-facetten {
		flex-wrap: wrap;
		flex: 1 1 100%;
		min-width: 0;
	}

	/* Nur der Rückfall ohne Skript: dort brechen die Reiter unter die
	   Zeile. Mit Skript gibt es hier ein Dropdown, und die Leiste bleibt
	   einzeilig. */
	.bereichsfilter:not([data-bf-mass]) .bf-typen {
		flex-wrap: wrap;
		flex: 1 1 100%;
		min-width: 0;
	}

	.bf-suche {
		flex: 0 0 2.25rem;
		min-width: 2.25rem;
	}

	.bf-suche input {
		padding-left: 1.9rem;
	}

	/* Trefferzahl und Sortierung wandern unter die Zeile. */
	.fz-ergebnis {
		display: none;
	}
}

/* --------------------------------------------------------------------------
   34. Vorschau-Panel
   Prüfen vor dem Laden — der einzige Grund, rechts Platz zu belegen.
   Eingeschoben, solange die Liste genug behält; darunter legt es sich
   von rechts über sie. Kein Kasten: eine Kante zur Liste genügt.

   Die Breite ist ein Anteil der INHALTSSPALTE, nicht des Fensters: das
   Prozent in `grid-template-columns` rechnet gegen die Breite von
   `.dokumente`, und das ist genau die Inhaltsspalte. (Container-Einheiten
   wären hier falsch: `cqw` löst gegen den nächsten Behälter der
   VORFAHREN auf — für `.dokumente` also gegen etwas ausserhalb.)

   Wichtiger als die Zahl ist, was daraus folgt: Die Liste weicht dem
   Panel aus, statt sich von ihm zudecken zu lassen. Sie wird schmaler,
   und weil der Strom der Abfragebehälter ist (Abschnitt 30), fallen
   ihre Spalten von rechts weg — Titel und Format bleiben stehen. Erst
   wenn auch das nicht mehr reicht, legt sich das Panel darüber; die
   Grenze zieht `assets/js/dokumentliste.js` an der gemessenen Fläche.
   -------------------------------------------------------------------------- */

.dokumente {
	/* 35 bis 45 % der Inhaltsbreite, mindestens 400 px (docs/DESIGN.md
	   §5.3). Der Deckel bei 640 px: darüber wird die Vorschau nicht
	   besser, die Liste aber schlechter. */
	--dp-breite: clamp(400px, 40%, 640px);
}

.dokumente.hat-panel {
	grid-template-columns: minmax(0, 1fr) var(--dp-breite);
}

.dokupanel {
	position: sticky;
	top: 0;
	align-self: start;
	max-height: 100vh;
	overflow-y: auto;
	overscroll-behavior: contain;
	display: grid;
	grid-template-rows: auto auto auto auto;
	align-content: start;
	gap: var(--raum-3);
	padding: var(--raum-4) 0 var(--raum-5) var(--raum-5);
	border-left: 1px solid var(--border);
	min-width: 0;
}

/* Reicht der Platz nicht, überlagert das Panel die Liste, statt ihr die
   Titel abzuschneiden. Hier steht eine feste Breite und kein Prozent:
   das Panel ist dann aus dem Raster genommen (`position: fixed`), ein
   Prozent rechnete gegen das Fenster und nicht mehr gegen die Liste. */
.dokumente.hat-panel-ueber .dokupanel {
	position: fixed;
	inset: 0 0 0 auto;
	z-index: 45;
	width: min(520px, 92vw);
	max-height: none;
	padding: var(--raum-4);
	background: var(--surface);
	border-left: 1px solid var(--border);
	box-shadow: -16px 0 40px -24px rgba(0, 0, 0, 0.5);
}

.dp-kopf {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--raum-3);
}

.dp-titel {
	margin: 0;
	font-weight: 600;
	line-height: 1.3;
	min-width: 0;
	overflow-wrap: anywhere;
}

.dp-schliessen {
	flex: none;
	display: grid;
	place-items: center;
	width: 28px;
	height: 28px;
	padding: 0;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text-muted);
	cursor: pointer;
}

.dp-schliessen:hover {
	background: var(--surface-2);
	color: var(--text);
}

/* Die Bühne zeigt erst die Miniatur, dann das Dokument selbst. */
.dp-buehne {
	display: grid;
	place-items: center;
	min-height: 220px;
	background: var(--bg);
	overflow: hidden;
}

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

.dp-buehne iframe {
	display: block;
	width: 100%;
	height: min(58vh, 620px);
	border: 0;
	background: var(--bg);
}

.dp-buehne .dp-zeichen {
	width: 40px;
	height: 40px;
	color: var(--text-faint);
}

.dp-leer {
	margin: 0;
	padding: var(--raum-5);
	font-size: var(--t--1);
	color: var(--text-faint);
	text-align: center;
}

.dp-angaben {
	margin: 0;
	font-size: var(--t--2);
	color: var(--text-muted);
	line-height: 1.5;
}

.dp-angaben:empty {
	display: none;
}

/* `baseline`, damit der leise Zweitlink auf der Schrift des Knopfes
   sitzt und nicht auf dessen Kasten. */
.dp-aktionen {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--raum-2) var(--raum-4);
}

.dp-aktionen:empty {
	display: none;
}

/* Das zweite Format eines Paares ist kein zweiter Knopf, sondern ein
   Satz daneben: «auch als DOCX». Ein Dokument hat eine Hauptsache und
   eine Nebensache — zwei gleich grosse «Öffnen» sagen nicht, welches
   von beiden gemeint ist (docs/DESIGN.md §5.3, §6). */
.dp-auch {
	font-size: var(--t--2);
	color: var(--text-muted);
	text-decoration: none;
	white-space: nowrap;
}

.dp-auch:hover {
	color: var(--link);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

/* Auf dem Telefon ist die Vorschau eine Vollbildlage. */
@media (max-width: 700px) {
	.dokumente.hat-panel,
	.dokumente.hat-panel-ueber {
		grid-template-columns: minmax(0, 1fr);
	}

	.dokumente.hat-panel .dokupanel,
	.dokumente.hat-panel-ueber .dokupanel {
		position: fixed;
		inset: 0;
		z-index: 45;
		width: auto;
		padding: var(--raum-4);
		background: var(--surface);
		overflow-y: auto;
	}
}

/* Die eingeklappte Schiene sagt, wie man wieder hineinkommt. */
.schiene-suche {
	display: grid;
	place-items: center;
	gap: 2px;
	width: 36px;
	padding: var(--raum-2) 0;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--text-muted);
	cursor: pointer;
}

.schiene-suche:hover {
	background: var(--surface-2);
	color: var(--text);
}

.schiene-kbd {
	font-family: var(--mono);
	font-size: 9px;
	line-height: 1;
	color: var(--text-faint);
}

/* --------------------------------------------------------------------------
   35. Startseite
   Zwei Fragen, sonst keine: wo finde ich Material zu meinem Thema, und
   was hat sich getan. Kein Raster von Bereichskacheln — das wäre die
   Seitenleiste ein zweites Mal.
   -------------------------------------------------------------------------- */

.start-suche {
	position: relative;
	display: flex;
	align-items: center;
	/* Die Breite hängt an der Spalte, nicht an einer festen Zahl: 640 px
	   waren bei 1440 px zwei Drittel der Spalte, bei 2560 px noch 31 %
	   (Befund B50). `ch` misst in der Schrift des Feldes — darum steht
	   sie hier am Formular und nicht erst am <input>. */
	font-size: var(--t-1);
	max-width: clamp(28rem, 60%, 52rem); /* wächst mit der Spalte, gedeckelt */
	/* Der Abstand zum ersten Abschnitt ist der Abschnittsabstand und
	   kein eigener: 48 px waren der einzige Wert auf der Seite, der aus
	   §2 ausscherte (Befund B81). */
	margin-bottom: var(--raum-6);
}

.start-suche-icon {
	position: absolute;
	left: 0.9rem;
	width: 18px;
	height: 18px;
	color: var(--text-faint);
	pointer-events: none;
}

.start-suche input {
	width: 100%;
	height: 52px;
	padding-left: 2.8rem;
	padding-right: 4rem;
	font-size: var(--t-1);
}

.start-kbd {
	position: absolute;
	right: 0.9rem;
	font-family: var(--mono);
	font-size: var(--t--2);
	color: var(--text-faint);
	pointer-events: none;
}

/* Was heute gilt — höchstens vier Zeilen, immer sichtbar. */
.jetzt-liste,
.einstiege-liste {
	list-style: none;
	margin: 0;
	padding: 0;
}

.jetzt-zeile {
	display: flex;
	align-items: baseline;
	gap: var(--raum-3);
	flex-wrap: wrap;
	padding: var(--raum-2) 0;
	border-bottom: 1px solid var(--border);
}

.jetzt-marke {
	flex: none;
	width: 9rem;
	font-size: var(--t--2);
	color: var(--text-faint);
}

.jetzt-neben {
	margin-left: auto;
	font-size: var(--t--2);
	color: var(--text-muted);
}

/* Das Themenraster: alle Themen mit ihrer Dokumentzahl, gruppiert nach
   Fachgebiet. Eine Zeile je Thema, keine Kachel. */
/* Spaltensatz statt Zeilenraster: im Raster stand eine Gruppe mit zwei
   Einträgen neben einer mit fünf, und darunter klaffte bis zur nächsten
   Reihe ein Loch von 125 px (Befund B60). Im Spaltensatz folgt die
   nächste Gruppe unmittelbar; gelesen wird Spalte für Spalte, die
   Reihenfolge der Gebiete bleibt also lesbar. */
.tr-gebiete {
	column-width: 15rem;
	column-gap: var(--luft);
}

.tr-gebiet {
	min-width: 0;
	/* Eine Gruppe wird nicht über zwei Spalten zerrissen. */
	break-inside: avoid;
	margin: 0 0 var(--raum-4);
}

.tr-titel {
	margin: 0 0 var(--raum-2);
	font-size: var(--t--2);
	font-weight: 600;
	color: var(--text-faint);
	letter-spacing: 0;
}

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

.tr-liste li {
	display: flex;
	align-items: baseline;
	gap: var(--raum-2);
	min-height: 26px;
}

.tr-liste a {
	color: var(--text);
	text-decoration: none;
	font-size: var(--t--1);
	min-width: 0;
}

.tr-liste a:hover {
	color: var(--link);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

.tr-zahl {
	margin-left: auto;
	font-size: var(--t--2);
	color: var(--text-faint);
}

.einstiege-liste li {
	display: flex;
	align-items: baseline;
	gap: var(--raum-3);
	flex-wrap: wrap;
	padding: var(--raum-3) 0;
	border-bottom: 1px solid var(--border);
}

.einstiege-satz {
	font-size: var(--t--1);
	color: var(--text-muted);
	min-width: 0;
}

@media (max-width: 560px) {
	.start-suche input {
		height: 46px;
		font-size: var(--t-0);
	}

	.start-kbd {
		display: none;
	}

	.jetzt-marke {
		width: auto;
	}
}

/* ==========================================================================
   36. Der Look
   Aus der Variante «Katalog» ist die Gestaltung geworden: eine ruhige
   Fläche auf dem Grund, Symbole in der Leiste, grosszügige Zeilen. Die
   drei Richtungen sind aufgelöst — was sie unterschieden, war Dichte und
   Spaltensatz, und das entscheidet jetzt die Ansicht der Liste, nicht
   eine Grundsatzwahl beim ersten Besuch.

   Keine Metaphern, keine Illustrationen, keine gefüllten Farbflächen als
   Schmuck. Farbe zeigt Zustand, sonst nichts.
   ========================================================================== */



/* ---- Zwei Flächen, eine Linie dazwischen ------------------------------ */

.shell {
	background: var(--bg);
}

/* Die Leiste ist die zweite Fläche; die Linie dazwischen ist die einzige
   Trennung, die es braucht. */
.seitenleiste {
	background: var(--bg-sidebar);
	border-right: 1px solid var(--border);
	--leiste-polster: var(--raum-3);
	padding: var(--raum-5) var(--raum-3) 0;
}

.spalte {
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas:
		"sicht"
		"band"
		"neben"
		"haupt"
		"fuss";
	grid-template-rows: auto auto auto 1fr auto;
}

.titelband {
	padding-block: calc(var(--rand) * 0.32) 0;
}

.titelband h1 {
	letter-spacing: -0.015em;
}

.lead {
	max-width: 72ch;
}

/* Angaben als ruhige Zeile unter dem Titel. */
.nebenspalte {
	padding-block: var(--raum-4) 0;
	max-width: none;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--raum-3) var(--raum-5);
}

.aside-block,
.aside-block + .aside-block {
	margin: 0;
	padding: 0;
	border: 0;
	display: flex;
	align-items: center;
	gap: var(--raum-3);
}

.aside-block h2 {
	margin: 0;
	font-size: var(--t--2);
	color: var(--text-muted);
	white-space: nowrap;
}

/* Paare bleiben Paare: Label und Wert stehen nebeneinander, das
   nächste Paar beginnt eine Zeile tiefer. Als Flex-Liste zerriss es
   die Angaben («Stand» rechts vom Link, der Wert darunter). */
.datenliste {
	display: grid;
	grid-template-columns: max-content minmax(0, 1fr);
	gap: var(--raum-1) var(--raum-3);
	align-items: baseline;
}

.datenliste dt {
	grid-column: 1;
	color: var(--text-muted);
}

.datenliste dd {
	grid-column: 2;
	margin: 0;
}

.inhalt {
	padding-block: var(--raum-6) var(--raum-7);
}

/* Auf der Fläche liegende Felder brauchen einen ruhigeren Grund. */
.mb-detail,
.browser-panel,
.abgabe-kasten,
.anmeldung,
.meldung {
	background: var(--bg);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="url"],
input[type="number"],
textarea {
	background: var(--bg);
}

/* Auf der Fläche liegt keine zweite Fläche. Abschnitte trennt eine
   Linie, nicht ein Rahmen. */
.browser-panel,
.mb-detail {
	border-color: transparent;
}

/* ---- Leiste: Symbole und eine gefüllte Zeile für den Ort --------------- */

.nav-icon {
	display: inline-flex;
}

/* Die Tiefe muss lesbar sein: die Unterpunkte hängen an einer feinen
   Führungslinie, die bis unter den letzten Eintrag läuft. */
.nav-ebene-2,
.nav-ebene-3,
.nav-ebene-4 {
	margin-left: 1.1rem;
	padding-left: 0.7rem;
	border-left: 1px solid var(--border);
}

.nav-ebene-2 .nav-link,
.nav-ebene-3 .nav-link {
	font-weight: 400;
}

.nav-link {
	font-weight: 500;
	padding-inline: var(--raum-3);
}

.nav-zeile:hover {
	background: var(--surface);
}

/* Der aktive Ort: Akzent in der Schrift und eine Kante links. Die
   gefüllte Pille war das lauteste Element der Seite und sagte über
   Wichtigkeit nichts aus. */
.nav-zeile.ist-aktiv > .nav-link,
.nav-zeile.ist-aktiv .nav-icon {
	color: var(--accent-text);
}

/* Nur die Laufweite ist hier enger; der Grad steht einmal weiter oben
   und kommt aus der Skala (--t-3). */
.marke-haupt,
.marke-neben {
	letter-spacing: -0.03em;
}



.suche-knopf {
	background: var(--surface);
	border-color: transparent;
	height: 42px;
}

.suche-knopf:hover {
	background: var(--surface-2);
	border-color: transparent;
}

.suche-kbd {
	background: var(--bg);
	border-color: transparent;
}

/* ---- Materialliste: zweizeilig ----------------------------------------- */

.browser {
	--mb-zeile: 56px;
	--mb-typ: 34px;
	--mb-spalten: var(--mb-typ) minmax(0, 1fr) auto var(--mb-groesse) 18px;
}

/* Zweizeilig: Titel oben, Herkunft darunter — lesbar statt tabellarisch. */
.mb-zeile {
	grid-template-areas:
		"typ haupt formate groesse chevron"
		"typ meta  meta    meta    .";
	row-gap: 2px;
}

.mb-typ { grid-area: typ; align-self: center; }
.mb-haupt { grid-area: haupt; }
.mb-formate { grid-area: formate; }
.mb-groesse { grid-area: groesse; }
.mb-chevron { grid-area: chevron; }

.mb-kopf {
	display: none;
}

.mb-meta {
	grid-area: meta;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--raum-3);
	min-width: 0;
}

.mb-autor:empty,
.mb-jahr:empty {
	display: none;
}

.browser-liste {
	border-top: 0;
}

.mb-eintrag {
	border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}

.mb-zeile {
	padding: var(--raum-3);
	border-radius: var(--radius-sm);
	align-items: center;
}

.mb-zeile:hover {
	background: var(--surface-2);
}

.mb-eintrag.ist-gewaehlt > .mb-zeile {
	background: var(--surface-2);
	box-shadow: none;
}

/* Typzeichen: feine Linien, ein dezent getöntes Feld dahinter. */
.mb-typ-kurz,
.mb-typ-lang {
	display: none;
}

.mb-icon {
	width: 16px;
	height: 16px;
	color: var(--text-faint);
}

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

.mb-beschrieb {
	margin-top: 2px;
	font-size: var(--t--2);
}

.mb-marke:hover {
	color: var(--link);
}

/* `:not(.ist-aktiv)`, sonst nimmt der Grund der Fläche dem gewählten Chip
   die Akzentfarbe und der Text steht hell auf hell. */
.chip:not(.ist-aktiv) {
	background: var(--bg);
	border-color: transparent;
}

.seitenliste > li > a,
.bereiche > li > a {
	font-weight: 500;
	letter-spacing: 0;
}

/* ---- Startseite: Bereiche als Raster mit Symbolen ---------------------- */

.bereiche {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0 var(--raum-6);
}

.bereiche > li {
	display: grid;
	grid-template-columns: 36px minmax(0, 1fr);
	column-gap: var(--raum-4);
	align-items: start;
	padding-block: var(--raum-5);
}

.bereich-icon {
	display: grid;
	place-items: center;
	width: 36px;
	height: 36px;
	color: var(--text-faint);
	grid-row: span 2;
}

.knopf {
	font-weight: 600;
}

@media (max-width: 900px) {
	.spalte {
		margin: 0;
		border: 0;
		border-radius: 0;
	}

	.bereiche {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* Steht das Vorschau-Panel offen, bleibt für die Liste wenig Platz: die
   Typspalte weicht, der Titel behält ihn. */
.browser.ist-offen {
	--mb-typ: 24px;
}

.browser.ist-offen .mb-kopf,
.browser.ist-offen .mb-typ-kurz,
.browser.ist-offen .mb-typ-lang {
	display: none;
}

.browser.ist-offen .mb-icon {
	display: block;
}

.meldung-marke {
	background: none;
}

/* --------------------------------------------------------------------------
   37. Ansicht der Dokumentliste
   Dieselben Zeilen in drei Dichten. Der Umschalter steht unauffällig über
   der Liste; die Wahl gilt für die ganze Site.

   Tabelle  eine Zeile, alle Angaben in Spalten (Vorgabe)
   Liste    zweizeilig, der Kontextsatz ungekürzt, keine Spalten
   Raster   Kacheln mit der ersten Seite als Bild
   -------------------------------------------------------------------------- */

/* EIN Idiom für «gewählt» in der ganzen Site: der aktive Knopf mit
   2-px-Unterstrich in der Akzentfarbe. Dieselbe Form wie die Typleiste
   (`.bf-knopf`, Abschnitt 32) und der Terminumschalter
   (`.termin-ansicht-knopf`, Abschnitt 17). Vorher stand hier eine
   gefüllte Fläche mit Radius 8 — zwei Auswahl-Idiome, 200 px
   auseinander in derselben Zeile, und auf `/bibliothek` sogar Reiter
   mit Unterstrich neben Ansichtsknöpfen mit Fläche. Die Fläche entfällt
   site-weit; die Klassennamen bleiben, damit `assets/js/ansicht.js`
   nichts nachzuziehen hat.

   Seit dem 15.09.2026 stehen dort drei Zeichen statt drei Wörtern:
   «Tabelle | Liste | Raster» war mit rund 160 px der längste Block der
   Leiste und stand den Typen gegenüber, die den Platz brauchen. Das ist
   dieselbe Ausnahme wie beim Stift der Bearbeiten-Handlung
   (docs/DESIGN.md §6): das Zeichen IST hier der Knopf und nicht sein
   Schmuck — der Name steht im `aria-label` und im `title`.

   Damit steht der Umschalter auch auf dem Telefon wieder da. Unter
   560 px stand hier `display: none`: drei Wörter kosteten 160 px, und
   die hatte ein 400-px-Schirm nicht. Drei Zeichen kosten 104 px — sie
   passen neben den Knopf «Typ» (92 px) in einen 312 px breiten Balken,
   und die Ansicht ist gerade dort die Wahl, die am meisten ändert. */
.ansicht {
	display: inline-flex;
	align-items: center;
	gap: var(--raum-1);
	flex: none;
}

/* Quadrat in Trefferflächenmass — 32 × 32 wie der Klappenknopf der
   Zeile, und so hoch wie `.bf-knopf` daneben: beide Leisten stehen
   `align-items: center` in derselben Zeile, und nur bei gleicher
   Kastenhöhe liegen auch ihre Unterstriche auf einer Linie. */
.ansicht-knopf {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	padding: 0;
	background: none;
	border: 0;
	color: var(--text-muted);
	font: inherit;
	cursor: pointer;
}

/* 19 px wie der Stift der Bearbeiten-Handlung — das Zeichen trägt die
   Zeile, es begleitet sie nicht. */
.ansicht-knopf .icon {
	width: 19px;
	height: 19px;
}

.ansicht-knopf:hover {
	color: var(--text);
	box-shadow: inset 0 -1px 0 0 var(--text-faint);
}

.ansicht-knopf.ist-aktiv {
	color: var(--accent-text);
	box-shadow: inset 0 -2px 0 0 var(--accent);
}

/* ---- Liste mit Kontext ------------------------------------------------ */

[data-ansicht="liste"] .dz-kopf {
	display: none;
}

[data-ansicht="liste"] .dz {
	grid-template-columns: 24px minmax(0, 1fr) minmax(0, max-content) 14px;
	align-items: start;
	padding-block: var(--raum-3);
}

[data-ansicht="liste"] .dz-typwort,
[data-ansicht="liste"] .dz-autor,
[data-ansicht="liste"] .dz-jahr,
[data-ansicht="liste"] .dz-stufe,
[data-ansicht="liste"] .dz-thema,
[data-ansicht="liste"] .dz-ort,
[data-ansicht="liste"] .dz-mass {
	display: none;
}

/* Der Kontextsatz steht hier ungekürzt — dafür ist diese Ansicht da. */
[data-ansicht="liste"] .dz-unter {
	display: block;
	-webkit-line-clamp: none;
	overflow: visible;
	white-space: normal;
}

[data-ansicht="liste"] .dz-unter-spalten {
	display: block;
}

/* ---- Raster ------------------------------------------------------------ */

[data-ansicht="raster"] .dz-kopf {
	display: none;
}

/* `align-items: start`: jede Kachel ist so hoch wie ihr Inhalt. Ohne die
   Angabe dehnt das Raster alle Kacheln einer Reihe auf die Höhe der
   höchsten — auf `/bibliothek` waren das 446 px, und eine Kachel ohne
   Miniatur liess davon 313 px leer. docs/DESIGN.md §5.3 verlangt das
   Gegenteil: «die gleiche Höhe kommt aus der Textzone, nicht aus einem
   leeren Kasten». Die Textzone hält ihre `min-height` weiterhin — die
   Kacheln MIT Bild stehen darum untereinander bündig, die ohne Bild
   hören nach dem Text auf. */
[data-ansicht="raster"] .dz-liste {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	align-items: start;
	gap: var(--raum-5) var(--raum-4);
}

[data-ansicht="raster"] .dz {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas:
		"bild"
		"haupt"
		"formate";
	align-content: start;
	gap: var(--raum-2);
	min-height: 0;
	padding: 0 0 var(--raum-3);
	margin-inline: 0;
	border-bottom: 1px solid var(--border);
}

[data-ansicht="raster"] .dz-typ {
	grid-area: bild;
	justify-self: stretch;
	align-self: stretch;
	display: grid;
	place-items: center;
	aspect-ratio: 3 / 4;
	/* 240 px statt 320: die Vorschau ist ein Hinweis, kein Lesebild —
	   drei Kacheln füllten sonst den ganzen Schirm, und die Liste war
	   nach zwei Reihen zu Ende. */
	max-height: 240px;
	background: var(--bg);
	border: 1px solid var(--border);
	overflow: hidden;
}

/* Die Seite-1-Miniatur füllt die Kachel. */
.dz-bild {
	display: none;
}

[data-ansicht="raster"] .dz-icon {
	display: none;
}

/* Ohne Miniatur KEIN leerer Rahmen (docs/DESIGN.md §6: «Kein leerer
   Vorschaurahmen»). Vorher stand dort ein weisser Kasten im Verhältnis
   3 : 4 mit einem kleinen Zeichen in der Mitte — eine Vorschau, die
   verspricht, was sie nicht hat. Jetzt bleibt das Typzeichen als
   Zeichen: klein, links, ohne Rahmen und ohne Fläche, direkt über dem
   Titel. Die gleiche Kachelhöhe holt sich die Textzone über ihre
   `min-height`, nicht ein leerer Kasten. */
[data-ansicht="raster"] .dz-typ:not(:has(.dz-bild)) {
	aspect-ratio: auto;
	max-height: none;
	justify-self: start;
	align-self: start;
	background: none;
	border: 0;
	place-items: start;
}

[data-ansicht="raster"] .dz-typ:not(:has(.dz-bild)) .dz-icon {
	display: block;
	width: 20px;
	height: 20px;
}

/* Titel, Kontextsatz und Angaben füllen dieselbe Höhe, ob die Kachel
   nun ein Bild trägt oder nicht: zwei Zeilen Titel plus zwei Zeilen
   Satz. */
[data-ansicht="raster"] .dz-haupt {
	min-height: 5.5em;
}

/* Ohne Miniatur hat die Kachel keine fremde Höhe zu halten. Seit die
   Reihe ihre Kacheln nicht mehr dehnt (`align-items: start` oben), wäre
   diese Mindesthöhe genau der leere Kasten, den docs/DESIGN.md §6
   ausschliesst — nur eine Stelle weiter unten: gemessen 77 px Textzone
   für einen einzeiligen Titel. Für Kacheln MIT Bild bleibt sie: dort
   richtet sie den Text unter gleich hohen Bildern auf eine Linie. */
[data-ansicht="raster"] .dz:not(:has(.dz-bild)) .dz-haupt {
	min-height: 0;
}

[data-ansicht="raster"] .dz-bild {
	display: block;
}

[data-ansicht="raster"] .dz-typ img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: top center;
}

[data-ansicht="raster"] .dz-icon {
	width: 28px;
	height: 28px;
}

[data-ansicht="raster"] .dz-haupt {
	grid-area: haupt;
}

[data-ansicht="raster"] .dz-titel {
	font-weight: 600;
}

[data-ansicht="raster"] .dz-formate {
	grid-area: formate;
	justify-content: flex-start;
}

[data-ansicht="raster"] .dz-typwort,
[data-ansicht="raster"] .dz-autor,
[data-ansicht="raster"] .dz-jahr,
[data-ansicht="raster"] .dz-stufe,
[data-ansicht="raster"] .dz-thema,
[data-ansicht="raster"] .dz-ort,
[data-ansicht="raster"] .dz-mass {
	display: none;
}

[data-ansicht="raster"] .dz-unter-spalten {
	display: block;
}

[data-ansicht="raster"] .dz:hover,
[data-ansicht="raster"] .dz.ist-gewaehlt {
	background: none;
}

[data-ansicht="raster"] .dz.ist-gewaehlt .dz-typ {
	border-color: var(--accent);
}

/* --------------------------------------------------------------------------
   38. Textseite mit Faktenspalte
   Eine 880-px-Textspalte auf einem 1440-px-Schirm ist eine halbe Seite
   Leere. Ab 1200 px Inhaltsbreite steht der Text links (68 ch) und
   rechts eine schmale Spalte mit dem, was man beim Lesen braucht:
   Angaben, Dokumente, die eine Handlung. Das ist die einzige rechte
   Spalte — und sie trägt Inhalt, keine Wiederholung.
   -------------------------------------------------------------------------- */

.zweispalt {
	display: grid;
	gap: 20px;
	align-items: start;
}

/* 980 px Inhalt sind auf einem 1440-px-Schirm mit offener Leiste der
   Normalfall — dort muss die Faktenspalte stehen, sonst bleibt der
   Text allein in der Breite. */
@container inhalt (min-width: 980px) {
	.zweispalt {
		grid-template-columns: minmax(0, 68ch) minmax(280px, 320px);
		gap: 40px;
	}
}

.zweispalt-text,
.zweispalt-fakten {
	min-width: 0;
}

.zweispalt-text > * + * {
	margin-top: 16px;
}

.zweispalt-fakten > * + * {
	margin-top: 20px;
}

/* Fakten: Begriff links klein und gedämpft, Wert rechts in Textfarbe.
   Keine Beschriftungszeile «Angaben · Institution · ETH Zürich». */
.fakten {
	display: grid;
	grid-template-columns: max-content minmax(0, 1fr);
	gap: 6px var(--raum-3);
	margin: 0;
	align-items: baseline;
}

.fakten dt {
	font-size: var(--t--2);
	color: var(--text-muted);
}

.fakten dd {
	margin: 0;
	font-size: var(--t--1);
	color: var(--text);
	overflow-wrap: anywhere;
}

.fakten-titel {
	margin: 0 0 8px;
	font-size: var(--t-1);
	font-weight: 600;
}

.zweispalt-fakten .knopf {
	width: 100%;
	justify-content: center;
}

/* --------------------------------------------------------------------------
   39. Anmeldung als Dialog
   Der Dialog bringt Fokusfalle, Grund und Esc mit. Er ist so breit wie
   das Formular und keinen Pixel breiter.
   -------------------------------------------------------------------------- */

/* Der Dialog steht in der Mitte. <dialog> bringt Backdrop, Fokusfalle
   und Esc mit; hier geht es nur um Mass und Farbe. */
.anmeldedialog {
	width: min(520px, calc(100vw - 2 * var(--raum-5)));
	max-height: min(88vh, 820px);
	padding: 24px 24px 26px;
	color: var(--text);
	overflow-y: auto;
}

.anmeldedialog .dialog-kopf {
	margin-bottom: 16px;
}

/* Im Dialog ist das Formular kein Kasten auf der Seite: kein eigener
   Grund, keine Linie, kein Abstand nach oben — der Dialog ist der Kasten. */
.anmeldedialog .anmeldung {
	margin: 0;
	padding: 0;
	border: 0;
	background: transparent;
	max-width: none;
}

.anmeldedialog .anmeldung-formular {
	margin-top: 0;
}

/* Im Dialog füllt das Formular die ganze Breite – der Dialog ist
   bereits auf 520 px begrenzt (DESIGN §5.5). */
.anmeldedialog .formular {
	max-width: none;
}

.anmeldedialog .datenschutz {
	border-top: 0;
	padding-top: 4px;
}

.anmeldedialog .meldung {
	margin: 0;
}

.feld-aktionen {
	display: flex;
	align-items: center;
	gap: var(--raum-4);
}

/* Dateiwahl: das native Feld bleibt für Tastatur und Formular da, ist
   aber unsichtbar. Sichtbar ist ein Kasten in Feldhöhe mit eigenem Knopf
   und dem Namen der gewählten Datei. */
.dateiwahl {
	position: relative;
	display: flex;
	align-items: center;
	gap: var(--raum-3);
	height: 34px;
	padding: 0 var(--raum-3) 0 4px;
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	min-width: 0;
}

.dateiwahl input[type="file"] {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.dateiwahl-knopf {
	display: inline-flex;
	align-items: center;
	flex: none;
	height: 24px;
	padding: 0 var(--raum-3);
	background: var(--surface);
	color: var(--text);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	font-size: var(--t--2);
	font-weight: 500;
	white-space: nowrap;
	cursor: pointer;
}

.dateiwahl-knopf:hover {
	border-color: var(--text-faint);
}

.dateiwahl-name {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	font-size: var(--t--2);
	color: var(--text-muted);
}

.dateiwahl.hat-datei .dateiwahl-name {
	color: var(--text);
}

.dateiwahl:hover {
	border-color: var(--text-faint);
}

.dateiwahl:focus-within {
	outline: 2px solid var(--accent);
	outline-offset: -1px;
	border-color: var(--accent);
}

/* Ein fehlendes Feld ist rot umrandet — beide Felder gleich. `:has()`
   greift beim Dateifeld, weil dort ein echtes <input> steckt; die
   Auswahl hat keines, darum setzt das Skript dort und am Dateifeld
   zusätzlich `.ist-ungueltig`. */
.dateiwahl:has(input[aria-invalid="true"]),
.dateiwahl.ist-ungueltig {
	border-color: var(--danger);
}

.auswahl.ist-ungueltig .auswahl-knopf {
	border-color: var(--danger);
}

/* Die drei Kernfakten unter dem Titel: ein Satz, keine Liste. */
.kernfakten {
	margin: var(--raum-2) 0 0;
	font-size: var(--t--1);
	color: var(--text-muted);
}

.abschnitt + .abschnitt {
	margin-top: 20px;
}

.abschnitt > h2 {
	margin: 0 0 4px;
	font-size: var(--t-1);
	font-weight: 600;
	line-height: 1.3;
}

/* In der Faktenspalte ist die Liste nur 320 px breit: dort zählt der
   Titel, alles andere tritt zurück. Welche Spalten das sind, sagt die
   Container-Abfrage der Zeile (Abschnitt 30) — hier steht nur, was
   dieser Ort zusätzlich weglässt. */
.zweispalt-fakten .dz {
	padding-left: 0;
	margin-inline: 0;
}

.zweispalt-fakten .dz-unter {
	display: none;
}

.zweispalt-fakten .bereichsfilter {
	display: none;
}

/* ==========================================================================
   Tafel und Raster (docs/DESIGN.md §5.1, §5.2)
   ========================================================================== */

/* Vergleichstafel: Dinge als Spalten, Merkmale als Zeilen. */
.tafel-rahmen {
	overflow-x: auto;
}

.tafel {
	width: 100%;
	border-collapse: collapse;
	table-layout: fixed;
	font-size: var(--t--1);
	line-height: 1.4;
	font-variant-numeric: tabular-nums;
}

.tafel col.tafel-merkmal {
	width: 112px;
}

.tafel th,
.tafel td {
	text-align: left;
	vertical-align: top;
	padding: 8px 12px 8px 0;
	border-bottom: 1px solid var(--border);
	overflow-wrap: anywhere;
}

.tafel thead th {
	padding-top: 6px;
	font-weight: 600;
	font-size: var(--t--1);
	color: var(--text);
	border-bottom: 1px solid var(--text-muted);
}

.tafel thead th a {
	color: inherit;
	text-decoration: none;
}

.tafel thead th a:hover {
	text-decoration: underline;
}

.tafel-gruppen th {
	padding: 0 12px 4px 0;
	font-weight: 500;
	font-size: var(--t--2);
	color: var(--text-muted);
	border-bottom: 0;
}

.tafel-gruppen th span {
	display: block;
	padding-bottom: 4px;
	border-bottom: 1px solid var(--border);
}

.tafel-gruppen td,
.tafel-aktion td:first-child {
	border-bottom: 0;
}

.tafel tbody th {
	font-weight: 400;
	font-size: var(--t--2);
	color: var(--text-muted);
	padding-left: 0;
}

.tafel .tafel-trenner {
	border-left: 1px solid var(--border);
	padding-left: 12px;
}

.tafel tbody tr:last-child td,
.tafel tbody tr:last-child th {
	border-bottom: 0;
}

.tafel-leer {
	color: var(--text-muted);
}

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

.tafel-dokumente li {
	display: flex;
	justify-content: space-between;
	gap: 8px;
	padding: 2px 0;
}

.tafel-dokumente a {
	color: var(--text);
	text-decoration: none;
}

.tafel-dokumente a:hover {
	text-decoration: underline;
}

.tafel-format,
.raster-format {
	color: var(--text-muted);
	font-size: var(--t--2);
	white-space: nowrap;
}

.tafel-aktion td {
	padding-top: 12px;
}

.tafel-aktion .knopf {
	width: auto;
}

/* Gäste können sich nicht einschreiben: statt des Knopfs steht der
   Weg zum Login da, als Text. */
.tafel-anmelden {
	font-size: var(--t--2);
}

/* Erklaertext unter der Tafel: je Praktikum eine Spalte, so viele
   nebeneinander, wie die Breite traegt. */
.tafel-ablauf {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
	gap: 20px 40px;
	margin-top: var(--raum-6);
}

.tafel-abschnitt h2 {
	margin: 0 0 4px;
	padding-top: 10px;
	border-top: 1px solid var(--border);
	font-size: var(--t-0);
	font-weight: 600;
}

.tafel-abschnitt h2 a {
	color: inherit;
	text-decoration: none;
}

.tafel-abschnitt h3 {
	margin: 8px 0 2px;
	font-size: var(--t--1);
	font-weight: 600;
}

.prosa-dicht {
	font-size: var(--t--1);
	line-height: 1.45;
	max-width: none;
}

.prosa-dicht p {
	margin: 0 0 6px;
}

.prosa-dicht ul,
.prosa-dicht ol {
	margin: 0 0 6px;
	padding-left: 18px;
}

/* Raster: Unterseiten als Spalten mit ihren Unterlagen. */
.prosa-bereich {
	margin-bottom: 20px;
}

.raster {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
	gap: 20px 40px;
	align-items: start;
}

.raster-spalte h2 {
	margin: 0;
	padding: 8px 0 6px;
	border-bottom: 1px solid var(--border);
	font-size: var(--t-0);
	font-weight: 600;
}

.raster-spalte h2 a {
	color: inherit;
	text-decoration: none;
}

.raster-spalte h2 a:hover {
	text-decoration: underline;
}

.raster-satz {
	margin: 6px 0 2px;
	font-size: var(--t--1);
	color: var(--text-muted);
}

.raster-liste {
	list-style: none;
	margin: 0;
	padding: 0;
	font-size: var(--t--1);
}

.raster-liste li {
	display: flex;
	justify-content: space-between;
	gap: 10px;
	padding: 5px 0;
	border-bottom: 1px solid var(--border);
}

.raster-liste li:last-child {
	border-bottom: 0;
}

.raster-liste a {
	color: var(--text);
	text-decoration: none;
	min-width: 0;
}

.raster-liste a:hover {
	text-decoration: underline;
}

.raster-mehr {
	display: inline-block;
	margin-top: 6px;
	font-size: var(--t--2);
}

.raster-leer {
	margin: 6px 0 0;
	font-size: var(--t--1);
	color: var(--text-muted);
}

/* Personen am Fuss der Startseite: eine Zeile je Person. Den Abstand
   zum Abschnitt darueber setzt die eine Regel fuer alle (--raum-6). */
.personen-zeile h2 {
	font-size: var(--t-0);
	font-weight: 600;
	margin: 0 0 6px;
}

.personen-liste {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
	gap: 0 36px;
}

.personen-liste li {
	padding: 6px 0;
	border-top: 1px solid var(--border);
	font-size: var(--t--1);
}

.personen-liste a:first-child {
	font-weight: 500;
	color: var(--text);
	text-decoration: none;
}

/* Eine Angabe je Zeile, alle Zeilen gleich hoch: Fachdidaktik,
   Funktion an der Schule, Schule oder Organisation, E-Mail. */
.personen-liste a:first-child,
.personen-rolle,
.personen-mail {
	display: block;
	margin: 0;
	line-height: 1.5;
}

.personen-rolle,
.personen-mail {
	color: var(--text-muted);
	font-size: var(--t--2);
}

/* Seite /personen: dasselbe Raster, eine Stufe grösser — hier ist die
   Liste die Seite und nicht ihr Fuss. Als einspaltige Liste stand der
   Text auf 28 % der Breite, während die Trennlinien über die ganze
   Fläche liefen (Befund B48); jetzt ist jede Person eine Spalte ohne
   Kasten, und die Linie ist so breit wie ihre Spalte.

   Die Spur beginnt bei 20 rem statt 22 rem: mit 22 rem fiel das Raster
   bei 1200 px Fenster (708 px Inhalt) auf EINE Spalte zurück, und die
   Spaltenlinie wurde zur Seitenlinie unmittelbar unter dem Titel —
   genau das, was §6 verbietet (Befund B75). `min(20rem, 100%)` hält die
   Spur auch auf dem Telefon in der Fläche.

   `auto-fit` statt `auto-fill`: drei Personen auf 2068 px standen vorher
   in fünf Spuren, von denen zwei leer blieben (Befund B79). `auto-fit`
   klappt die leeren ein und teilt die Fläche unter den gefüllten auf.
   Der Deckel gegen zu breite Spalten sitzt nicht an der Spur, sondern am
   Text darin (`--prosa`, weiter unten): eine feste Obergrenze an der
   Spur wäre zugleich die Zahl, aus der der Browser die Spurenzahl
   rechnet — und mit ihr fiele das Raster bei 1200 px wieder auf eine
   Spalte zurück. */
.personen-raster {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
	gap: var(--raum-5) var(--luft);
}

.personen-raster > li {
	min-width: 0;
	padding-top: var(--raum-2);
	border-top: 1px solid var(--border);
}

/* Bleibt nur eine Spalte übrig — auf dem Telefon —, ist die Oberlinie
   der ersten Zeile keine Spaltenlinie mehr, sondern eine Linie über die
   ganze Breite direkt unter dem Seitentitel (§6, Befund B47/B75). Zwei
   Spuren brauchen 2 × 20 rem und eine Lücke; darunter steht eine. Der
   Bezug ist die Inhaltsbreite, nicht das Fenster: die Leiste ist
   verstellbar. Die Lücke ist `--luft` und im Look «labor» 36 statt
   48 px; die Schwelle steht auf der breiteren der beiden, weil der
   Fehler dann in die harmlose Richtung fällt — im schmalen Fenster
   fehlt der ersten von zwei Spalten die Oberlinie, statt dass eine
   Linie über die volle Breite unter dem Titel stünde. */
@container inhalt (max-width: 43rem) {
	.personen-raster > li:first-child {
		padding-top: 0;
		border-top: 0;
	}
}

.personen-raster > li > a:first-child {
	display: block;
	font-size: var(--t-0);
	font-weight: 600;
	color: var(--text);
	text-decoration: none;
}

.personen-raster > li > a:first-child:hover {
	color: var(--link);
}

/* Vier kurze Zeilen, keine Sätze: der Deckel hält sie unter der
   Lesegrenze, auch wenn eine Spalte breiter wird (Befund B20). */
.personen-raster .personen-rolle,
.personen-raster .personen-mail,
.personen-raster .personen-satz {
	display: block;
	max-width: var(--prosa);
	font-size: var(--t--1);
	line-height: 1.5;
	color: var(--text-muted);
}

.personen-raster .personen-mail {
	color: var(--link);
	text-decoration: none;
}

.personen-raster .personen-mail:hover {
	text-decoration: underline;
}

.personen-raster .personen-satz {
	margin: var(--raum-1) 0 0;
	line-height: 1.45;
}

/* Dokumentliste auf Textseiten: Titel mit Satz, Angaben rechts. */
.dokliste li > div {
	min-width: 0;
}

.dokliste-satz {
	display: block;
	font-size: var(--t--2);
	color: var(--text-muted);
}

.dokliste-breit .raster-liste {
	max-width: 1100px;
}

.dokliste-breit .raster-liste li {
	padding: 8px 0;
}


/* Modus als drei Textknoepfe in einer Zeile. */
.theme-segment {
	display: flex;
	gap: 4px;
	margin: 0 0 14px;
	padding: 0;
	border: 0;
}

.theme-modus {
	border: 0;
	padding: 0;
	margin: 0;
	min-width: 0;
}

.theme-modus-option {
	position: relative;
}

.theme-modus-option input {
	position: absolute;
	opacity: 0;
	inset: 0;
	margin: 0;
	cursor: pointer;
}

.theme-modus-option span {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	height: 30px;
	padding: 0 12px;
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	font-size: var(--t--1);
	color: var(--text);
	white-space: nowrap;
}

.theme-modus-option input:checked + span {
	border-color: var(--accent);
	color: var(--accent-text);
	font-weight: 500;
}

.theme-modus-option input:focus-visible + span {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
}

/* Personen: eine Zeile je Funktion. */
.funktion p {
	margin: 0 0 2px;
	font-size: var(--t-0);
	color: var(--text);
}

.funktion p:last-child {
	color: var(--text-muted);
}

@keyframes panel-herein {
	from { transform: translateX(24px); opacity: 0; }
	to   { transform: none; opacity: 1; }
}

[data-dokupanel]:not([hidden]) {
	animation: panel-herein .18s ease-out;
}

@media (prefers-reduced-motion: reduce) {
	[data-dokupanel]:not([hidden]) { animation: none; }
}


/* Alle Dateitypen tragen dieselbe Textfarbe, in jeder Ansicht und
   jedem Theme. Die Endung und das Symbol unterscheiden das Format. */
.dz-typ .dz-icon,
.mb-marke[data-endung],
.raster-format[data-datei],
.tafel-format[data-datei],
.termin-endung[data-datei] {
	color: var(--text);
}


/* Sortierbare Kopfzeile */
.dz-sort {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 0;
	background: none;
	border: 0;
	font: inherit;
	font-size: var(--t--2);
	font-weight: 500;
	color: var(--text-muted);
	text-align: left;
	cursor: pointer;
}

.dz-sort:hover {
	color: var(--text);
}

.dz-sort-pfeil::before {
	content: "";
	display: inline-block;
	width: 0;
	height: 0;
	opacity: 0;
	border-left: 3.5px solid transparent;
	border-right: 3.5px solid transparent;
	border-bottom: 5px solid currentColor;
}

.dz-sort[aria-sort="ascending"] .dz-sort-pfeil::before {
	opacity: 1;
}

.dz-sort[aria-sort="descending"] .dz-sort-pfeil::before {
	opacity: 1;
	transform: rotate(180deg);
}

.dz-sort[aria-sort]:not([aria-sort="none"]) {
	color: var(--text);
}

.neue-dokumente-summary {
	display: flex;
	align-items: center;
	gap: var(--raum-2);
	width: fit-content;
	font-size: var(--t-0);
	font-weight: 600;
}

.neue-dokumente-summary::before {
	content: "";
	width: 8px;
	height: 8px;
	border-right: 1.6px solid var(--text-faint);
	border-bottom: 1.6px solid var(--text-faint);
	transform: rotate(-45deg);
	transition: transform 0.16s ease;
}

.neue-dokumente details[open] > .neue-dokumente-summary {
	margin-bottom: 6px;
}

.neue-dokumente details[open] > .neue-dokumente-summary::before {
	transform: rotate(45deg);
}

.neue-dokumente-anzahl {
	font-size: var(--t--2);
	font-weight: 500;
	font-variant-numeric: tabular-nums;
	color: var(--text-muted);
}

/* «Neue Dokumente» stand bei 2068 px Inhaltsbreite auf 900 px — 43.5 %
   der Fläche, und rechts daneben nichts (Befund B76). Der Deckel ist
   darum kein Deckel mehr, sondern derselbe Spaltensatz wie beim
   Themenraster einen Abschnitt darüber (§5.1): die Liste wächst mit der
   Fläche, und das Datum bleibt an seinem Titel, statt bei 2560 px einen
   halben Schirm weit von ihm abzurücken. 34 rem als Spaltenbreite, weil
   eine Zeile hier Titel UND Kurzbeschrieb trägt — bei 1440 px bleibt es
   dabei eine Spalte über die volle Breite, ab 1920 px werden es zwei. */
.neue-dokumente .raster-liste {
	column-width: 34rem;
	column-gap: var(--luft);
}

/* Ein Eintrag wird nicht über zwei Spalten zerrissen. */
.neue-dokumente .raster-liste li {
	break-inside: avoid;
}

/* Reiter ohne JavaScript: Radio + Label. Nur der gewaehlte Inhalt ist sichtbar. */

/* Die Tafel haelt Radios, Leiste und Inhalte als Geschwister zusammen —
   die Regeln unten arbeiten mit `~`. Ein <fieldset> statt eines <div>,
   damit die drei Radios eine benannte Gruppe sind (<legend>, versteckt);
   die Vorgabe-Rahmen und `min-width: min-content` muessen dafuer weg,
   sonst sprengte eine breite Tabelle darin die Seite. */
.reiter-tafel {
	min-width: 0;
	margin: 0 0 var(--raum-7);
	padding: 0;
	border: 0;
}

/* Versteckt, aber fokussierbar: `display: none` nimmt dem Radio den
   Fokus, und damit waeren die Reiter mit der Tastatur nicht mehr
   erreichbar (die Pfeiltasten wechseln in einer Radiogruppe von selbst). */
.reiter-radio {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.reiter-leiste {
	display: flex;
	/* Auf schmalen Schirmen laesst sich die Leiste seitlich schieben,
	   statt umzubrechen oder die Seite waagrecht zu sprengen (fuenf
	   Reiter der Startseite). Die Grundlinie ist ein Schatten statt
	   eines Rahmens: `overflow-x` schneidet sonst die um 1 px
	   hinuntergezogene Unterstreichung des aktiven Reiters ab. */
	flex-wrap: nowrap;
	overflow-x: auto;
	scrollbar-width: none;
	gap: 4px;
	margin: 0 0 14px;
	box-shadow: inset 0 -1px 0 var(--border);
}

.reiter-knopf {
	display: inline-flex;
	flex: none;
	align-items: center;
	gap: 6px;
	padding: 6px 12px 8px;
	white-space: nowrap;
	font-size: var(--t--1);
	font-weight: 500;
	color: var(--text-muted);
	cursor: pointer;
	border-bottom: 2px solid transparent;
}

.reiter-knopf:hover {
	color: var(--text);
}

.reiter-zahl {
	font-size: var(--t--2);
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
}

/* Der Zaehler als Kreis: was neu ist oder wartet, soll man am Reiter
   sehen, ohne ihn zu oeffnen. `min-width` gleich der Hoehe haelt die
   einstellige Zahl rund; zweistellige wachsen zur Kapsel statt zum Ei.
   Die Farbe kommt aus den Tokens (ARCHITEKTUR §7) und stimmt damit in
   hell und dunkel; die eigene `color` schlaegt die geerbte des aktiven
   Reiters. */
.reiter-zahl.ist-kreis {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	height: 18px;
	min-width: 18px;
	padding: 0 5px;
	border-radius: 999px;
	background: var(--accent);
	color: var(--accent-contrast);
	font-weight: 600;
	line-height: 1;
}

/* ==========================================================================
   37. Layout-Varianten (docs/DESIGN.md §8)

   Drei Werte an [data-layout] des <html>, vom Server gesetzt: kompakt
   (Vorgabe), komfort, fokus. Kein zweites Stylesheet, keine kopierte
   Regel: komfort verstellt Tokens, fokus startet mit eingeklappter
   Leiste (Schiene mit Symbolen; die Leiste erscheint beim Ueberfahren).
   ========================================================================== */

/* ---- komfort: eine Stufe groesser, eine Stufe luftiger ---------------- */

/* Fuer grosse Schirme und den Beamer. Jede Schriftstufe waechst um genau
   1 px, die Abstandsskala um den Faktor 1.25, die Dokumentzeile von 40
   auf 44 px. Nichts anderes: dieselbe Gestaltung, nur weiter weg lesbar. */
:root[data-layout="komfort"] {
	--t--3:  0.8125rem;  /* 13 px   */
	--t--2:  0.84375rem; /* 13.5 px */
	--t--1b: 0.90625rem; /* 14.5 px */
	--t--1:  0.9375rem;  /* 15 px   */
	--t-0:   0.9375rem;  /* 15 px   */
	--t-0b:  0.96875rem; /* 15.5 px */
	--t-1:   1rem;       /* 16 px   */
	--t-2:   1.0625rem;  /* 17 px   */
	--t-3:   1.3125rem;  /* 21 px   */
	--t-4:   calc(1.8125rem - var(--titel-minus)); /* 29 px */
	--t-5:   calc(2.3125rem - var(--titel-minus)); /* 37 px */

	--raum-1: 0.3125rem; /* 5 px  */
	--raum-2: 0.625rem;  /* 10 px */
	--raum-3: 0.9375rem; /* 15 px */
	--raum-4: 1.25rem;   /* 20 px */
	--raum-5: 1.875rem;  /* 30 px */
	--raum-6: 2.5rem;    /* 40 px */
	--raum-7: 3.75rem;   /* 60 px */

	--dz-zeile: 44px;
	--reihe: 40px;

	--leiste: var(--leiste-wahl, 400px);
}

/* ---- fokus: die Schiene ist die Leiste ------------------------------- */

/* Der Server rendert data-leiste="zu": sichtbar bleibt die Schiene mit
   den Symbolen der Bereiche, die Leiste legt sich beim Ueberfahren der
   Schiene als Ueberlagerung darueber (leiste-peek, leiste.js). Der
   Inhalt bleibt maximal breit; das Ziehen und der Einklapp-Knopf sind aus. */
[data-layout="fokus"] .leiste-einklappen,
[data-layout="fokus"] .leiste-griff,
[data-layout="fokus"] [data-leiste-ausklappen] {
	display: none;
}

.reiter-inhalt {
	display: none;
}

.reiter-radio:nth-of-type(1):checked ~ .reiter-leiste .reiter-knopf:nth-of-type(1),
.reiter-radio:nth-of-type(2):checked ~ .reiter-leiste .reiter-knopf:nth-of-type(2),
.reiter-radio:nth-of-type(3):checked ~ .reiter-leiste .reiter-knopf:nth-of-type(3),
.reiter-radio:nth-of-type(4):checked ~ .reiter-leiste .reiter-knopf:nth-of-type(4),
.reiter-radio:nth-of-type(5):checked ~ .reiter-leiste .reiter-knopf:nth-of-type(5),
.reiter-radio:nth-of-type(6):checked ~ .reiter-leiste .reiter-knopf:nth-of-type(6),
.reiter-radio:nth-of-type(7):checked ~ .reiter-leiste .reiter-knopf:nth-of-type(7),
.reiter-radio:nth-of-type(8):checked ~ .reiter-leiste .reiter-knopf:nth-of-type(8) {
	color: var(--accent-text);
	border-bottom-color: var(--accent);
}

.reiter-radio:nth-of-type(1):checked ~ .reiter-inhalt[data-reiter-nr="1"],
.reiter-radio:nth-of-type(2):checked ~ .reiter-inhalt[data-reiter-nr="2"],
.reiter-radio:nth-of-type(3):checked ~ .reiter-inhalt[data-reiter-nr="3"],
.reiter-radio:nth-of-type(4):checked ~ .reiter-inhalt[data-reiter-nr="4"],
.reiter-radio:nth-of-type(5):checked ~ .reiter-inhalt[data-reiter-nr="5"],
.reiter-radio:nth-of-type(6):checked ~ .reiter-inhalt[data-reiter-nr="6"],
.reiter-radio:nth-of-type(7):checked ~ .reiter-inhalt[data-reiter-nr="7"],
.reiter-radio:nth-of-type(8):checked ~ .reiter-inhalt[data-reiter-nr="8"] {
	display: block;
}

.reiter-radio:focus-visible ~ .reiter-leiste {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
}

.tafel-login {
	font-size: var(--t--2);
	color: var(--text-muted);
}

.tafel .tafel-format {
	font-size: var(--t--2);
}

/* Praktika: Institutionen als getrennte Bloecke, Praktikum als
   Beschreibungstabelle.

   Zwei Spalten, sobald zwei hineinpassen (Entscheid vom 15.09.2026):
   `31rem + 32px + 31rem` sind genau 64 rem, darunter bleibt eine Spalte.
   Vorher stand je Institution ein Block ueber die ganze Breite, und
   darin eine Tabelle, die nur ihren Inhalt mass — zwei schmale Tafeln
   untereinander mit zwei Dritteln leerer Flaeche rechts daneben.

   Der Deckel von 100 rem haelt die beiden Spalten auf breiten Schirmen
   zusammen: bei 2560 px Fenster misst der Inhalt 2076 px, zwei Spalten
   daraus waeren je 1022 px, und die Lektionenspalte allein truege den
   ganzen Ueberschuss. Mit 100 rem sind es 784 px je Spalte — mehr als
   die 60 % Blockbreite aus Abschnitt 7 verlangen (1600 von 2076 px sind
   77 %) und nahe an dem, was die breitere der beiden Tafeln von sich aus
   braucht (886 px).

   Die Spur beginnt bei einer FESTEN Laenge, nicht bei `auto`: eine
   `auto`-Spur waechst auf den `max-content`-Beitrag ihres Inhalts, die
   Tafel darin wuerde die Spalte breiter machen als `main`, und statt der
   Tabelle scrollte die ganze Seite (Befund B71). `min(100%, 31rem)` ist
   auf dem Telefon die volle Breite und sonst die Schwelle; die Spur
   misst sich damit nie am Inhalt, und `.tabelle-rahmen` uebernimmt das
   waagrechte Scrollen — genau die Aufgabe, fuer die er da ist. */
.institutionen {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 31rem), 1fr));
	gap: 32px;
	max-width: 100rem;
}

/* Der Block ist sein eigener Abfragebehaelter, nicht das Fenster: ob
   die Tafel darin noch Spalten tragen kann, entscheidet die Breite des
   Blocks. Im Raster ist das je nach Schirm die halbe oder die ganze
   Inhaltsbreite — eine Fensterbreite waere an beiden Stellen falsch.
   (Wie bei der Dokumentliste, app.css §30.) */
.institution {
	min-width: 0;
	container: institution / inline-size;
}

/* Der Abstand zwischen zwei Spalten ist der der Tafel (`--raum-4`); die
   früheren 24 px vergrösserten das Loch zwischen Titel und Lektionen. */

.praktika-titel {
	font-weight: 500;
	color: var(--text);
	text-decoration: none;
}

.praktika-titel:hover {
	text-decoration: underline;
}

.praktika-neben {
	display: block;
	font-size: var(--t--2);
	color: var(--text-muted);
}

.praktika-mehr {
	font-size: var(--t--2);
	white-space: nowrap;
}

.beschreibung-kopf {
	margin: 0 0 14px;
}

.beschreibung {
	width: 100%;
	max-width: 1100px;
	border-collapse: collapse;
	font-size: var(--t--1);
}

.beschreibung th,
.beschreibung td {
	text-align: left;
	vertical-align: top;
	padding: 10px 16px 10px 0;
	border-bottom: 1px solid var(--border);
}

.beschreibung th {
	width: 180px;
	font-weight: 500;
	color: var(--text-muted);
	font-size: var(--t--2);
	padding-top: 12px;
}

.beschreibung tr:last-child th,
.beschreibung tr:last-child td {
	border-bottom: 0;
}

.beschreibung .prosa-dicht {
	max-width: 80ch;
}

.beschreibung .prosa-dicht > :last-child {
	margin-bottom: 0;
}

.beschreibung-dokumente {
	max-width: 620px;
}

/* ===================================================================
/* ---- Dialog: der Abschnitt «Layout» ueber «Farben» -------------------- */

/* Der Korpus des Dialogs setzt die Abschnitte untereinander; die Linie
   zwischen ihnen liegt darum oben, nicht links. */
.darstellung-korpus > .darstellung-spalte + .darstellung-spalte {
	border-left: 0;
	border-top: 1px solid var(--border);
}

.theme-segment-layout {
	gap: 6px;
	margin-bottom: 0;
}

/* Alle gleich hoch: der Knopf ist eine Flaeche, keine Zeile. */
.theme-segment-layout .theme-modus-option {
	display: flex;
	flex: 1 1 0;
	min-width: 0;
}

/* Ein Wort, darunter eine Zeile Erklaerung. Der Knopf waechst mit dem
   Text — gekuerzt wird nichts. */
.theme-segment-layout .theme-modus-option span {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 2px;
	width: 100%;
	height: auto;
	padding: 7px 9px;
	white-space: normal;
}

.theme-layout-option b {
	font-weight: 500;
}

/* Der Akzent gilt dem Wort, nicht der Erklaerung. */
.theme-layout-option i,
.theme-layout-option input:checked + span i {
	font-style: normal;
	font-size: var(--t--3);
	line-height: 1.25;
	font-weight: 400;
	color: var(--text-muted);
}

/* ==========================================================================
   Leiste: aufklappbares Menü in einer Spalte (docs/DESIGN.md §5.6)
   ========================================================================== */

/* Die Leiste scrollt als Ganzes; kein zweiter Balken in ihr
   (docs/DESIGN.md §5.6). Die Navigation bekommt darum keine eigene
   Hoehe und keinen eigenen Ueberlauf: sie ist so hoch, wie sie ist, und
   die Leiste darum herum scrollt. Vorher schrumpfte sie im Flex-Kasten
   auf die Resthoehe und schnitt Eintraege mitten in der Zeile ab. */
.leiste-nav {
	flex: none;
	overflow: visible;
	padding: 4px 0 8px;
}

/* Hierarchie in der Grösse: Bereich 14.5/600, Gruppe 13.5/600, Eintrag 13.5/400.
   Ein Titel ist nie kleiner als das, was unter ihm steht. Die beiden
   Grade stehen als Token in der Skala (--t-0b, --t--1b), nicht als harte
   Pixelwerte an jeder einzelnen Regel. */
.nav-bereich .nav-link {
	min-height: 36px;
	font-size: var(--t-0b);
	font-weight: 600;
}

.nav-bereich .nav-icon .icon {
	width: 16px;
	height: 16px;
}

/* Gruppentitel (Kurse, ETH Zürich, Kapitel, Nach Typ): Meta-Grösse, gedämpft,
   ohne Linie darunter. */
.nav-gruppe-titel {
	margin: 10px 0 2px;
	padding: 0 var(--raum-2);
	font-size: var(--t--1b);
	font-weight: 600;
	line-height: 1.3;
	color: var(--text);
}

.nav-gruppe-titel a {
	color: inherit;
	text-decoration: none;
}

.nav-gruppe-titel a:hover {
	color: var(--accent-text);
}

/* Fachgebiete als Klappen: gleiche Grösse und gleiches Gewicht wie ein
   Gruppentitel, in Tinte, nicht gedämpft. */
.nav-gebiet,
.nav-gebiet:hover {
	font-size: var(--t--1b);
	font-weight: 600;
	color: var(--text);
}

.nav-gruppe + .nav-gruppe {
	margin-top: 4px;
}

.nav-ebene-3 .nav-link {
	min-height: 30px;
	padding-top: 0.2rem;
	padding-bottom: 0.2rem;
	font-size: var(--t--1b);
	font-weight: 400;
}

/* Vorlesungen: direkte Einträge, ohne leere Gruppen und dritte Ebene. */
[data-bereich="vorlesung"] > .nav-sub .nav-ebene-2 > .nav-item .nav-link {
	font-size: var(--t--1b);
	font-weight: 400;
}

.kurs-archiv {
	margin-top: var(--raum-5);
}

.kurs-archiv-filter,
.kurs-semester-filter {
	display: flex;
	align-items: center;
	gap: var(--raum-2);
	flex-wrap: wrap;
}

.kurs-archiv-filter {
	justify-content: space-between;
	margin-bottom: var(--raum-3);
}

.kurs-semester-filter select {
	width: auto;
	min-width: 9rem;
}

.kurs-semester-filter label {
	margin: 0;
}

.kurs-archiv-tabs {
	display: flex;
	gap: var(--raum-3);
}

.kurs-archiv-tabs a {
	padding: 6px 0;
	color: var(--text-muted);
	text-decoration: none;
	border-bottom: 2px solid transparent;
}

.kurs-archiv-tabs a[aria-current="page"] {
	color: var(--accent-text);
	border-bottom-color: var(--accent-text);
}

.kurs-archiv-liste {
	list-style: none;
	padding: 0;
	margin: 0;
}

.kurs-archiv-liste li {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: var(--raum-2);
	padding: 10px 0;
	border-bottom: 1px solid var(--border);
}

.kurs-archiv-bearbeiten {
	font-size: var(--t--1b);
	flex-shrink: 0;
}

.nav-neben {
	margin-left: auto;
	padding-left: 8px;
	font-size: var(--t--3);
	color: var(--text-muted);
	white-space: nowrap;
}

.nav-hinweis {
	color: var(--text-muted);
	font-size: var(--t--2);
}

/* Praktika-Kurzübersicht (docs/DESIGN.md §5.2): die Tafel füllt ihren
   Block, sie misst sich nicht selbst (Entscheid vom 15.09.2026).
   `.tabelle` bringt `width: max-content; max-width: 100%` mit — das ist
   für eine Tafel richtig, die für sich steht, und falsch für eine, die
   in einer Rasterspalte sitzt: die Tabelle stand dann als schmaler
   Streifen links im Block, und die rechte Kante des Blocks trug nichts.
   Den Deckel für breite Schirme trägt jetzt `.institutionen` (100 rem);
   hier wäre er doppelt und machte den Streifen nur wieder schmaler. */
.praktika-liste {
	width: 100%;
	max-width: none;
}

/* Die Titelspalte ist so breit wie ihr längster Titel und keinen Pixel
   breiter: `width: 1%` fällt in der automatischen Tabellenrechnung auf
   die Mindestbreite zurück, und `nowrap` macht die Mindestbreite zum
   ganzen Titel. Damit bleibt zwischen Titel und Lektionen nur das
   Zellpolster — das Loch von 174 px, das feste Prozentspuren rissen,
   kann so gar nicht entstehen. Passt der Titel nicht mehr, scrollt der
   `.tabelle-rahmen`, wie vorgesehen. */
.praktika-liste th.pl-praktikum,
.praktika-liste td.pl-praktikum {
	width: 1%;
	white-space: nowrap;
}

/* `break-word` und nicht `anywhere`: `anywhere` zieht die Mindestbreite
   einer Zelle auf null, und seit die Tafel in ihrer Spalte bleibt
   (B71), drückte das die Titelspalte unter die Wortbreite —
   «Einführungsprakti | kum». Mit `break-word` misst die Spalte
   mindestens ihr längstes Wort; reicht der Platz dafür nicht, scrollt
   der `.tabelle-rahmen`, wie vorgesehen. Ein einzelnes überlanges Wort
   bricht weiterhin, statt hinauszulaufen. */
.praktika-liste td,
.praktika-liste th {
	vertical-align: top;
	overflow-wrap: break-word;
}

/* Die Zeile unter dem Zeiger: eine weiche Fläche mit runden Ecken; der
   Text hält Abstand zum Rand der Fläche. */
.praktika-liste th:first-child,
.praktika-liste td:first-child {
	padding-left: 10px;
}

.praktika-liste th:last-child,
.praktika-liste td:last-child {
	padding-right: 10px;
}

.praktika-liste tbody tr:hover {
	background: none;
}

.praktika-liste tbody tr:hover td {
	background: var(--hover, var(--surface));
}

.praktika-liste tbody tr:hover td:first-child {
	border-radius: var(--radius) 0 0 var(--radius);
}

.praktika-liste tbody tr:hover td:last-child {
	border-radius: 0 var(--radius) var(--radius) 0;
}

/* Ausrichtung an der Spaltenklasse, die Kopf und Zelle teilen: so
   können die beiden rechten Kanten gar nicht auseinanderlaufen.

   `width: 1%` und `nowrap` wie bei der Titelspalte: die Spalte ist so
   breit wie der Knopf, und alles, was übrig bleibt, gehört den
   Lektionen. Weil die Tafel ihren Block füllt, steht der Knopf damit an
   der rechten Kante des Blocks — in beiden Blöcken auf demselben
   Abstand von ihr. */
.praktika-liste th.pl-aktion,
.praktika-liste td.pl-aktion {
	width: 1%;
	white-space: nowrap;
	text-align: right;
}

/* Der Knopf ist höher als eine Textzeile; ohne Ausgleich schöbe seine
   Zeilenbox die Grundlinie nach unten, und die Zeile stünde nicht mehr
   auf einer Linie (wie die Datumsspur der Termine). Der Ausgleich ist
   die halbe Differenz zwischen Knopfhöhe und Zeilenhöhe — in Tokens
   gerechnet, nicht in Pixeln. */
.praktika-liste td.pl-aktion .knopf {
	margin-block: calc((1lh - var(--feld) - 2px) / 2);
}

/* ---- Unter 480 px Blockbreite: die Zeile wird zweizeilig -------------
   Gemessen bei 400 px Fenster: die Lektionenspalte hatte noch 101 px,
   und «5 Lektionen hospitieren / 5 Lektionen halten» stand darin auf
   vier Zeilen, waehrend der Knopf rechts aus dem Rahmen lief (49 px
   Scrollweite). Drei Spalten sind dort keine Tafel mehr, sondern eine
   Treppe. Darum dasselbe Mittel wie bei der Dokumentzeile (§5.3): der
   Titel oben, die Lektionen als leise Zeile darunter, der Knopf rechts
   daneben ueber beide Zeilen. Die Kopfzeile faellt weg — zweizeilige
   Bloecke haben keine Spalten mehr, die sie beschriften koennte.

   Die Trennlinie und die Flaeche unter dem Zeiger wandern von den
   Zellen auf die Zeile: die Zellen sind hier keine Spalten mehr, und
   drei Linien untereinander waeren drei Zeilen statt einer. */
@container institution (max-width: 480px) {
	.praktika-liste thead {
		display: none;
	}

	.praktika-liste,
	.praktika-liste tbody {
		display: block;
	}

	.praktika-liste tbody tr {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: start;
		column-gap: var(--raum-4);
		padding: var(--raum-3) 10px;
		border-bottom: 1px solid var(--border);
		border-radius: var(--radius);
	}

	.praktika-liste tbody tr:last-child {
		border-bottom: 0;
	}

	/* Den 10-px-Einzug der Flaeche unter dem Zeiger traegt hier die
	   Zeile; an den Zellen muss er weg, sonst stuende der Titel 10 px
	   weiter rechts als die Lektionen darunter. `:first-child` und
	   `:last-child` wiegen schwerer als ein blosses `td` — sie stehen
	   darum mit im Selektor. */
	.praktika-liste tbody td,
	.praktika-liste tbody td:first-child,
	.praktika-liste tbody td:last-child {
		display: block;
		width: auto;
		padding: 0;
		border-bottom: 0;
	}

	/* Der Titel darf hier umbrechen: `nowrap` ist die Regel der
	   Spaltenbreite, und Spalten gibt es in diesem Modus nicht mehr. */
	.praktika-liste tbody td.pl-praktikum {
		grid-column: 1;
		width: auto;
		white-space: normal;
	}

	.praktika-liste tbody td.pl-dauer {
		grid-column: 1;
		font-size: var(--t--2);
		color: var(--text-muted);
	}

	/* Ueber beide Zeilen und oben angeschlagen: der Knopf gehoert zum
	   Titel, nicht zur Mitte des Blocks. */
	.praktika-liste tbody td.pl-aktion {
		grid-column: 2;
		grid-row: 1 / span 2;
		width: auto;
		align-self: start;
	}

	/* Die Flaeche unter dem Zeiger ist die ganze Zeile. */
	.praktika-liste tbody tr:hover {
		background: var(--hover, var(--surface));
	}

	.praktika-liste tbody tr:hover td {
		background: none;
	}
}

/* Unterlagen eines Praktikums nutzen die Breite: Spalten statt einer
   schmalen Liste. */
.beschreibung-dokumente {
	max-width: none;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
	gap: 0 32px;
}

/* Praktikumsseite: Handlung als Zeile über der Tabelle; Gäste sehen einen
   Textlink, keinen Knopf. Text der alten Seite darunter, dann die
   Dokumenttabelle. */
.praktikum-handlung {
	margin: 0 0 16px;
	font-size: var(--t--1);
}

.praktikum-login {
	color: var(--accent-text);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.praktikum-text {
	margin-top: 24px;
	max-width: 72ch;
}

.praktikum-dokumente-titel {
	margin: var(--raum-6) 0 var(--raum-2);
	font-size: var(--t-2);
	font-weight: 600;
}

/* Die Formatmarke hinter einem Dateilink im Fliesstext braucht Abstand. */
.prosa .dateilink-format {
	margin-left: 6px;
}

/* ==========================================================================
   Dialoge: ein Aussehen für alle (Darstellung, Anmeldung, Suche, Login).
   Fläche, 1-px-Linie, Radius, Schatten — und der Hintergrund unscharf.
   Einzige Ausnahme ist «Darstellung»: dort bleibt der Grund scharf und
   ungedimmt, sonst wäre der Theme-Wechsel dahinter nicht zu sehen
   (Abschnitt «Theme-Umschalter» weiter oben).
   ========================================================================== */

dialog::backdrop {
	background: rgba(10, 12, 16, 0.32);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
}

.darstellung,
.anmeldedialog,
.login-dialog,
.suchpalette-fenster {
	background: var(--surface, var(--bg));
	border: 1px solid var(--border);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow);
}

.login-dialog {
	width: min(420px, calc(100vw - 2 * var(--raum-5)));
	max-height: min(88vh, 720px);
	padding: 24px 24px 26px;
	color: var(--text);
	overflow-y: auto;
}

.login-dialog .formular-schmal {
	max-width: none;
}

.login-dialog .feld:last-child {
	margin-bottom: 0;
}

.login-satz {
	margin: 0 0 16px;
	font-size: var(--t--1);
	line-height: 1.5;
	color: var(--text);
}

.login-fehler {
	margin: 0 0 12px;
	font-size: var(--t--1);
	line-height: 1.5;
	color: var(--danger);
}

.login-formular {
	display: grid;
	gap: 14px;
}

.login-formular .feld input {
	height: 40px;
	font-size: var(--t-0);
}

.login-code {
	letter-spacing: 0.12em;
	font-size: 1.05rem;
}

.login-knopf {
	width: 100%;
	height: 40px;
	justify-content: center;
}

.login-alternative {
	margin: 14px 0 0;
	font-size: var(--t--2);
}

.login-alternative a {
	color: var(--text-muted);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.login-alternative a:hover {
	color: var(--text);
}

.login-dialog .dialog-kopf {
	margin-bottom: 16px;
}

.dialog-kopf {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--raum-3);
	margin-bottom: 12px;
}

/* Derselbe Titel wie im Darstellungsdialog: 16/600 (docs/DESIGN.md §6).
   18 px waren eine dritte Groesse neben 15 und 16 — fuer dieselbe Rolle. */
.dialog-titel {
	margin: 0;
	font-size: var(--t-2);
	font-weight: 600;
	line-height: 1.25;
}

@media (prefers-reduced-motion: no-preference) {
	.login-dialog[open],
	.anmeldedialog[open],
	.darstellung[open] {
		animation: dialog-auf 0.14s ease-out;
	}
}

@keyframes dialog-auf {
	from { opacity: 0; transform: translateY(-0.4rem); }
	to   { opacity: 1; transform: none; }
}

/* Theme-Wechsel und Vorschau im Darstellungsdialog: rasch überblenden
   statt hart umschalten. */
@media (prefers-reduced-motion: no-preference) {
	html,
	body,
	.seitenleiste,
	.spalte,
	main#inhalt {
		transition: background-color 0.16s ease, color 0.16s ease;
	}
}

/* In der schwebenden Vorschau zeigt der Pfeil nach rechts: der Knopf
   klappt die Leiste dann bleibend aus. */
[data-leiste="zu"] .leiste-einklappen-pfeil {
	transform: rotate(180deg);
}

/* Ansicht-Schalter im Leistenfuss (nur echte Admins): «Ich», «Gast» oder
   ein Konto — die Seite zeigt dann, was diese Person sieht. */
.leiste-sicht {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 4px 8px 6px;
	font-size: var(--t--2);
	color: var(--text-muted);
}

.leiste-sicht-label {
	flex: none;
}

.leiste-sicht-select {
	flex: 1 1 auto;
	min-width: 0;
	height: 28px;
	padding: 0 6px;
	font: inherit;
	font-size: var(--t--2);
	color: var(--text);
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
}

.leiste-sicht-select:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
}

.sichtband-test {
	color: var(--text-muted);
}

/* ==========================================================================
   Auswahl (site/snippets/auswahl.php): aufklappbare Liste in HTML und CSS.
   Ein Knopf wie ein Feld, darunter die Liste als Fläche mit Schatten.
   ========================================================================== */

.auswahl {
	position: relative;
	display: grid;
	gap: 4px;
	min-width: 0;
}

.auswahl-label {
	font-size: var(--t--2);
	font-weight: 500;
	color: var(--text);
}

.auswahl-knopf {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	width: 100%;
	height: 34px;
	padding: 0 8px 0 10px;
	font: inherit;
	font-size: var(--t--1b);
	text-align: left;
	color: var(--text);
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	cursor: pointer;
}

.auswahl-knopf:hover {
	border-color: var(--text-muted);
}

.auswahl-knopf:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 1px;
}

.auswahl-text {
	min-width: 0;
	overflow-wrap: anywhere;
}

.auswahl-pfeil {
	flex: none;
	width: 14px;
	height: 14px;
	color: var(--text-muted);
	transform: rotate(90deg);
	transition: transform 0.14s ease;
}

.auswahl.ist-offen .auswahl-pfeil {
	transform: rotate(-90deg);
}

.auswahl-liste {
	position: absolute;
	top: calc(100% + 4px);
	left: 0;
	z-index: 40;
	min-width: 100%;
	max-height: 320px;
	overflow-y: auto;
	margin: 0;
	padding: 4px;
	list-style: none;
	background: var(--surface);
	border: 1px solid var(--border);
	border-radius: var(--radius);
	box-shadow: var(--shadow);
}

.auswahl[data-auswahl-oben] .auswahl-liste {
	top: auto;
	bottom: calc(100% + 4px);
}

.auswahl-option {
	padding: 6px 10px;
	border-radius: var(--radius-sm);
	font-size: var(--t--1b);
	line-height: 1.35;
	color: var(--text);
	cursor: pointer;
	white-space: nowrap;
}

.auswahl-option:hover,
.auswahl-option:focus {
	background: var(--hover);
	outline: none;
}

.auswahl-option[aria-selected="true"] {
	color: var(--accent-text);
	font-weight: 500;
}

/* Suchfeld zuoberst: bleibt beim Scrollen der Liste stehen. */
.auswahl-suche {
	position: sticky;
	top: -4px;
	z-index: 1;
	margin: -4px -4px 4px;
	padding: 4px;
	background: var(--surface);
	border-bottom: 1px solid var(--border);
}

.auswahl-suchfeld {
	width: 100%;
	padding: 5px 8px;
	font: inherit;
	font-size: var(--t--1b);
	color: var(--text);
	background: var(--bg);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
}

.auswahl-suchfeld:focus {
	outline: 2px solid var(--accent);
	outline-offset: -1px;
}

.auswahl-gruppe {
	padding: 8px 10px 2px;
	font-size: var(--t--3);
	color: var(--text-muted);
}

.auswahl-gruppe:first-child {
	padding-top: 4px;
}

.auswahl-ersatz {
	margin-top: 4px;
}

/* Im Leistenfuss: kleiner, öffnet nach oben. */
.leiste-sicht .auswahl {
	flex: 1 1 auto;
}

.leiste-sicht .auswahl-knopf {
	height: 28px;
	font-size: var(--t--2);
}

.leiste-sicht .auswahl-option {
	font-size: var(--t--2);
}

/* Filterzeile der Korrekturen: Felder nebeneinander, kein Knopf «Filtern». */
.korrekturen-filter {
	display: flex;
	flex-wrap: wrap;
	align-items: end;
	gap: 12px 16px;
	margin: 0 0 16px;
}

.korrekturen-filter .auswahl {
	min-width: 220px;
}

/* Mono nur in code, pre, kbd (DESIGN.md §3). Die Klasse .mono aus den
   Verwaltungsseiten bleibt in der Grundschrift, tabellarische Ziffern. */
.mono {
	font-family: inherit;
	font-size: inherit;
	font-variant-numeric: tabular-nums;
}

/* Korrekturen-Filter: Knopf und Links stehen auf der Grundlinie der Felder. */
.korrekturen-filter {
	align-items: flex-end;
}

.korrekturen-filter > .knopf,
.korrekturen-filter > a {
	align-self: flex-end;
	display: inline-flex;
	align-items: center;
	height: 34px;
	margin: 0;
}

/* Tief- und Hochstellung (fdcFormel): ohne die Zeilenhöhe zu verändern. */
sub, sup {
	font-size: 0.72em;
	line-height: 0;
	position: relative;
	vertical-align: baseline;
}

sub { bottom: -0.22em; }
sup { top: -0.5em; }

.katex { font-size: 1.05em; }

/* Übungen auf der Kursseite: dieselbe Tabelle wie die Termine darüber. */
.kurs-uebungen {
	margin-top: 32px;
}

.kurs-uebungen .ku-titel {
	font-weight: 500;
	color: var(--text);
	text-decoration: none;
}

.kurs-uebungen .ku-titel:hover {
	text-decoration: underline;
}

.kurs-uebungen .ku-rest {
	display: block;
	font-size: var(--t--2);
	color: var(--text-muted);
}

/* Status einer Abgabe als Wort, nicht als Pille (DESIGN.md §1). Gilt
   auf Kursseite, Mein Bereich und Übungsseite gleichermassen. Farbe
   trägt die Bedeutung: grün erledigt, gelb wartet, rot fehlt. */

.status-marke,
a.status-marke {
	display: inline;
	padding: 0;
	border: 0;
	border-radius: 0;
	background: none;
	font-size: var(--t--1);
	font-weight: 500;
	line-height: 1.4;
	color: var(--text-muted);
	text-decoration: none;
	white-space: nowrap;
}

a.status-marke:hover {
	text-decoration: underline;
}

.status-marke.status-eingereicht,
.status-marke.status-ueberarbeitung-eingereicht,
.status-marke.status-verspaetet {
	color: var(--warn, #7A5A12);
}

.status-marke.status-ueberarbeitung,
.status-marke.status-nicht-erfolgreich,
.status-marke.status-nicht-eingereicht {
	color: var(--danger);
}

.status-marke.status-erledigt {
	color: var(--ok, #1F6F4A);
}

.status-marke.status-offen {
	color: var(--text-muted);
}

.status-runde {
	font-size: 0.85em;
	color: var(--text-muted);
}


/* Startseite: Dashboard für Studierende (Übungen, Termine) und Admin
   (Zu korrigieren, Termine) – dieselben Tabellen wie überall. */
.dash {
	margin: 0 0 32px;
}

.dash-kopf {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 8px;
}

.dash-kopf h2 {
	margin: 0;
}

.dash-link {
	font-size: var(--t--2);
	color: var(--text-muted);
}

.dash-tabelle {
	table-layout: fixed;
	width: 100%;
}

.dash-titel {
	font-weight: 500;
	color: var(--text);
	text-decoration: none;
}

.dash-titel:hover {
	text-decoration: underline;
}

.dash-rest {
	display: block;
	font-size: var(--t--2);
	color: var(--text-muted);
}

.dash-rest.ist-abgelaufen {
	color: var(--danger);
}

.dash-aktion {
	text-align: right;
}

/* Tabellen der Arbeitsorte (Meine Kurse, Verwaltung): Namen und Titel
   brechen nicht um, sie werden gekürzt und stehen ganz im title-Attribut. */
.zelle-knapp {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Eine Auswahl (Semester, Status) rechts über der Tabelle. */
.kopf-auswahl {
	display: flex;
	justify-content: flex-end;
	margin: 0 0 var(--raum-3);
}

/* Schmal (Handy): die festen Spalten der Startseitentabellen liefen
   bei 390 px ineinander (Datum über dem Titel, Kurs über der Frist).
   Unter 600 px Inhaltsbreite wird jede Zeile ein Block: erste Zelle
   leise darüber, die übrigen darunter; die Kopfzeile entfällt. */
@container inhalt (max-width: 600px) {
	.dash-tabelle,
	.dash-tabelle tbody,
	.dash-tabelle tr,
	.dash-tabelle td {
		display: block;
		width: auto;
	}

	.dash-tabelle thead,
	.dash-tabelle colgroup {
		display: none;
	}

	.dash-tabelle tr {
		padding: 8px 0;
		border-bottom: 1px solid var(--border);
	}

	.dash-tabelle td,
	.tabelle.dash-tabelle td.dash-kurs {
		padding: 0;
		border: 0;
		text-align: left;
	}

	.dash-tabelle td:first-child:not(:has(.dash-titel)) {
		font-size: var(--t--2);
		color: var(--text-muted);
	}
}

/* Die Kursspalte der Terminliste endet an der Linie: linksbündig blieb
   zwischen Link und Zellenkante ein Streifen von 153 px bei 1440 und
   483 px bei 2560 (Befund B11). Die Zelle hat rechts kein Polster
   (`.tabelle td:last-child`), der Link steht also genau auf der
   Kante. Der Selektor trägt `.tabelle td` mit, weil die Grundregel
   `.tabelle td { text-align: left }` sonst gewichtiger wäre. */
.tabelle td.dash-kurs {
	text-align: right;
}

/* ==========================================================================
   Inhaltsdarstellung: Rollen, Faktenspalte, gedeckelte Tabellen
   (Befunde 4, 13, 19, 20, 21 des Site-Reviews vom 14.09.2026)

   Angehängt statt eingefügt, damit an den bestehenden Zeilen nichts
   verrutscht. Alles hier ist Mass und Anordnung — keine neue Fläche,
   kein Kasten, keine zweite Farbe.
   ========================================================================== */

/* ---- Personen: eine Zeile je Rolle ------------------------------------- */

/* `Funktion` ist mehrzeilig. In der Übersicht standen die Zeilen bisher in
   EINEM <span> und verklebten zu einem unsinnigen Satz. Jetzt steht jede
   Rolle auf ihrer Zeile — dieselbe Klasse und dieselbe Form wie auf der
   Startseite. */
.seitenliste .personen-rolle {
	margin-top: 2px;
	color: var(--text-faint);
}

/* ---- Personenseite: Angaben als Faktenspalte ---------------------------- */

/* Das Porträt ist ein Bild, kein Aufmacher: in der Faktenspalte füllt es
   deren Breite, allein stehend bleibt es bei Lesebreite. */
.person-angaben .portraet {
	max-width: 240px;
	margin-top: var(--raum-4);
}

.zweispalt-fakten.person-angaben .portraet {
	max-width: none;
	margin-top: 0;
}

/* In der schmalen Spalte trägt der Rollenblock die Textgrösse der Spalte,
   nicht die der Hauptspalte. */
.zweispalt-fakten.person-angaben .funktion p {
	font-size: var(--t--1);
}

/* ---- Übung: Teilnehmerliste und Bilanz nebeneinander -------------------- */

/* Sechs Spalten mit «—» in jeder Zeile sind keine Tabelle, sondern ein
   leeres Raster; welche Spalten erscheinen, entscheidet jetzt der Bestand
   (site/templates/uebung.php). Was bleibt, braucht keine 2100 px: die
   Tabelle nimmt, was sie braucht, und die Bilanz stellt sich daneben. */
.teilnehmende-raster {
	display: grid;
	gap: var(--raum-5);
	align-items: start;
}

.tabelle-teilnehmende {
	max-width: 900px;
}

@container inhalt (min-width: 980px) {
	.teilnehmende-raster {
		/* Die Tabelle nimmt, was sie braucht (Deckel 900 px, oben); die
		   Bilanz stellt sich unmittelbar daneben, nicht an den Rand
		   einer leeren Spalte. */
		grid-template-columns: minmax(0, max-content) minmax(200px, 280px);
		column-gap: var(--raum-7);
		justify-content: start;
	}

	.teilnehmende-raster .kursstand-gesamt {
		margin-top: 0;
	}
}

/* ---- Listen der Verwaltung: Lesebreite statt Fensterbreite -------------- */

/* Ein Tabellenkopf, der über 2100 px läuft, ist keine Zeile mehr, sondern
   eine Strecke. Vier bis sieben Spalten brauchen keine. */
.tabelle-anfragen {
	max-width: 1100px;
}

.tabelle-abgaben {
	max-width: 720px;
}

/* Abgaben: je Person ein Block. Auf breiten Schirmen stehen sie
   nebeneinander, statt sich zu einer Spalte aufzureihen. */
.abgaben-raster {
	display: grid;
	gap: var(--raum-6) var(--raum-7);
	grid-template-columns: repeat(auto-fill, minmax(320px, 520px));
	justify-content: start;
	align-items: start;
}

/* Eingang: «Anfragen» und «Neueste Abgaben» sind zwei Listen — auf einem
   breiten Schirm stehen sie nebeneinander, nicht untereinander. */
.eingang-raster {
	display: grid;
	gap: var(--raum-6);
	align-items: start;
}

@container inhalt (min-width: 1180px) {
	.eingang-raster {
		grid-template-columns: minmax(0, 1fr) minmax(280px, 420px);
		column-gap: var(--raum-7);
	}
}

/* ==========================================================================
   Eingabefelder auf dem Telefon: mindestens 16 px (Befund B74)

   Safari auf iOS und iPadOS zoomt beim Fokus in jedes Textfeld unter
   16 px in die Seite hinein — und zoomt danach nicht von selbst zurueck.
   Einmal in die Suche getippt, und die Seite steht schief, bis man sie
   von Hand zurechtzieht. `max(16px, …)` ist damit die einzige feste
   Pixelzahl dieser Datei: sie steht nicht fuer eine Gestaltung, sondern
   begegnet dem iOS-Zoom. Waechst die Skala je ueber 16 px, hat sie
   weiterhin den Vortritt.

   Die Regel steht am Schluss der Datei, damit sie die spaeter notierten
   Feldgrade (`.start-suche input` im 560-px-Fenster) sicher ueberschreibt;
   `.login-formular .feld input` setzt einen eigenen Grad mit hoeherer
   Gewichtung und steht darum ausdruecklich mit im Selektor.
   ========================================================================== */

@media (max-width: 700px) {
	input[type="text"],
	input[type="email"],
	input[type="password"],
	input[type="search"],
	input[type="url"],
	input[type="number"],
	input[type="date"],
	textarea,
	select,
	.feld input,
	.feld textarea,
	.feld select,
	.start-suche input,
	.login-formular .feld input {
		font-size: max(16px, var(--t--1));
	}

	/* Der Grad waechst, der Kasten darf mitwachsen: eine feste Hoehe
	   schnitte den Text sonst an. Das bisherige Mass bleibt die
	   Untergrenze, damit kein Feld kleiner wird als vorher. */
	input[type="text"],
	input[type="email"],
	input[type="password"],
	input[type="search"],
	input[type="url"],
	input[type="number"],
	input[type="date"],
	select,
	.feld input,
	.feld select,
	.login-formular .feld input {
		height: auto;
		min-height: 34px;
	}

	.start-suche input {
		min-height: 46px;
	}

	.login-formular .feld input {
		min-height: 40px;
	}
}

/* Übersicht und Organisatorisches: dieselbe kompakte Dokumentbox. */
.dokumentbox {
	margin-block: 6px;
	padding: 4px 6px;
	border: 1px solid var(--border);
	border-radius: var(--radius);
	background: var(--surface);
	overflow-x: auto;
}
.dokumentbox table {
	width: 100%;
	border-collapse: collapse;
	text-align: left;
	font-size: var(--t--1);
	line-height: 1.4;
}
.dokumentbox th,
.dokumentbox td {
	padding: 5px 8px;
	vertical-align: middle;
}
.dokumentbox th {
	padding-block: 3px;
	font-size: var(--t--2);
	font-weight: 400;
	color: var(--text-muted);
	white-space: nowrap;
}
.dokumentbox tbody tr { height: 32px; }
.dokumentbox tbody tr:hover { background: var(--hover, var(--surface-2)); }
.dokumentbox-titel { width: 100%; min-width: 13rem; }
.dokumentbox a { color: var(--text); text-decoration: none; }
.dokumentbox a:hover { color: var(--link); text-decoration: underline; }
.dokumentbox-titel a { font-weight: 500; }
.dokumentbox-typ,
.dokumentbox-autor,
.dokumentbox-groesse { color: var(--text-muted); font-size: var(--t--2); }
.dokumentbox-typ span { display: flex; align-items: center; gap: var(--raum-2); }
.dokumentbox-typ .icon { width: 16px; height: 16px; flex: none; color: var(--text); }
.dokumentbox-autor { min-width: 9rem; }
.dokumentbox-formate,
.dokumentbox-groesse { white-space: nowrap; text-align: right; }
.dokumentbox-formate a + a { margin-left: var(--raum-2); }
@media (max-width: 600px) {
	.dokumentbox { padding-inline: var(--raum-1); }
	.dokumentbox th, .dokumentbox td { padding-inline: var(--raum-2); }
}

/* Kompakter Vorlesungskopf; die Themenseiten behalten ihre Abstände. */
.spalte:has(.kurs-kopf) > .inhalt { padding-top: var(--raum-6); }
.inhalt .kurs-organisatorisches > h2 { margin-top: 0; margin-bottom: 4px; }
.kurs-organisatorisches > * + * { margin-top: 6px; }
.kurs-organisatorisches .prosa > * + * { margin-top: 8px; }
.kurs-organisatorisches .dokumentbox { margin-bottom: 0; }
.kurs-uebungen { scroll-margin-top: 20px; }
/* Terminansicht und Übungen schalten gemeinsam um. */
.kurs-plan > * + * { margin-top: var(--raum-6); }
.kurs-plan > .termine,
.kurs-plan > .kurs-uebungen { min-width: 0; }
.kurs-tabellentitel { margin: 0 0 var(--raum-4); }
@media (min-width: 901px) {
	/* Exakte Hälften, unabhängig von der Breite der jeweiligen Datumsspur. */
	.kurs-plan .termine-raster {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		--raster-abstand: var(--raum-5);
	}
	.kurs-plan .termine-raster > .termine-zelle {
		grid-template-columns: max-content minmax(0, 1fr);
	}
	.kurs-plan .termine-raster > .termine-zelle:nth-child(odd) {
		grid-column: 1;
		margin-right: var(--raster-abstand);
	}
	.kurs-plan .termine-raster > .termine-zelle:nth-child(even) {
		grid-column: 2;
		padding-left: var(--raster-abstand);
	}
	.kurs-plan .termine-raster > .termine-zelle:nth-child(even)::after {
		inset-inline-start: var(--raster-abstand);
	}
}
@container inhalt (min-width: 850px) {
	.kurs-plan[data-kurs-ansicht="tabelle"]:has(> .termine):has(> .kurs-uebungen) {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		align-items: start;
	}
	.kurs-plan[data-kurs-ansicht="tabelle"]:has(> .kurs-uebungen) > .termine { display: contents; }
	.kurs-plan[data-kurs-ansicht="tabelle"]:has(> .kurs-uebungen) > .termine > .termine-kopf {
		grid-column: 1 / -1;
	}
	.kurs-plan[data-kurs-ansicht="tabelle"]:has(> .kurs-uebungen) > .termine > [data-ansicht-inhalt="tabelle"] {
		grid-column: 1;
		grid-row: 2;
		margin: 0 var(--raum-5) 0 0;
		min-width: 0;
	}
	.kurs-plan[data-kurs-ansicht="tabelle"]:has(> .termine) > .kurs-uebungen {
		grid-column: 2;
		grid-row: 2;
		margin: 0;
		padding-left: var(--raum-5);
		border-left: 1px solid var(--border);
		align-self: stretch;
	}
}
@media (min-width: 1920px) {
	.kurs-plan .termine-raster { --raster-abstand: var(--raum-7); }
}
.kurs-uebungen-pfeil {
	position: fixed;
	top: 24px;
	right: 22px;
	z-index: 20;
	display: grid;
	place-items: center;
	width: 38px;
	height: 38px;
	border: 1px solid var(--border);
	border-radius: 50%;
	background: var(--bg);
	color: var(--accent-text, var(--link));
	box-shadow: 0 2px 10px rgb(0 0 0 / 8%);
	text-decoration: none;
}
.kurs-uebungen-pfeil .icon {
	width: 20px;
	height: 20px;
	transform: rotate(90deg);
	animation: kurs-pfeil-puls 3s ease-in-out infinite;
}
.kurs-uebungen-pfeil[hidden] { display: none; }
.kurs-uebungen-pfeil:hover { background: var(--surface); }
.kurs-uebungen-pfeil:focus-visible { outline: 2px solid var(--link); outline-offset: 3px; }
@keyframes kurs-pfeil-puls {
	0%, 100% { opacity: .6; transform: translateY(-1px) rotate(90deg); }
	50% { opacity: 1; transform: translateY(2px) rotate(90deg); }
}
@media (max-width: 900px) {
	.kurs-uebungen-pfeil { top: 64px; right: 14px; }
	.spalte:has(.kurs-kopf) .titelband-innen { padding-right: 44px; }
}
@media (prefers-reduced-motion: reduce) {
	.kurs-uebungen-pfeil .icon { animation: none; }
}
