/* Farbpalette und Maße der Oberfläche ------------------------------------------------------------
 *
 * Zentral definiert, weil dieselben Werte sonst über das ganze Stylesheet verstreut wären (vor der
 * Vereinheitlichung stand allein die alte Grundfarbe an 47 Stellen). Wer die Optik nachjustieren will,
 * ändert hier eine Zeile statt dutzender.
 *
 * Die Formensprache stammt aus dem TMDB-Bereich und gilt seitdem für die ganze Anwendung: Bedienelemente mit
 * Beschriftung sind Pillen, reine Icon-Schaltflächen sind Kreise, beide gleich hoch (--control-height). */
:root {
	/* Bedienelemente (Schaltflächen, Menüs, Formularelemente) */
	--control-bg:              #1b2b52;
	--control-border:          #4a70b0;
	--control-text:            #cfe0f5;
	/* Die "hover"-Stufe trägt den Namen nur noch aus historischen Gründen: Sie steht inzwischen für "hervorgehoben"
	   und wird von .active (gewähltes Segment, offene Filterleiste) und von :active (gedrückt) genutzt. Echte
	   Hover-Effekte gibt es außer beim Tooltip keine mehr - warum, steht bei [data-tooltip]. */
	--control-bg-hover:        #2a4383;
	--control-border-hover:    #7aa0e0;
	--control-text-hover:      #fff;
	--control-bg-disabled:     #16203a;
	--control-border-disabled: #2a3a5a;
	--control-text-disabled:   #667;
	--control-height:           2rem;
	--control-height-small:     1.6rem; /* kompakte Variante für dichte Zeilen, siehe .miniBtn */
	--control-radius:           999px;
	/* Eingabe- und Auswahlfelder sind bewusst nur abgerundet statt voll rund: in einer Pille liefe der Text in die
	   runden Enden, was bei langen Eingaben (Suche, Pfade, Textbereiche) schlecht zu lesen ist. Die Höhe teilen sie
	   sich dagegen mit den Schaltflächen, damit gemischte Zeilen fluchten. */
	--field-radius:             8px;

	/* Flächen */
	/* Seitenhintergrund. Wie --surface auf dem Blauton der Bedienelemente (223°), nur dunkler und schwächer
	   gesättigt: das alte #003 lag bei 240° und voller Sättigung und stach damit aus der Familie heraus - die
	   entsättigten Kacheln und Karten darauf wirkten grau statt zugehörig. */
	--page-bg:        #0d1426;
	/* Karten, Kacheln und Formulare. Die Helligkeit ist bewusst deutlich unter der von --control-bg: bei
	   annähernd gleicher Helligkeit (vorher 20% gegen 21%) heben sich Felder und Schaltflächen darauf nur noch
	   durch ihren Rahmen ab, das Formular wirkt flach und die Elemente aufgeklebt. So entsteht eine Staffelung
	   Seite (10%) - Fläche (15%) - Bedienelement (21%). Der Farbton folgt dem der Bedienelemente (223°); vorher
	   lag er bei 240° und damit sichtbar in einer anderen Farbfamilie. */
	--surface:        #172036;
	--surface-raised: #1b2b52; /* Aufliegendes ohne eigene Bedienelemente: Menüs */
	/* Dialoge liegen dunkler als die Bedienelemente darin - dieselbe Beziehung wie auf der Seite, wo Felder und
	   Schaltflächen ebenfalls heller als ihr Untergrund sind. Ein heller Dialogkörper wäre bei großen Dialogen
	   (Trefferliste, Tabelle) eine grelle Fläche mit zu wenig Kontrast zum Inhalt. Etwas heller als die Seite
	   bleibt er trotzdem, damit er sich als aufliegend abhebt. */
	--surface-dialog: #111d3d;

	/* Linien und große Flächen sind bewusst deutlich weniger gesättigt als die Bedienelemente: derselbe kräftige
	   Blauton, der einen 2rem großen Button trägt, wirkt über eine ganze Seitenkante oder einen Tabellenkopf
	   gezogen grell. Die kleinen Elemente behalten ihn (--control-border, 41% Sättigung), die Struktur liegt bei
	   rund 21% - dem Niveau, das die Anwendung vor der Vereinheitlichung hatte.
	   --line trägt die sichtbare Struktur (Seitenkopf, Seitenleiste, Trenner), --line-subtle die Andeutung einer
	   Kante innerhalb einer Fläche (Kachelrahmen). */
	--line:        #5f6e91;
	--line-subtle: rgba(102,153,221,0.25);
	/* Tabellen bekommen eine neutrale Linie statt einer blauen: eine Aufnahme- oder EPG-Liste besteht aus sehr
	   vielen Linien, in der Bereichsfarbe würde die Seite blaustichig. */
	--line-table:  #999;
	/* Band für dauerhaft sichtbare Flächen: Dialog-Kopfzeile, Akkordeon-Köpfe. Bewusst nicht --control-bg-hover,
	   obwohl das farblich naheläge: dieser Ton ist für kleine, kurz sichtbare Zustände gedacht (ein Element unter
	   dem Mauszeiger, ein gewähltes Segment). Über ein breites, dauerhaft stehendes Band gezogen wirkt seine hohe
	   Sättigung laut - im Textfilter-Dialog stapeln sich gleich mehrere davon. */
	--surface-band: #424c67;

	/* Band des Tabellenkopfs, samt Schriftfarbe darauf: dieselbe Fläche wie die Bedienelemente, damit der Kopf
	   nicht als dritter Farbton neben Fläche und Schaltflächen steht. Die Schrift ist bewusst fast weiß und nicht
	   --control-text, das hellblau ist und dem Kopf einen Blaustich gab. */
	--table-header-bg:   #1b2b52;
	--table-header-text: #f2f2f2;

	/* Text */
	--text:        #ddd;
	--text-muted:  #aaa;
	/* Nur für Zeichen, die zurücktreten sollen, statt gelesen zu werden: Platzhalter-Symbole auf leeren Postern
	   und Folgenbildern, ausgegraute Blätterpfeile. Bewusst kein Grau, sondern der Blauton der Familie (223°). */
	--text-faint:  #555e77;

	/* Bedeutungsfarben - sie tragen eine Aussage und folgen deshalb nicht der Bereichsfarbe:
	   blau "gesammelt", grün "gesehen", lila "Filmreihe", gelb "Bewertung". */
	--accent-collected:  #6af;
	--accent-watched:    #6c6;
	--accent-collection: #cae;
	--accent-rating:     #fc6;
	/* Rot für die Merkliste des Streaming-Portals - das Herz kennt man von anderen Diensten in genau dieser Farbe,
	   und keine der vier darüber ist noch frei (siehe inc/tmdbMeta.html#watchlistHeart). */
	--accent-watchlist:  #e5566b;

	/* Bereichsgruppen. Dieselbe Einteilung trägt die Startseite (Beschriftungsbalken der Gruppenkacheln) und die
	   Seitenleiste (Streifen an der Gruppenkante), damit ein Bereich überall dieselbe Farbe hat. Bewusst gedeckt
	   und nur als schmaler Streifen eingesetzt: über größere Flächen gezogen würde die Anwendung bunt. */
	--group-recording: #46698a;
	--group-mediathek: #4a7a5f;
	--group-misc:      #6b6350;
	/* Aufgehellte Fassungen für den aktiven Eintrag im Flyout (Variante B): derselbe Farbton, nur deutlich heller,
	   damit die Gruppe erkennbar bleibt und die Markierung trotzdem heraussticht. */
	--group-recording-bright: #7aa9d8;
	--group-mediathek-bright: #74bd93;
	--group-misc-bright:      #b8a87e;

	/* Karteireiter auf der Startseite: die Bereichsmarke (siehe .homeRowsLabel) und die Überschrift jeder Reihe
	   (siehe .homeCardRows h3). Gleiche Form, unterschiedliche Farbe - allein daran hängt die Rangfolge, denn
	   nebeneinandergestellt sähen zwei graue Reiter gleichrangig aus. Der Bereich trägt deshalb das Grün seiner
	   Gruppe, die Reihen darunter das neutrale Grau der Trenner. */
	--home-label-color:     var(--group-mediathek);
	--home-row-label-color: var(--line);

	/* Markierung der TEST-Instanz im Logo (siehe .testTag): bewusst ein Farbton, der in keiner der Gruppen- oder
	   Bedeutungsfarben oben vorkommt, damit er nicht mit einer von ihnen verwechselt wird. */
	--test-tag-color: #f0a030;
}

/* Das hidden-Attribut blendet immer aus. Der Browser setzt es nur mit einer schwachen Grundregel um, und jede Klasse mit
   eigenem display (.defaultBtn: inline-flex, Zeilen mit flex) schlug es - bis zum 28.09.2026 standen dafür rund
   zwanzig Einzelregeln .xyz[hidden] { display: none } im Stylesheet, jede nachgeschoben, nachdem es aufgefallen war.
   Die Folge dieser Regel: Ein Element mit hidden lässt sich nicht mehr per jQuery .show()/.toggle()/slideToggle()
   einblenden - das hebelte hidden nur über ein direkt gesetztes display aus. Umgeschaltet wird mit
   .prop("hidden", …); siehe CLAUDE.md. */
[hidden] {
	display: none !important;
}

/* Die Füllfläche der Duotone-Icons (::before) setzt Phosphor auf 20 % der Symbolfarbe - auf dem dunkelblauen
   Hintergrund ist sie damit kaum zu sehen. all.css wird nach dieser Datei geladen, daher der spezifischere
   Selektor (i + Attribut) statt einer schlichten .ph-duotone::before-Regel. */
i.ph-duotone[class*="ph-"]::before {
	opacity: 0.35;
}

html {
	box-sizing: border-box;
	/* Die Kopfzeile liegt fest über dem Inhalt (siehe "Header"). Ohne diese Zeile landete jedes per Anker
	   angesprungene Ziel dahinter - gemessen: Überschrift bei y=0 unter einer 64px hohen Kopfzeile. scroll-padding
	   gehört an den Scroll-Container und gilt damit für die ganze Anwendung; scroll-margin an jedem einzelnen Ziel
	   wäre dasselbe in mühsam, und man vergisst es beim nächsten Anker. Gilt auch für scrollIntoView, also z.B. für
	   die Sprungmarken der Suche.

	   .tmdbEpisodeCard trug das früher selbst (4,5rem) und hat es hierfür abgegeben: Beides zusammen addierte sich,
	   die angesprungene Folge landete 152px statt 80px unter dem Rand. Gescrollt wird auf allen geprüften Seiten und
	   Breiten das html-Element, eine Regel dort genügt also. */
	scroll-padding-top: 5rem;
}

/* Inherit box-sizing */
*, *::before, *::after {
	box-sizing: inherit;
}

body {
	background: var(--page-bg);
	color: #ddd;
	font-family: Verdana, sans-serif;
	margin: 0;
}

a {
	color: #fff;
	text-decoration: none;
}

/* Header --------------------------------------------------------------------------------------- */

header {
	align-items: center;
	background: linear-gradient(180deg, var(--page-bg), var(--surface));
	border-bottom: 1px solid var(--line);
	display: flex;
	gap: 1rem;
	height: 4rem;
	padding: 0;
	position: fixed;
	top: 0;
	width: 100%;
	z-index: 10;
}

.menuBtn {
	align-items: center;
	background: transparent;
	border: none;
	border-right: 1px solid var(--line);
	color: #aaa;
	cursor: pointer;
	display: flex;
	flex-direction: column;
	flex-shrink: 0;
	font-size: 1.5rem;
	height: 4rem;
	justify-content: center;
	margin: 0;
	padding: 0;
	transition: width 0.3s ease;
	width: 5.5rem;
}

.menuBtn:active {
	color: #fff;
}

.menuBtn .label {
	font-size: 0.7rem;
	margin-top: 0.2em;
}

h1 {
	font-size: 2em;
	margin: 0;
	width: fit-content;
}

.logo {
	display: block;
	font-size: 1rem; /* Anker für .testTag, das relativ dazu (em) skaliert - siehe dort */
	height: 3rem;
	margin: 0;
	position: relative; /* Anker für .testTag */
}

.logo img {
	height: 100%;
}

/* Kennzeichnet die TEST-Instanz (siehe testInstance im Template-Kontext, TemplateEngine.evaluate) direkt im Logo,
   damit auf Tablet/Handy sofort erkennbar ist, in welcher der beiden Instanzen man sich befindet. Bewusst außerhalb
   des Flex-Flusses der Kopfzeile (position: absolute statt eines echten Flex-Kindes): .globalActions ist auf
   schmalen Viewports bereits sehr eng bemessen (siehe dortige Regeln unter max-width: 640px), ein zusätzliches
   Element im normalen Fluss würde ihr dort Platz wegnehmen. em-Größe statt rem, damit das Tag automatisch mit
   .logo (und dessen eigenem font-size) mitschrumpft, ohne eine eigene Media-Query zu brauchen. pointer-events: none,
   damit das Tag den Klick auf das Logo (Link zur Startseite) an keiner Stelle blockiert.
   Verankert ist es an oben/rechts, nicht an unten/links: so wächst es bei einer Änderung der Schriftgröße nach
   unten und nach links ins Wort hinein, statt oben aus der Kopfzeile herauszulaufen. */
.testTag {
	background: var(--test-tag-color);
	border-radius: var(--control-radius);
	color: #1b1204;
	display: inline-block;
	font-size: 0.78em;
	font-weight: bold;
	letter-spacing: 0.03em;
	line-height: 1;
	padding: 0.15em 0.5em;
	pointer-events: none;
	position: absolute;
	right: 0.2em;
	top: -0.15em;
	white-space: nowrap;
}

/* "TEST" steht in Großbuchstaben und hat damit keine Unterlängen - die Zeilenbox reserviert darunter trotzdem
   Platz dafür, weshalb die Schrift in der Pille sichtbar zu hoch sitzt (gemessen 1,88px bei 12,89px Pillenhöhe).
   align-items: center hilft dagegen nicht: zentriert wird die Zeilenbox, und die enthält den leeren Raum bereits.
   text-box-trim schneidet die Box stattdessen auf Versalhöhe bis Grundlinie zu, sodass das symmetrische Padding
   die tatsächlichen Buchstaben zentriert (gemessen 0,13px Restabweichung). Weil dabei rein geometrisch nach den
   Schriftmetriken geschnitten wird, gilt das für jede Schrift - wichtig, weil Verdana nicht überall vorhanden ist
   und der Ersatz andere Metriken mitbringt.
   Das größere Padding gleicht die weggeschnittene Höhe wieder aus, damit die Pille gleich groß bleibt; beides
   steht deshalb zusammen im @supports und nicht in der Regel oben - Browser ohne text-box-trim bekämen sonst eine
   zu hohe Pille. */
@supports (text-box-trim: trim-both) {
	.testTag {
		padding: 0.28em 0.5em;
		text-box: trim-both cap alphabetic;
	}
}

/* Die Gruppe spannt den freien Bereich zwischen Logo und rechtem Rand auf, damit der "Jetzt läuft"-Kasten ihn
   breit ausfüllen kann. Die Rechtsbündigkeit kommt deshalb aus justify-content und nicht mehr aus margin-left:auto:
   sie hängt so an einer Eigenschaft des immer vorhandenen Containers statt an einer Auto-Margin eines Kindes, das
   es nur gibt, wenn gerade etwas läuft. Sonst säßen die festen Schaltflächen je nach Wiedergabezustand woanders. */
.globalActions {
	align-items: center;
	display: flex;
	flex: 1 1 auto;
	gap: 0.5em;
	height: 100%;
	justify-content: flex-end;
	min-width: 0;
	padding-right: 1em;
}

/* Alle Symbole der Kopfzeile gleich groß. Die beiden Flyout-Auslöser müssen ausdrücklich mit aufgeführt werden:
   sie sind .iconBtn und keine .rcBtn, und ihre eigenen Regeln setzen "font-size: inherit", damit sie sich ihrem
   jeweiligen Einsatzort anpassen - hier ist dieser Einsatzort genau diese Regel. */
.globalActions .rcPower,
.globalActions .rcMute,
.globalActions .nowPlayingToggle,
.globalActions .quickAccessToggle,
.globalActions .searchToggle,
.globalActions .toggleRemote,
.globalActions .gotoRemote {
	font-size: 2.5em;
}

/* Die aktive Box ist im Standby (siehe base.html) - rein farblicher Hinweis, sonst bleiben die Knöpfe unverändert
   bedienbar (z.B. um die Box per rcPower wieder aufzuwecken).
   Die Fernbedienung steht hier zweimal, und beide müssen aufgeführt sein: Breit klappt .toggleRemote sie ein und
   aus, schmal führt .gotoRemote auf die eigene Seite (siehe base.html und die Media Query weiter unten). Nur die
   erste zu dämpfen hieß, dass dasselbe Symbol auf dem Handy weiß blieb, während Ein/Aus daneben grau war. */
.globalActions.boxInStandby .rcPower,
.globalActions.boxInStandby .rcMute,
.globalActions.boxInStandby .toggleRemote,
.globalActions.boxInStandby .gotoRemote,
.globalActions.boxInStandby .quickAccessToggle {
	color: var(--text-faint);
}

/* Im Schnellzugriff ist aber nur EIN Knopf je Zeile von der Box abhängig: Gestreamt wird unmittelbar vom NAS, das
   läuft auch bei schlafender Box weiter (siehe de.keks.stream). Gedämpft wird deshalb nur das Abspielen - der
   Auslöser oben sagt "die Box schläft", hier drin steht, was das konkret heißt.
   Vier Klassen, damit ".actions .moreFlyout button { color: white }" sicher geschlagen wird. */
.globalActions.boxInStandby .quickAccessRow .playMovie {
	color: var(--text-faint);
}

/* Ohne Flex sitzen die Glyphen rund 4px zu hoch in ihren Schaltflächen: die Zeilenbox reserviert unter der Glyphe
   Platz für Unterlängen, den ein Symbol nicht braucht. Die Schaltflächen selbst stehen dabei mittig - nur ihr
   Inhalt nicht. Gleiches Vorgehen wie bei .infoBar .iconBtn.
   Die Regel muss VOR den display-Regeln der beiden Fernbedienungs-Schaltflächen stehen: sie hat dieselbe
   Spezifität wie diese, und bei Gleichstand gewinnt die spätere - andernfalls hebt sie deren "display: none" auf
   und das Symbol erscheint doppelt. */
.globalActions .iconBtn {
	align-items: center;
	display: inline-flex;
	justify-content: center;
}

.globalActions .gotoRemote {
	display: none;
}

.globalActions .toggleRemote.active,
.globalActions .gotoRemote.active {
	color: #6af;
}

/* Auf dem Handy fällt "Stumm" aus der Kopfzeile: Dort ist der Platz zwischen Logo und rechter Gruppe am knappsten,
   und von allen Symbolen dort ist es das am wenigsten gebrauchte - stummschalten lässt sich die Box weiterhin über
   die Fernbedienung (dieselbe Taste, siehe remote.html). Ein-/Ausschalten und Fernbedienung bleiben.
   Die Regel steht NACH ".globalActions .iconBtn": Sie hat dieselbe Spezifität, und eine Media Query ändert daran
   nichts - weiter oben verlöre sie und der Knopf bliebe stehen (nachgemessen, genau wie bei .nowPlayingToggle). */
@media (max-width: 480px) {
	.globalActions .rcMute {
		display: none;
	}

	/* Und ebenso der Schnellzugriff: Hier ist die Kopfzeile am engsten, und sein Menü ist das breiteste von allen
	   (Titel plus vier Symbole je Zeile). Wer das Handy hochkant hält, kommt über die Suche oder die Mediathek an
	   dieselbe Aufnahme - quer gedreht steht er wieder da, ohne dass die Seite neu gebaut werden muss. */
	.globalActions .quickAccessActions {
		display: none;
	}
}

/* Suchleiste in der Kopfzeile -------------------------------------------------------------------- */

/* Sie legt sich über die Kopfzeile, statt sich in sie hineinzuschieben: Ab 1025px belegt der "Jetzt läuft"-Kasten
   den freien Platz, darunter gibt es ohnehin keinen. z-index über dem Header (10), damit Menüknopf, Logo und
   Aktionen wirklich verdeckt sind - eine halb sichtbare Kopfzeile darunter läse sich wie ein Fehler. */
.searchBar {
	background: var(--surface);
	border-bottom: 1px solid var(--line);
	left: 0;
	position: fixed;
	right: 0;
	top: 0;
	z-index: 11;
}

.searchBarRow {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	height: 4rem;
	padding: 0 0.8rem;
}

/* Der aktive Umschalter der Suchleiste trägt den Ton, den die Anwendung überall für "gewählt" benutzt (siehe
   --control-bg-hover), damit er sich von den beiden Schließen-Knöpfen daneben abhebt. */
.searchBar .searchBarOption.active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

.searchBar .iconBtn {
	align-items: center;
	display: inline-flex;
	font-size: 1.6rem;
	justify-content: center;
}

/* Das Feld nimmt den ganzen Rest der Zeile ein - es ist der Grund, warum die Leiste offen ist. */
.searchBarInput {
	background: transparent;
	border: none;
	color: #fff;
	flex: 1;
	font-family: inherit;
	font-size: 1.1rem;
	min-width: 0;
	outline: none;
}

/* Auf dem Handy schließt der Zurück-Pfeil links, das x rechts entfällt: Zwei Wege aus derselben Leiste sind dort
   eine Schaltfläche zu viel, und der Pfeil ist der gewohnte. Breit stehen beide - wer von rechts kommt (das Feld
   liegt dort), soll nicht quer über die Leiste zielen müssen. */
@media (max-width: 640px) {
	/* ".searchBar" davor ist nötig: ".searchBar .iconBtn { display: inline-flex }" oben hat sonst die höhere
	   Spezifität, und eine Media Query ändert daran nichts (dieselbe Falle wie bei .rcMute). */
	.searchBar .searchBarCloseRight {
		display: none;
	}
}

/* Die Vorschlagsliste: dieselbe Fläche wie die Menüs (siehe .moreFlyout), damit sie sich von der Leiste abhebt. */
.searchSuggestions {
	background: var(--surface-raised);
	border-top: 1px solid var(--line);
	list-style: none;
	margin: 0;
	max-height: 60vh;
	overflow-y: auto;
	padding: 0.3rem 0;
}

.searchSuggestion {
	align-items: center;
	cursor: pointer;
	display: flex;
	gap: 0.6rem;
	padding: 0.6rem 1rem;
}

.searchSuggestion > i {
	color: var(--text-muted);
	flex-shrink: 0;
}

/* Ein Personenvorschlag wirkt anders als seine Nachbarn - er sucht nicht, er springt auf die Personenseite (siehe
   search.js#useSuggestion). Das Symbol sagt es doppelt: gefüllt statt nur konturiert, und im Grün der Mediathek,
   zu der die Person gehört. Die übrigen Symbole der Liste bleiben gedämpft (--text-muted), der Unterschied ist
   damit auf einen Blick da, ohne dass ein Wort nötig wäre. */
.searchSuggestionPerson > i {
	color: var(--group-mediathek-bright);
}

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

.searchSuggestion.active,
.searchSuggestion:active {
	background: var(--control-bg-hover);
}

.searchSuggestionDelete {
	background: none;
	border: none;
	color: var(--text-muted);
	cursor: pointer;
	flex-shrink: 0;
	padding: 0 0.2rem;
}

/* "Jetzt läuft" in der Kopfzeile ---------------------------------------------------------------- */

/* Ein Markup, zwei Darstellungen (siehe inc/nowPlaying.html): Grundzustand ist das gewöhnliche Flyout unter einem
   Symbol - dafür ist hier nichts zu tun, das erledigen die .actions .moreFlyout-Regeln weiter unten. Ab 1025px
   (Block am Ende dieses Abschnitts) wird derselbe Kasten zum statischen Inline-Element.
   Die Umschaltbreite ist 1025px und nicht 640px, weil zwischen 641 und ~850px nur 36 bis 195px frei bleiben - für
   zwei Textzeilen zu wenig. Ab 1025px sind es mindestens 420px.
   Die Überschreibungen unten stehen VOR den .actions-Regeln, deshalb reicht Quellreihenfolge nicht: sie brauchen
   durchweg höhere Spezifität, daher die Form .moreFlyout.nowPlayingFlyout (zwei Klassen am selben Element). */

/* Der Wrapper wird kopfzeilenhoch, damit das top:100% des Menüs an deren Unterkante sitzt und nicht mitten im
   Header. Bewusst nur der direkte Kindpfad: das Tonspur-Menü liegt inzwischen *innerhalb* dieses Menüs und soll
   seinen eigenen inline-block aus .audioTrackActions .actionWrapper behalten. */
.globalActions > .actions > .actionWrapper {
	align-items: center;
	display: flex;
	height: 100%;
}

/* Blau wie der Titel im aufgeklappten Kasten - das Symbol vertritt ihn ja auf schmalen Bildschirmen. Mit
   .globalActions davor, weil ".iconBtn { color: white }" bei gleicher Spezifität weiter unten in der Datei steht.
   Durchweg .nowPlayingToggle statt ".nowPlayingActions .toggleMoreFlyout": seit der Tonspur-Auslöser innerhalb
   dieses Kastens liegt, träfe die zweite Form ihn mit und machte ihn 2.5em groß und blau. */
.globalActions .nowPlayingToggle {
	color: #6af;
}

/* Ohne die feste Schriftgröße erben beide Flyouts unter 640px die 0.6em der Buttongruppe (siehe Media Query) und
   wären rund 9px groß - der Inhalt hat mit der Größe der Symbole nichts zu tun. */
/* margin-top größer als die 2px von ".actions .moreFlyout": in der Kopfzeile stehen die Menüs unter großen
   Symbolen, und mit dem knappen Abstand kleben sie an ihnen. Gilt auch für das Tonspur-Menü, das im "Jetzt
   läuft"-Menü steckt.
   ".actions" muss mit in den Selektor, sonst herrscht Gleichstand mit ".actions .moreFlyout" und die gewinnt über
   die Quellreihenfolge - font-size und max-width blieben davon zwar unberührt (die setzt sie nicht), margin-top
   aber nicht. */
.globalActions .actions .moreFlyout {
	font-size: 1rem;
	margin-top: 8px;
	max-width: min(80vw, 28rem);
}

.nowPlayingActions {
	min-width: 0;
}

/* Läuft nichts, bleibt das Element als leere Hülle stehen: nowPlaying.js braucht einen festen Platz zum Austauschen und
   einen Träger für data-version. Sichtbar sein darf es dabei nicht, sonst entstünde in .globalActions eine Lücke. */
.nowPlayingActions.nowPlayingEmpty {
	display: none;
}

.nowPlayingToggle {
	padding: 0 5px;
}

/* Wie beim Tonspur-Auslöser: die 1.2rem aus ".actions button i" würden das Symbol kleiner machen als seine
   Nachbarn, es soll aber die 2.5em der Buttongruppe übernehmen. ".globalActions" davor ist nötig, weil
   ".actions button i" mit (0,1,2) sonst die höhere Spezifität hätte. */
.globalActions .nowPlayingToggle i {
	font-size: inherit;
}

/* Gefüllt nur, solange das Menü offen ist, sonst die schlankere Bold-Variante (siehe die beiden Symbole in
   inc/nowPlaying.html). Der Kindselektor im :has() ist wichtig: im "Jetzt läuft"-Menü steckt das Tonspur-Menü,
   und ohne ihn bliebe das Symbol auch dann gefüllt, wenn nur noch jenes offen wäre. */
.nowPlayingIconOpen {
	display: none;
}

.actionWrapper:has(> .moreFlyout.open) .nowPlayingIconIdle {
	display: none;
}

.actionWrapper:has(> .moreFlyout.open) .nowPlayingIconOpen {
	display: block;
}

/* Im aufgeklappten Zustand (schmaler Bildschirm) bleibt es bei der Spalte aus ".actions .moreFlyout": die
   Schaltflächen stehen unter den Textzeilen, damit denen die volle Breite des Kastens bleibt. Nebeneinander
   stehen sie erst im Inline-Zustand, wo die Höhe knapp und die Breite reichlich ist (siehe unten). */
.actions .moreFlyout.nowPlayingFlyout {
	gap: 0.5em;
}

/* Titel-Link und Schaltflächen bekämen sonst das Aussehen von Menüeinträgen aus ".actions .moreFlyout button,
   .actions .moreFlyout a" (Flex über die volle Breite mit Innenabstand). Beim Titel verhinderte das zusätzlich die
   Ellipsis, weil das Element nie schmaler als sein Text würde; bei den Schaltflächen sind display:flex und
   width:100% block-artig und stellten Wiedergabe und Stopp untereinander statt nebeneinander. */
/* color muss mit hier hinein: ".actions .moreFlyout a" setzt weiß und schlüge ein #6af an .nowPlayingTitle
   (0,1,0) sonst. Blau wie in der Info-Box der Startseite und wie früher in der currentInfoBar. */
.actions .moreFlyout.nowPlayingFlyout a {
	color: #6af;
	display: block;
	padding: 0;
	width: auto;
}

/* Mediathek-Darstellung ------------------------------------------------------------------------ */

/* Bei einer mit TMDB verknüpften Aufnahme steht links das Bild und rechts der Textblock; der Link umfasst
   beides (siehe inc/nowPlaying.html). Spezifität 0,4,1, um das display:block der Regel darüber zu schlagen. */
.actions .moreFlyout.nowPlayingFlyout a.nowPlayingLink {
	align-items: center;
	display: flex;
	flex: 1 1 auto;
	gap: 0.6em;
	min-width: 0;
}

/* "Stretched link": der Link deckt über sein Pseudo-Element die ganze Box ab, obwohl er im Markup nur Bild
   und Text umschließt. Ein <a> um die ganze Box wäre ungültig, sobald darin Schaltflächen stehen - so bleibt
   er ein richtiger Link (Mittelklick, Tastatur, Kontextmenü) und die Schaltflächen bleiben erreichbar.
   Nebenwirkung: Text im Kasten lässt sich nicht mehr markieren, in einer Kopfzeile vertretbar. */
.nowPlayingLink::after {
	content: "";
	inset: 0;
	position: absolute;
}

/* Die Schaltflächen müssen über die aufgezogene Fläche. Beide sind positioniert, der z-index steht trotzdem
   ausdrücklich da, damit die Absicht lesbar ist. Das Tonspur-Menü liegt als Nachfahre mit darüber. */
.nowPlayingTmdbBox .nowPlayingButtons {
	position: relative;
	z-index: 1;
}

/* Höhe fest, Breite über das Seitenverhältnis - so trägt ein Element beide Formen: Poster beim Film (2:3),
   Szenenbild bei einer Folge (16:9). flex:none ist zwingend, sonst quetscht der Flex-Container das Bild und
   das Verhältnis kippt. */
.nowPlayingImage {
	background-color: var(--page-bg);
	border-radius: 4px;
	flex: none;
	height: 4.5rem;
	overflow: hidden;
}

.nowPlayingImage.poster {
	aspect-ratio: 2 / 3;
}

.nowPlayingImage.still {
	aspect-ratio: 16 / 9;
}

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

/* Bewusst der Kindselektor bzw. .toggleMoreFlyout und nicht schlicht "button": im Tonspur-Menü, das seit Neuestem
   in diesem Menü steckt, hat jede Zeile eine Schaltfläche - die sollen ihre eigenen Maße behalten und nicht die
   der vier Bedienelemente hier. Ohne die Eingrenzung standen die Lautsprecher-Symbole dort nicht mehr in einer
   Spalte, weil Innenabstand und Schriftgröße der Zeilen überschrieben wurden. */
.moreFlyout.nowPlayingFlyout .nowPlayingButtons > button,
.moreFlyout.nowPlayingFlyout .nowPlayingButtons .toggleMoreFlyout {
	display: inline-flex;
	font-size: 1.2rem;
	padding: 0 5px;
	width: auto;
}

.moreFlyout.nowPlayingFlyout .nowPlayingButtons > button i,
.moreFlyout.nowPlayingFlyout .nowPlayingButtons .toggleMoreFlyout i {
	font-size: inherit;
}

/* Drei Zeilen plus Balken müssen in die 4rem hohe Kopfzeile passen: 1.15 statt 1.2 bringt gut 2px, die am Ende
   den Unterschied zwischen "passt" und "drückt die Kopfzeile auf" machen. Der Rest der Höhe geht als gap in die
   Zeilenabstände - bei einer Aufnahme großzügiger, weil dort eine Zeile weniger steht (siehe .nowPlayingMovie). */
.nowPlayingMain {
	display: flex;
	flex-direction: column;
	gap: 0.1875em; /* 3px bei der Grundgröße; in em, damit es der größeren Schrift auf dem Handy folgt */
	justify-content: center;
	line-height: 1.15;
	min-width: 0;
}

.nowPlayingMovie .nowPlayingMain {
	gap: 0.5em;
}

/* Der großzügige Abstand darüber gilt der zweizeiligen Aufnahme-Darstellung. In der Mediathek-Darstellung hat eine
   Serienfolge aber drei Zeilen (Serie, Folgentitel, Meta-Angaben) - dort wieder der engere Abstand der TV-Variante,
   sonst stehen sie zu weit auseinander und der Kasten sprengt fast die Kopfzeile.
   Die Unterscheidung über :has(.nowPlayingDesc) statt über eine eigene Klasse, weil es genau darum geht: die
   mittlere Zeile gibt es nur bei einer Folge, beim Film bleiben es zwei Zeilen. */
.nowPlayingTmdbBox .nowPlayingMain:has(.nowPlayingDesc) {
	gap: 0.1875em;
}

/* Bei einer Aufnahme steht das Auflösungssymbol hier statt in der entfallenen Senderzeile. */
.nowPlayingTitleRow {
	align-items: center;
	display: flex;
	gap: 0.4em;
	min-width: 0;
}

/* Flex, weil die Glyphe sonst rund 1.5px zu hoch in ihrem Kästchen sitzt: dessen Zeilenbox reserviert unter dem
   Symbol Platz für Unterlängen. Derselbe Effekt wie bei den Schaltflächen der Kopfzeile, siehe .globalActions
   .iconBtn - hier fällt er nur stärker auf, weil daneben eine Textzeile steht. */
/* color ausdrücklich, weil in der Mediathek-Darstellung die ganze Titelzeile im Link liegt und dessen Blau sonst
   auch das Auflösungssymbol einfärbt. In der Darstellung ohne TMDB ist der Wert derselbe wie der geerbte, dort
   ändert die Regel also nichts. */
.nowPlayingTitleRow .videoSizeIcon {
	align-items: center;
	color: var(--control-text);
	display: inline-flex;
	flex: none;
	font-size: 0.75rem;
}

/* font-size etwas kleiner als die geerbte Grundgröße - dieselbe wie beim Titel in der Info-Box der Startseite
   (.content .db-row, 0.9rem).
   Titel und Untertext sind die einzigen Teile, die schrumpfen dürfen. Damit das greift, muss die min-width:0-Kette
   von .globalActions bis hierher lückenlos sein - ein Flex-Kind schrumpft sonst nie unter seine Inhaltsbreite und
   der Kasten schöbe die Schaltflächen aus der Kopfzeile.
   Die Farbe steht bewusst nicht hier, sondern bei ".actions .moreFlyout.nowPlayingFlyout a": der Titel ist ein
   Link, und jene Regel hätte die höhere Spezifität. */
.nowPlayingTitle {
	font-size: 0.9rem;
	font-weight: bold;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Zeile 2: die Kurzbeschreibung der Sendung bzw. der Aufnahme. Etwas heller als die Senderzeile darunter, damit
   die Reihenfolge Titel - Inhalt - Herkunft auch farblich abgestuft ist. */
.nowPlayingDesc {
	color: #ccc;
	font-size: 0.75em;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.nowPlayingSub {
	align-items: center;
	color: #aaa;
	display: flex;
	font-size: 0.75em;
	gap: 0.4em;
	min-width: 0;
}

.nowPlayingSubText {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.nowPlayingRemaining {
	flex: none;
}

/* gap in em, damit der Abstand der Vergrößerung auf dem Handy folgt (siehe Media Query). Er kommt zu den 5px
   Innenabstand je Schaltfläche hinzu.
   Einzeilig - im aufgeklappten Menü steht die Reihe unter dem Text und hat die volle Breite. Zweizeilig wird sie
   erst im Inline-Zustand, wo die Höhe da ist und die Breite knapp (siehe Media Query). */
.nowPlayingButtons {
	align-items: center;
	display: flex;
	flex: none;
	gap: 0.5em;
}

/* Die beiden Sprungknöpfe sehen aus wie ihre Nachbarn; ohne Ziel bleiben sie als ausgegraute Attrappe stehen,
   damit die Anordnung nicht springt. Farbe wie bei .tmdbTitleNav .disabled. */
.nowPlayingNav.disabled {
	color: var(--text-faint);
	cursor: default;
}

/* Binge-Modus. Bewusst größer als seine sechs Nachbarn: Er schaltet einen Zustand um, der über das Ende der
   laufenden Folge hinaus wirkt, während die anderen sechs Einzelaktionen auslösen - und er steht als einziger
   allein in seiner Rasterspalte, wo die zusätzliche Größe niemanden verdrängt.
   Der lange Selektor ist nötig: ".moreFlyout.nowPlayingFlyout .nowPlayingButtons > button i" weiter oben setzt
   mit (0,4,2) "font-size: inherit" und schlüge jede kürzere Fassung. Und em statt rem, damit die Vergrößerung
   auch im Handy-Menü greift, wo die Schaltflächen selbst schon größer sind. */
.moreFlyout.nowPlayingFlyout .nowPlayingButtons > button.nowPlayingBinge i {
	font-size: 1.4em;
}

/* Der eingeschaltete Zustand allein über die Farbe - blau wie der Titel und der Umschalter des Kastens. Anders
   als dort wird bewusst nicht zusätzlich auf die gefüllte Symbolvariante umgeschaltet: Die gefüllte
   Unendlichkeitsschleife verliert ihre Form, weil die Innenflächen der beiden Schlaufen zulaufen.
   ".globalActions" davor, weil ".iconBtn { color: white }" bei gleicher Spezifität weiter unten in der Datei
   steht - dieselbe Falle wie beim .nowPlayingToggle. */
.globalActions .nowPlayingBinge.active {
	color: #6af;
}

/* Die Symbole sind mit 29x19px zu klein, um sie mit dem Finger sicher zu treffen - danebengetippt löst man die
   aufgezogene Fläche des Titel-Links aus und landet auf der Detailseite. Ein unsichtbares Pseudo-Element
   vergrößert deshalb nur die Trefferfläche, ohne am Aussehen etwas zu ändern.
   4px je Seite ist das Maximum ohne Überlappung: zwischen den Schaltflächen liegen 8px, zwischen den beiden
   Zeilen des Rasters 8.8px - die vergrößerten Flächen stoßen also gerade aneinander. */
.nowPlayingButtons > button,
.nowPlayingButtons .toggleMoreFlyout {
	position: relative;
}

.nowPlayingButtons > button::after,
.nowPlayingButtons .toggleMoreFlyout::after {
	content: "";
	inset: -4px;
	position: absolute;
}

/* Der Balken ist hier kein eigener Streifen wie in den Timer-Listen, sondern nur ein dünner Trenner zwischen
   Kurzbeschreibung und Senderzeile - die 0.5em Höhe von .timerProgress wären dafür viel zu wuchtig und kosteten
   die Zeile, die stattdessen die Beschreibung bekommt. Zwei Klassen, weil .timerProgress weiter unten in der
   Datei steht und bei gleicher Spezifität über die Quellreihenfolge gewänne. */
/* margin: 0 gehört ausdrücklich dazu: ".timerProgress .timerProgressBar" gibt dem gefüllten Teil sonst 0.2em
   Außenabstand mit, und der rutscht bei 2px Höhe sichtbar aus seiner Spur heraus - es sieht dann nach zwei
   Strichen aus statt nach einem Balken. */
.nowPlayingMain .nowPlayingProgress,
.nowPlayingMain .nowPlayingProgress .timerProgressBar {
	border-radius: 1px;
	height: 2px;
	margin: 0;
}


/* Die Größe steht an der Schaltfläche, nicht am Symbol: der Tonspur-Auslöser trägt bewusst "font-size: inherit"
   an seinem <i> (siehe .audioTrackActions .toggleMoreFlyout i), passt sich also seinem Umfeld an - und dieses
   Umfeld ist genau diese Regel. Nicht auf .rcBtn eingegrenzt, weil weder Info- noch Tonspur-Knopf einer ist. */
/* Der Tonspur-Auslöser steckt als einziger der vier in einem .actionWrapper (er bringt ja sein eigenes Menü mit).
   Dessen inline-block aus ".audioTrackActions .actionWrapper" richtet ihn an der Grundlinie aus statt mittig, und
   er säße dadurch 1.4px höher als seine drei Nachbarn. Drei Klassen, weil jene Regel weiter unten in der Datei
   steht und bei Gleichstand gewönne. */
.actions .nowPlayingButtons .actionWrapper {
	align-items: center;
	display: flex;
}


/* Ab hier der Inline-Zustand. Bewusst als min-width-Block, obwohl die Datei sonst desktop-first ist: andernfalls
   müsste ein max-width-Block den Popup-Zustand mit kopierten Werten (Fläche, Rahmen, Innenabstand, absolute
   Positionierung) wiederherstellen, die bei einer Änderung an .actions .moreFlyout stillschweigend auseinanderliefen.
   So bleibt der Flyout-Zustand der unangetastete Originalzustand. */
@media (min-width: 1025px) {
	/* margin-left hält den Kasten vom Logo weg - ohne ihn beginnt der Titel unmittelbar an dessen Kante, weil der
	   Kasten den freien Bereich ja gerade ausfüllen soll. */
	.nowPlayingActions {
		flex: 1 1 auto;
		margin-left: 1.5rem;
	}

	/* .globalActions davor ist nötig: ".globalActions .iconBtn { display: inline-flex }" hätte sonst die höhere
	   Spezifität, und eine Media Query ändert daran nichts. */
	.globalActions .nowPlayingToggle {
		display: none;
	}

	.actions .moreFlyout.nowPlayingFlyout {
		align-items: center;
		background-color: transparent;
		border: none;
		display: flex;
		flex-direction: row;
		margin-top: 0;
		padding: 0;
		position: static;
	}

	/* Der Kasten muss Bezugspunkt für das aufgezogene Pseudo-Element bleiben. Ohne das spannte es sich bis zur
	   Kopfzeile auf - die ist positioniert - und schluckte die Klicks auf Ein/Aus und Fernbedienung.
	   .nowPlayingTmdbBox sitzt am äußeren .actions-Element, nicht am Menü selbst; vier Klassen, damit die Regel
	   darüber (0,3,0, im selben Block) sicher geschlagen wird. */
	.actions.nowPlayingTmdbBox .moreFlyout.nowPlayingFlyout {
		position: relative;
	}

	/* In der 4rem hohen Kopfzeile kleiner als im Flyout: 3rem entspricht der Höhe des Logos. */
	.nowPlayingImage {
		height: 3rem;
	}

	/* Die Breitenbegrenzung gilt dem aufgeklappten Menü, damit es auf dem Handy nicht über den Rand läuft. Inline
	   ist sie schädlich: der Kasten hört dann mitten im freien Bereich auf und kürzt seine Zeilen mit "...", obwohl
	   rechts noch Platz ist. Begrenzt wird er hier ohnehin durch die Flex-Kette - er wächst nur bis an die
	   Schaltflächen und schrumpft davor über min-width:0 (siehe .nowPlayingLink). */
	.globalActions .actions .moreFlyout.nowPlayingFlyout {
		max-width: none;
	}

	/* Sechs Schaltflächen inline: als 3x2-Raster statt in einer Reihe. Das spart rund 37px Breite gegenüber einer
	   Reihe (die stattdessen 74px mehr bräuchte) und kostet nur Höhe, die in der 4rem hohen Kopfzeile neben dem
	   52px hohen Textblock ohnehin da ist. Bei 1025px sind links nur rund 628px frei - dort zählt die Breite.
	   Ein Raster statt flex-wrap, weil die Umbruchstelle so festliegt und nicht von den Buttonbreiten abhängt.
	   Nur mit den Sprungknöpfen: ohne sie sind es vier Schaltflächen (Film) bzw. zwei (Fernsehen), und die
	   stünden im Dreierraster als 3+1 da - Stopp allein in der zweiten Zeile. */
	.nowPlayingButtons:has(.nowPlayingNav) {
		display: grid;
		grid-template-columns: repeat(3, auto);
	}

	/* Die vierte Spalte nur, wenn der Binge-Schalter auch da ist. Sie einfach immer zu deklarieren wäre falsch:
	   Eine leere Spur fällt zwar auf Breite 0 zusammen, aber die automatische Platzierung füllt sie vorher auf -
	   ohne den Schalter stünden die sechs übrigen dann als 4+2 statt als 3+3 (gemessen). */
	.nowPlayingButtons:has(.nowPlayingNav):has(.nowPlayingBinge) {
		grid-template-columns: repeat(3, auto) auto;
	}

	/* Der Schalter bekommt die vierte Spalte über beide Zeilen und steht darin mittig. Die feste Platzierung
	   nimmt ihn aus dem automatischen Fluss, die übrigen sechs verteilen sich also unverändert auf 1-3. */
	.nowPlayingButtons:has(.nowPlayingNav) .nowPlayingBinge {
		align-self: center;
		grid-column: 4;
		grid-row: 1 / span 2;
	}

	/* Die drei Wiedergabe-Schaltflächen gemeinsam in die zweite Zeile, damit sie dort als zusammenhängende
	   Leiste "zurück - Wiedergabe - vor" stehen. In der Markup-Reihenfolge umschließt die Navigation die
	   Wiedergabe, was einzeilig richtig ist; im Dreierraster zerfiele sie sonst zeilenweise zu
	   "Beschreibung, Tonspur, zurück / Wiedergabe, vor, Stopp".
	   Über order statt über eine andere Markup-Reihenfolge, damit die einzeilige Anordnung unberührt bleibt. */
	.nowPlayingButtons:has(.nowPlayingNav) .nowPlayingNav,
	.nowPlayingButtons:has(.nowPlayingNav) [data-rc="play"] {
		order: 1;
	}
}

.remoteFlyout {
	height: fit-content;
	margin: 0 0.5rem 0 0;
	position: sticky;
	scrollbar-gutter: stable;
	top: 5rem;
}

.remoteFlyout .remote {
	margin: 0;
}

#remoteFlyout {
	display: none;
}
#remoteFlyout.open {
	display: block;
}

/* Flyout Menu ---------------------------------------------------------------------------------- */

.flyout-menu {
	background: linear-gradient(180deg, var(--page-bg), var(--surface));
	border-bottom: 1px solid var(--line);
	border-right: 1px solid var(--line);
	display: flex;
	flex-direction: column;
	gap: 0;
	left: 0;
	max-height: calc(var(--vh) * 100 - 4rem);
	opacity: 0;
	overflow-y: auto;
	padding: 0;
	pointer-events: none;
	position: fixed;
	top: 4rem;
	transform: translateX(-100%);
	transform-origin: left;
	transition: transform 0.3s ease, opacity 0.3s ease;
	width: 200px;
	z-index: 11;
}

.flyout-menu.open {
	opacity: 1;
	pointer-events: auto;
	transform: translateX(0);
}

.flyout-item {
	align-items: center;
	border-left: 3px solid transparent;
	color: #aaa;
	cursor: pointer;
	display: flex;
	gap: 0.75em;
	padding: 0.6em 1em;
	text-align: left;
	transition: all 0.2s ease;
	white-space: nowrap;
}

.flyout-item:active {
	background-color: rgba(102, 153, 221, 0.2);
	color: #fff;
}

.flyout-item.active {
	border-left-color: #6af;
	color: #6af;
	font-weight: bold;
}

/* Die Box-Umschalter sind eine Auswahl, kein Ort. Mit der Ortsmarkierung der Menüpunkte (Balken plus eingefärbte
   Schrift) sah es aus, als wäre man auf zwei Seiten gleichzeitig. Die gewählte Box bekommt deshalb die Optik einer
   Auswahlliste - gefüllte Fläche und Häkchen - und bewusst keinen Balken. */
.flyout-item.switchBox.active {
	background: var(--control-bg);
	border-left-color: transparent;
	color: var(--control-text);
}

.switchBoxCheck {
	display: none;
}

.switchBox.active .switchBoxCheck {
	display: inline-block;
	margin-left: auto;
}

.flyout-item i {
	font-size: 1.3rem;
	flex-shrink: 0;
}

.flyout-separator {
	border-top: 1px solid var(--line);
}

/* Bereichsgruppen wie auf der Startseite: Balken in der Gruppenfarbe links, wo er am schnellsten erfasst wird.
   Der Balken sitzt bewusst an den Einträgen selbst und nicht an der Gruppe - so läuft er ohne Lücke durch, und der
   aktive Eintrag kann sein eigenes Stück davon einfärben (Variante B unten). Getrennt werden die Gruppen durch eine
   Linie ohne Abstand, damit der Farbbalken eine durchgehende Spalte bleibt. */
.flyout-group + .flyout-group {
	border-top: 1px solid var(--line);
}

.flyout-group--recording .flyout-item { border-left-color: var(--group-recording); }
.flyout-group--mediathek .flyout-item { border-left-color: var(--group-mediathek); }
.flyout-group--misc      .flyout-item { border-left-color: var(--group-misc); }

/* Der aktive Eintrag hellt sein Stück des Gruppenbalkens auf, statt eine eigene Farbe einzuführen - so bleibt die
   Bereichszugehörigkeit auch in der Markierung lesbar. Schrift und Symbol gehen bewusst mit: ein grüner Balken neben
   hellblauer Schrift wären zwei Aussagen zur selben Zeile. */
.flyout-group--recording .flyout-item.active { border-left-color: var(--group-recording-bright); color: var(--group-recording-bright); }
.flyout-group--mediathek .flyout-item.active { border-left-color: var(--group-mediathek-bright); color: var(--group-mediathek-bright); }
.flyout-group--misc      .flyout-item.active { border-left-color: var(--group-misc-bright);      color: var(--group-misc-bright); }

/* Menüpunkte ohne Gruppe (derzeit nur "Einstellungen") bleiben auf der Grauachse, statt hellblau zu werden: Das
   Hellblau stand als vierte Farbe neben den drei Bereichsfarben und sah aus wie eine weitere Gruppe. Aufgehellt wird
   nach demselben Muster wie bei den Gruppen - der gedämpfte Grundton (#aaa, siehe .flyout-item) geht auf die normale
   Textstärke hoch. Reines Weiß wäre der Sprung ans obere Ende und dafür zu grell.
   Der Kindselektor trifft genau die gruppenlosen Einträge - die der Gruppen liegen eine Ebene tiefer in
   .flyout-group. Bewusst hier und nicht an .flyout-item.active: diese Klasse vergibt auch die Listen-Seitenleiste an
   die gewählte Liste (lists.js). */
.mainItems > .flyout-item.active {
	border-left-color: var(--text);
	color: var(--text);
}

/* Die drei Bereiche stehen im Flyout nur, solange die Seitenleiste fehlt. Ab 1025px führt die sie bereits (siehe
   .sidebar), und das Flyout beschränkt sich auf das, was es allein hat: Box-Umschalter, Power und das Beiwerk unten -
   von 765 auf 365 Pixel, womit der Scrollbalken auf einem Tablet im Querformat verschwindet.

   Das war bis zum 19.08.2026 schon einmal so (damals bei 1200px) und wurde dort bewusst aufgegeben, im Tausch gegen
   einen anderen Eintrag: "das Flyout zeigt immer alle Bereiche (dafür entfällt Einstellungen in der Sidebar)". Der
   Tausch bleibt bestehen - Einstellungen steht weiterhin nur hier -, nur ist das Flyout seither um sechs Einträge
   gewachsen. Vier Tage später kam das zweite Argument dazu: Flyout und Seitenleiste tragen dieselbe Reihenfolge und
   dieselben Farben, "sodass ein Bereich überall gleich aussieht". Das gilt weiter und wiegt nur weniger schwer als
   die Länge. Wer es zurücknimmt, löscht diese eine Media Query. */
@media (min-width: 1025px) {
	.flyout-sections {
		display: none;
	}
}

.flyout-item.has-submenu {
	position: relative;
}
.flyout-item.has-submenu::after {
	content: "▼";
	display: inline-block;
	margin-left: auto;
}
.flyout-item.has-submenu.open::after {
	content: "▲";
}

.flyout-submenu .flyout-item {
	font-size: 0.9em;
    padding: 0.4em 1em 0.5em 1.6em;
}
.flyout-submenu .flyout-item:first-child {
	border-top: 1px dashed var(--line);
}
.flyout-submenu .flyout-item i {
    font-size: 1rem;
}

/* Sidebar -------------------------------------------------------------------------------------- */

.sidebar {
	border-right: 1px solid var(--line);
	display: flex;
	flex: 0 0 5.5rem;
	flex-direction: column;
	left: 0;
	height: calc(var(--vh) * 100 - 4rem);
	overflow-y: auto;
	/* Oben bewusst ohne Abstand: Der Farbbalken der ersten Gruppe soll direkt unter dem Seitenkopf ansetzen - eine
	   Lücke sah nach abgerissener Spalte aus und kostete nur Höhe. Unten bleibt Luft für das Ende der Liste. */
	padding: 0 0 0.75em 0;
	position: sticky;
	top: 4rem;
	transition: width 0.3s ease;
	/* Unter den Aktionsmenüs (z-index 8, siehe .actions .moreFlyout): Ein Menü der ersten Kachel reicht bis über die
	   Navigationsleiste, und lag diese darüber, schienen ihre Symbole durch das Menü hindurch - sie hat keinen eigenen
	   Hintergrund. Über dem Seiteninhalt bleibt sie damit trotzdem. */
	z-index: 7;
}

.nav-btn {
	align-items: center;
	background: transparent;
	border: none;
	border-left: 3px solid transparent;
	color: #aaa;
	cursor: pointer;
	display: flex;
	flex-direction: column;
	font-size: 0.65rem;
	gap: 0.3em;
	justify-content: center;
	min-height: 5em;
	padding: 0.5em;
	text-align: center;
	transition: font 0.3s ease;
	width: 100%;
}

.nav-btn i {
	font-size: 1.7rem;
}

.nav-btn:active {
	color: #fff;
}

.nav-btn.active {
	border-left-color: #6af;
	color: #6af;
}

/* Bereichsgruppen wie im Flyout und auf der Startseite: Balken in der Gruppenfarbe links, wo er am schnellsten
   erfasst wird.
   Der Balken wird hier als Hintergrund der Gruppe gezeichnet und nicht als Rahmen der Schaltflächen. Nur so trägt er
   die Innenabstände mit: Die Gruppen brauchen Luft zueinander und zum Seitenkopf, ein Abstand zwischen den
   Schaltflächen würde den Balken aber zerhacken. Als Rahmen der Schaltfläche bliebe er dagegen exakt so hoch wie die
   Schaltfläche selbst.
   Die Schaltflächen behalten ihren 3px-Rahmen links, der im Normalfall durchsichtig ist und den Gruppen-Hintergrund
   durchscheinen lässt - der aktive Eintrag färbt ihn ein und überdeckt damit passgenau sein Stück des Balkens. */
.nav-group {
	padding: 0.4em 0;
}

.nav-group + .nav-group {
	border-top: 1px solid var(--line);
}

/* Die letzte Gruppe bekommt eine Linie auch unten. Oben schließt der Seitenkopf die Leiste ab, unten stand sie
   seit dem 22.09.2026 offen - vorher endete sie mit der farblosen vierten Gruppe (Hilfe, Über), deren Linie diesen
   Abschluss nebenbei mitbrachte. Nur dort, wo sie wirklich die letzte ist: In der Leiste stehen ausschließlich die
   drei Gruppen, aber :last-child hält das auch, falls eine vierte zurückkommt. */
.nav-group:last-child {
	border-bottom: 1px solid var(--line);
}

.nav-group--recording { background: linear-gradient(to right, var(--group-recording) 3px, transparent 3px); }
.nav-group--mediathek { background: linear-gradient(to right, var(--group-mediathek) 3px, transparent 3px); }
.nav-group--misc      { background: linear-gradient(to right, var(--group-misc) 3px, transparent 3px); }

/* Der aktive Bereich hellt sein Stück des Balkens auf und färbt Schrift und Symbol mit - wie im Flyout, damit
   dieselbe Markierung nicht in zwei Navigationen unterschiedlich aussieht. */
.nav-group--recording .nav-btn.active { border-left-color: var(--group-recording-bright); color: var(--group-recording-bright); }
.nav-group--mediathek .nav-btn.active { border-left-color: var(--group-mediathek-bright); color: var(--group-mediathek-bright); }
.nav-group--misc      .nav-btn.active { border-left-color: var(--group-misc-bright);      color: var(--group-misc-bright); }

.sidebar-spacer {
	flex: 1;
}

/* Main ----------------------------------------------------------------------------------------- */

main {
	display: flex;
	gap: 1rem;
	justify-content: space-between;
	margin-top: 4rem;
	padding: 0;
}

/* min-width: 0 hebt den Standardwert "auto" für Flex-Kinder auf, der ein Element nie unter seine Inhaltsbreite
   schrumpfen lässt. Ohne ihn wächst der gesamte Inhaltsbereich mit seinem breitesten Kind mit (statt sich auf die
   Fensterbreite zu beschränken), und innenliegende Bereiche mit overflow-x kommen nie zum Zug: sie haben ja
   scheinbar Platz. Aufgefallen an der Videoreihe einer Serie mit vielen Videos, die die Seite auf ~2260px zog. */
/* Rechts bewusst genauso viel Luft wie links (dort kommt sie aus dem gap zur .sidebar): Ohne eigenes
   padding-right klebte der Inhalt am rechten Rand, sobald kein Formular in .editForm daneben sitzt - das betrifft
   die meisten Seiten. Wirkt sich auf ein offenes Formular nicht aus, weil das ein eigenes Flex-Geschwister von
   main-content ist und dessen rechte Kante unverändert am main-Rand bleibt (siehe .editForm). Unterhalb von
   1024px (siehe dortige Media Query) verschwindet die Sidebar ohnehin, dort bleibt es daher beim alten,
   randlosen Verhalten. */
.main-content {
	flex: 1;
	min-width: 0;
	padding: 0 1em 1em 0;
}

/* Content -------------------------------------------------------------------------------------- */

.errorCode {
	color: #999;
}

.errorDetails {
	background-color: var(--surface);
	color: #ccc;
	font-family: monospace;
	font-size: 1rem;
	padding: 1rem;
	white-space: pre-wrap;
}

.infoBar {
	align-items: center;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: 0.5rem 1rem;
	margin: 1rem 0;
}

/* Auch innerhalb der Zählzeile eine Flex-Zeile: dort stehen Schaltflächen zwischen Fließtext, und im Textfluss
   richten sie sich an der Schriftlinie aus statt an der Mitte - eine 2rem hohe Schaltfläche saß dadurch sichtbar
   höher als der Text daneben. */
.countInfo {
	align-items: center;
	column-gap: 0.25rem;
	display: flex;
	flex-wrap: wrap;
	row-gap: 0.4rem;
}

/* Auf Leisten mit .flowBar fließen Angaben und Schaltflächen in einem gemeinsamen Fluss: sonst ist die Zählzeile
   ein einzelnes Flex-Element, und sobald ihr Inhalt umbricht, wird sie zweizeilig - die Schaltflächen dahinter
   können dann nicht mehr neben ihrer letzten Zeile stehen und rutschen komplett darunter (auf einem schmalen
   Handy ergab das vier Zeilen statt zwei).
   Der gesamte Abstand kommt hier aus dem gap und nicht aus margins: ein gap fällt am Zeilenanfang weg, ein
   margin nicht - eine umbrochene Zeile begänne sonst sichtbar eingerückt. Die Trennzeichen der Seite dürfen
   dafür keine eigenen Leerzeichen mitbringen, sie sind eigenständige Elemente des Flusses. */
.infoBar.flowBar {
	column-gap: 0.4rem;
}

.infoBar.flowBar .countInfo {
	display: contents;
}

/* "Hier ist alles in Ordnung" in der Zählzeile - auf den vier Abgleichsseiten und bei den Fundstellen.
   Sonst steht dort eine Zahl über einer Tabelle, und die Zeile liest sich schon durch ihre Stellung als Kopf der
   Seite. Ist nichts zu tun, fehlt diese Tabelle: Die Zeile stand dann als erster von mehreren gleich aussehenden
   Absätzen da und war von ihnen nicht zu unterscheiden. Das Häkchen macht sie wieder zum Urteil über die Seite
   statt zum Satzanfang - und zwar grün wie überall der erledigte Zustand (siehe --accent-watched).
   Nur das Zeichen ist grün, der Text bleibt in der Textfarbe: Ein ganzer grüner Satz schreit an einer Stelle,
   an der es nichts zu tun gibt. */
.countInfoOk {
	font-weight: bold;
}

.countInfoOk > i {
	color: var(--accent-watched);
	font-size: 1.2rem;
}

/* Der führende Reload-/Refresh-Button steht etwas abgesetzt: er ist eine Aktion, während rechts davon die
   Angaben der Seite folgen - ohne den Abstand liest er sich wie deren erstes Zeichen. */
.countInfo > .iconBtn:first-child {
	margin-right: 0.5rem;
}

/* Eine einzelne Angabe der Zählzeile - Symbol und Zahl gehören zusammen und dürfen nicht getrennt werden. */
.countItem {
	white-space: nowrap;
}

/* Eine Ergänzung in Klammern hinter einer Angabe ("274 Filmreihen (191 komplett)", siehe tmdbmovies.html). Sie
   erläutert die Zahl davor und tritt deshalb zurück, statt als zweite Angabe gelesen zu werden. */
.countSub {
	color: var(--text-muted);
}

/* Icon-Schriften wie Phosphor füllen ihr Zeichen nahezu bis zum Schriftrand aus und setzen dessen Unterkante exakt
   auf die Grundlinie - eine Ziffer dagegen hat keine Unterlänge und wirkt dadurch, an derselben Grundlinie
   ausgerichtet, sichtbar tiefer als das Symbol daneben. vertical-align:middle behebt das: Es richtet die Mitte des
   Symbols an der Mitte der x-Höhe der Ziffern aus, was optisch sehr nah an eine echte Zentrierung herankommt. */
.countItem i {
	vertical-align: middle;
}

/* Rein per CSS gezeichnet statt des Zeichens "&triangleright;": dessen Position im Glyphen ist von Schriftart zu
   Schriftart verschieden (mal mittig, mal deutlich Richtung Grundlinie) und lässt sich deshalb nicht zuverlässig
   zentrieren - dieses Dreieck dagegen sitzt unabhängig von der Schriftart exakt mittig zur Zeile. em-Einheiten,
   damit es mit der Schriftgröße der Zählzeile mitskaliert; currentColor, damit es dieselbe Farbe wie der Text hat. */
.sepTriangle {
	border-bottom: 0.22em solid transparent;
	border-left: 0.4em solid currentColor;
	border-top: 0.22em solid transparent;
	display: inline-block;
	height: 0;
	vertical-align: middle;
	width: 0;
}

/* Der "verwaist"-Zähler ist als einziger Zähler eine Schaltfläche (er setzt den zugehörigen Filter, siehe
   listFilter.js#data-filter-shortcut). Er soll sich trotzdem nahtlos in die Zählerzeile einreihen - daher ohne
   Rahmen und Hintergrund, nur in Warnfarbe und mit Zeigerhand. */
.countInfo .showMissingBtn {
	background: none;
	border: none;
	color: #d44;
	cursor: pointer;
	font: inherit;
	padding: 0;
}

/* Der Pfad ist aus einzelnen Links je Verzeichnisebene aufgebaut; der column-gap der Zeile würde ihn
   auseinanderreißen ("/hdd/ !TV/" statt "/hdd/!TV/"). Er läuft deshalb ohne Lücke durch, und die Schaltflächen
   dahinter holen sich ihren Abstand selbst - sie sollen sich deutlich vom Pfad und voneinander absetzen. */
.infoBar .breadcrumb {
	column-gap: 0;
}

/* :not(:first-child), weil dieselbe Zeile auf der Ordnerübersicht mit dem Reload-Button beginnt - der soll
   bündig mit dem übrigen Seiteninhalt stehen und nicht eingerückt sein. */
.infoBar .breadcrumb > .iconBtn:not(:first-child) {
	margin-left: 0.6rem;
}

/* Der Zurück-Pfeil ist jetzt der erste - wie der Reload-Button auf der Ordnerübersicht braucht er Abstand nach
   rechts statt nach links, sonst klebt der Pfad direkt daran. */
.infoBar .breadcrumb > .breadcrumbBack {
	margin-right: 0.5rem;
}

.countInfo .prevNextButtons {
	margin-left: 1rem;
}

.countLabel {
	display: inline;
}

/* Das Seitensymbol tritt auf schmalen Bildschirmen an die Stelle der Beschriftung (siehe Media Query). Den
   Abstand zur Zahl trägt ein echtes Leerzeichen im Markup - genau wie bei den übrigen Angaben, damit er dort
   und hier identisch ist. Auf breiten Bildschirmen steht davor die Beschriftung mit eigenem Leerzeichen; beide
   fallen zusammen, weil HTML aufeinanderfolgende Leerzeichen zu einem zusammenzieht. */
.countIcon {
	display: none;
}

.filter .checkBox {
	display: none;
}

.filter .checkBox:checked + .checkLabel {
	background-color: var(--control-bg-hover);
	color: var(--control-text-hover);
	font-weight: bold;
}

.filter .checkLabel {
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 3px;
	color: #ddd;
	cursor: pointer;
	display: inline-block;
	font-size: 0.9em;
	margin: 0 0.5em 0.25em 2em;
	padding: 3px 5px;
}

/* Filterleiste: standardmäßig zugeklappt, wird über den Trichter-Button in der .infoBar geöffnet. */
/* Bewusst ohne eigene Fläche und ohne Rahmen: die Filterleiste besteht bereits aus lauter umrandeten
   Bedienelementen, ein Kasten darum ergab einen Rahmen im Rahmen. Ohne Innenabstand fluchten ihre Elemente
   zudem mit dem übrigen Seiteninhalt statt eingerückt zu stehen. */
.filterBar {
	align-items: center;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	/* Waagerecht enger als eine übliche Bedienzeile: seit die Filter Symbol-Knöpfe statt Pillen-Gruppen sind,
	   trennt schon der eigene Rahmen jedes Elements sie deutlich genug voneinander. Senkrecht dagegen mehr, denn
	   auf schmalen Geräten bricht die Leiste um: Stünden die Zeilen genauso eng wie die Elemente darin, verschwämmen
	   sie zu einer Fläche, statt als zwei Zeilen lesbar zu sein. */
	gap: 0.6rem 0.5rem;
	margin: 0 0 1rem 0;
	padding: 0;
}

/* Suchfeld + Suchfelder-Flyout-Button ohne Abstand aneinandergedockt, sodass nur eine gemeinsame
   Border-Linie an der Nahtstelle sichtbar ist (wirkt wie ein Element mit integriertem Button): */
.filterSearchGroup {
	display: inline-flex;
}

.filterSearchGroup .filterSearch {
	border-bottom-right-radius: 0;
	border-right: none;
	border-top-right-radius: 0;
}

.filterSearchGroup .filterFlyoutToggleBtn {
	border-bottom-left-radius: 0;
	border-top-left-radius: 0;
}

/* Ganz schmale Geräte: das Suchfeld gibt Breite ab, damit die Filterleiste in zwei statt drei Zeilen passt.
   Beide Zahlen sind gemessen, nicht geschätzt (Filmübersicht, deren Leiste die meisten Filter trägt): Mit der
   vom Browser vorgegebenen Feldbreite von 200px reicht es bis 404px Fensterbreite für zwei Zeilen, ab 400px
   bricht die dritte auf - daher genau hier die Grenze. Und 6,5rem ist die größte Breite, mit der auch die
   verbreiteten 360px-Geräte noch mit zwei Zeilen auskommen (ab 116px wird es dort wieder dreizeilig). Bei
   320px hilft übrigens keine Feldbreite mehr, dort bleiben es drei Zeilen. */
@media (max-width: 400px) {
	.filterBar .filterSearch {
		width: 6.5rem;
	}
}

/* .defaultSelect ist an anderen Stellen der App (Edit-Formulare etc.) bewusst größer - hier an die
   Höhe von .filterSearch (input[type="search"]) angleichen, damit alle Elemente der Filterleiste
   gleich hoch sind: */
.filterBar .defaultSelect {
	height: var(--control-height);
	padding: 0 2rem 0 0.75rem;
}

/* Der Innenabstand bleibt halb so groß wie der zwischen den Filtern (siehe .filterBar), sonst verwischt die
   Gruppierung: die Pillen einer Gruppe stünden genauso weit auseinander wie die Gruppen selbst. */
.filterBar .filterGroup {
	align-items: center;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: 0.25rem;
}

/* Anker für das Kennzeichen mit der Trefferzahl. Es hängt am Trichter-Umschalter, damit auch zugeklappt
   sichtbar bleibt, dass gefiltert wird - und bei dauerhaft offener Leiste (Filme, Serien), die keinen
   Umschalter mehr hat, stattdessen am Zurücksetzen-Knopf. */
.filterToggleBtn,
.filterResetBtn {
	position: relative;
}

/* Zeigt die Anzahl der Einträge, die der Filter übrig lässt (siehe listFilter.js). Pillenform statt Kreis:
   bei großen Sammlungen wird die Zahl vierstellig, ein 50%-Radius ergäbe dann eine Ellipse. Das Badge wächst
   nach links (rechte Kante steht fest) und darf dabei nicht umbrechen. */
.filterBadge {
	background-color: #c33;
	border-radius: 999px;
	color: #fff;
	font-size: 0.7rem;
	line-height: 1rem;
	min-width: 1rem;
	padding: 0 0.25rem;
	position: absolute;
	right: -0.3rem;
	text-align: center;
	top: -0.3rem;
	white-space: nowrap;
}

/* Das Kennzeichen überlappt die obere rechte Ecke seines Knopfes. Am Trichter-Umschalter ist das unkritisch -
   dort erscheint es nur beim Filtern, und dann ist die Zahl die wichtigere Auskunft. Am Zurücksetzen-Knopf
   einer offenen Leiste steht es dagegen dauerhaft und schnitte den Trichter sonst immer oben an; sein Symbol
   rückt deshalb ein Stück nach unten. Leicht aus der Mitte ist das kleinere Übel als dauerhaft verdeckt. */
.filterResetBtn:has(.filterBadgePermanent) > i {
	transform: translateY(3px);
}

/* Ruhezustand des dauerhaften Kennzeichens: dieselbe Pille, aber im Blau der Bedienelemente statt in Rot.
   Rot heißt hier durchgehend "eingeschränkt" - ungefiltert ist die Zahl nur eine Auskunft und darf nicht so
   aussehen, als sei etwas ausgeblendet. */
.filterBadge.filterBadgeIdle {
	background-color: var(--control-bg-hover);
	color: var(--control-text);
}

/* Ausgefilterte Einträge. Der zweite Selektor ist kein Versehen: .tmdbTile setzt weiter unten selbst
   display:flex, und bei gleicher Spezifität (je eine Klasse) gewinnt die später notierte Regel - die
   Kacheln blieben dadurch trotz gesetzter Klasse sichtbar. Eine Kachelart, die eigenes display braucht,
   muss hier deshalb mit aufgeführt werden (Tabellenzeilen brauchen das nicht). */
.filterHidden,
.tmdbTile.filterHidden {
	display: none;
}

.filterNoMatch {
	color: #aab;
	font-style: italic;
	margin: 1rem 0;
}

/* Die Zeile über dem Raster, die beim Filtern nennt, wie viel von wie viel übrig ist (siehe
   listFilter.js#updateCountSummary). Gedämpft wie die Meldung darüber, aber aufrecht: Sie berichtet einen
   Stand, während jene einen Ausnahmefall erklärt. Der obere Rand ist klein, damit sie erkennbar zur
   Filterleiste darüber gehört und nicht zum Raster darunter. */
.filterCountSummary {
	color: #aab;
	margin: 0.2rem 0 0.6rem 0;
}

/* Generisches Flyout: Button + darunter aufklappendes Panel, Optik analog zu .autoTimerActionFlyout.
   Von mehreren Filtern gemeinsam genutzt (Tags, Status, ggf. weitere) - siehe listFilter.js, das jedes
   .filterFlyoutWrapper innerhalb einer .filterBar generisch öffnen/schließen kann. */
.filterFlyoutWrapper {
	position: relative;
}

.filterFlyoutToggleBtn {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--field-radius);
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-size: 0.9em;
	gap: 0.3rem;
	height: var(--control-height); /* gleiche Höhe wie die übrigen Elemente der Filterleiste */
	padding: 0 0.6rem;
}

.filterFlyoutToggleBtn:active:not(:disabled):not(.active) {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Gleiche Highlight-Farbe wie im Hauptmenü (.flyout-item.active), damit hier kein neuer Blauton entsteht: */
.filterFlyoutToggleBtn.active {
	background-color: rgba(102, 153, 221, 0.3);
	border-color: #6af;
	color: #6af;
	font-weight: bold;
}

.filterFlyoutToggleBtn:disabled {
	cursor: default;
	opacity: 0.5;
}

.filterFlyoutCount {
	background-color: #c33;
	border-radius: 50%;
	color: #fff;
	font-size: 0.7rem;
	line-height: 1rem;
	min-width: 1rem;
	padding: 0 0.3rem;
	text-align: center;
}

/* Zugeklappt bewusst display:none statt nur visibility:hidden: ein lediglich unsichtbares Panel behält
   seine Ausmaße und schiebt, sobald es rechts über den Fensterrand hinausreicht, den Scrollbereich der
   Seite auf - beim Aufklappen der Filterleiste entstand dadurch rechts ein leerer Streifen, obwohl die
   Leiste selbst bequem in eine Zeile passte. Ohne Fläche kann es das nicht mehr (wie beim "..."-Menü,
   siehe .actions .moreFlyout). Beim aufgeklappten Panel hält positionFlyout() den Rand ein.

   Rechtsbündig statt linksbündig verankert (wächst nach links auf): die meisten Flyouts (Genre/Kategorie/
   Tags/Reset, aber auch der Suchoptionen-Flyout direkt neben dem schmalen Suchfeld) stehen in der Filterleiste
   eher gegen deren Ende bzw. ihr eigener Umschalter ist schmaler als das Panel. Bei linksbündiger Verankerung
   entsteht dort für einen Layout-Durchgang eine über den rechten Fensterrand hinausragende Fläche, bevor
   positionFlyout() sie per transform zurückschiebt - transform korrigiert zwar die Bildschirmposition, nicht
   aber die von manchen mobilen WebViews (App-Shell) herangezogene Layoutbreite, die daraufhin die ganze Seite
   herauszoomt (siehe auch Kommentar oben zum zugeklappten Zustand - dasselbe Prinzip, nur beim Öffnen statt
   beim Schließen). Rechtsbündig legt das Panel dabei auch optisch näher an das zugehörige Suchfeld statt
   seitlich daneben. */
.filterFlyoutPanel {
	background-color: var(--surface-raised);
	border: 1px solid var(--control-border);
	border-radius: 10px; /* wie das "..."-Menü, siehe .actions .moreFlyout */
	display: none;
	flex-direction: column;
	left: auto;
	margin-top: 2px;
	min-width: 12rem;
	padding: 0.5rem;
	position: absolute;
	right: 0;
	top: 100%;
	z-index: 8; /* unter den festgehefteten Leisten, siehe .actions .moreFlyout */
}

.filterFlyoutPanel.open {
	display: flex;
}

/* Im Flyout-Panel sind die Einträge Menüzeilen, keine Chips: Fläche und Rahmen entfallen deshalb, nur das
   Kästchen bzw. der Punkt davor bleibt. Der Rahmen wird auf transparent gesetzt statt entfernt, damit die
   Zeilen ihre Breite behalten und beim Antippen nicht springen. */
.filterFlyoutPanel .defaultCheckboxLabel,
.filterFlyoutPanel .defaultRadioLabel {
	background-color: transparent;
	border-color: transparent;
	border-radius: 6px;
	padding: 0.25rem 0.4rem;
	white-space: nowrap;
}

/* border-color muss hier mit: die allgemeine Druck-Regel der Chips hellt ihn sonst auf, und beim Antippen
   blitzte der Rahmen wieder auf, den die Zeile gerade nicht haben soll. */
.filterFlyoutPanel .defaultCheckboxLabel:active,
.filterFlyoutPanel .defaultRadioLabel:active {
	background-color: rgba(102, 153, 221, 0.2);
	border-color: transparent;
	color: var(--control-text-hover);
}

/* Trennlinie zwischen zwei Gruppen innerhalb desselben Flyout-Panels (z.B. Status/aktiviert-deaktiviert): */
.filterFlyoutSeparator {
	border-top: 1px solid var(--control-border);
	margin: 0.4rem 0;
}

/* Bewusst ohne max-height und eigenen Scrollbereich: Die Liste wird lieber lang und schiebt das Panel nach unten
   aus dem Fenster, als sich in einen zweiten Scrollbereich innerhalb der Seite zu zwängen. Dann sieht man auf einem
   großen Bildschirm alle Einträge auf einen Blick, und auf einem kleinen scrollt man nur die Seite statt erst sie
   und darin nochmal die Liste (gleiche Überlegung wie bei den Aktionsmenüs, siehe positionFlyout in chrome.js). */
.filterTagFlyoutList {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
}

.filterTagFlyoutMode {
	display: flex;
	flex-direction: column;
	font-size: 0.85em;
	gap: 0.3rem;
}

/* "Alle"/"Keine" am Fuß der Mehrfachauswahl-Flyouts. Beide teilen sich die Panelbreite zu gleichen Teilen,
   damit sie als ein Paar auftreten; das margin der .miniBtn entfällt, den Abstand setzt hier das gap. */
.filterFlyoutBulkActions {
	display: flex;
	gap: 0.4rem;
}

.filterFlyoutBulkActions .miniBtn {
	flex: 1;
	margin: 0;
}

/* Flyouts, deren Einträge nur aus einem Wort bestehen (Gesehen-Status, Bewertung, ...), sollen nicht auf die für
   Tag- und Genre-Listen gedachte Mindestbreite aufgeblasen werden. */
.filterFlyoutPanelNarrow {
	min-width: 0;
}

/* Hält den Platz des Zustands-Symbols vor der Beschriftung frei, auch bei "alle", das keines trägt - sonst
   stünde dessen Text als einziger weiter links (siehe filter_icon_flyout). */
.filterOptionIcon {
	display: inline-flex;
	justify-content: center;
	width: 1.15em;
}

/* Der jeweils vollständige Zustand ("gesehen", "gesammelt") trägt im Panel die Farbe seines Kennzeichens auf der
   Kachel (siehe .tmdbBadge.watched/.tmdbBadge.collected). Seit es "teilweise" daneben gibt, steht dieselbe Form
   zweimal in der Liste - auf der Kachel unterscheidet sie genau diese Farbe, hier also auch. Gesetzt wird sie über
   "tone" der Möglichkeit, nicht über deren Symbol (siehe filter_icon_flyout). */
.filterOptionIcon.watched {
	color: #6c6;
}

.filterOptionIcon.collected {
	color: #6af;
}

/* Der gewählte Wert neben dem Symbol des Auslösers (siehe filter_rating_flyout). Ohne :empty-Regel bliebe
   bei "alle" der Abstand des leeren Elements stehen und der Knopf wäre breiter als die übrigen. */
.filterFlyoutValue:empty {
	display: none;
}

input[type="text"],
input[type="password"],
input[type="search"],
input[type="date"],
input[type="time"],
input[type="number"],
select,
textarea {
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--field-radius);
	color: var(--control-text);
	font-size: 0.9rem;
	height: var(--control-height);
	line-height: 1rem;
	margin: 0;
	padding: 0 0.6rem;
}

/* Der Textbereich wächst mit seinem Inhalt, eine feste Höhe wäre hier falsch. font-family, weil Browser hier
   sonst als einzigem Formularelement eine Schreibmaschinenschrift einsetzen: */
textarea {
	font-family: inherit;
	height: auto;
	line-height: 1.4;
	padding: 0.4rem 0.6rem;
	resize: vertical;
}

/* Das Dateifeld bringt seine Schaltfläche selbst mit, vom Browser gezeichnet - ohne eigene Regeln steht sie als
   einziges Element in Systemoptik (hellgrauer Kasten) im Dialog. Das Feld selbst bleibt unsichtbar und trägt nur
   den Text daneben ("keine Datei ausgewählt"), die Schaltfläche bekommt die Pillenform.
   Die Beschriftung stellt der Browser in der Sprache des Systems, darauf haben wir keinen Zugriff. */
input[type="file"] {
	align-items: center;
	background-color: transparent;
	border: none;
	color: var(--text-muted);
	display: inline-flex;
	font-size: 0.9rem;
	gap: 0.6rem;
	height: auto;
	max-width: 100%;
	padding: 0;
}

input[type="file"]::file-selector-button {
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	cursor: pointer;
	font-family: inherit;
	font-size: 0.9rem;
	height: var(--control-height);
	padding: 0 0.9rem;
}

input[type="file"]::file-selector-button:active {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Firefox */
input[type="number"] {
	appearance: textfield;
}
/* Chrome, Safari, Edge, Opera */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

/* Chrome, Safari, Edge, Opera: natives Suchfeld-Aussehen an die übrigen Eingabefelder angleichen */
input[type="search"] {
	-webkit-appearance: none;
	appearance: none;
}

/* Das Löschzeichen im Suchfeld selbst zeichnen. Chromium liefert dafür eine Grafik mit senkrechtem Farbverlauf: Auf
   unserem dunklen Untergrund verblasst deren untere Hälfte so weit, dass vom "x" nur die oberen Schenkel übrig
   bleiben - es liest sich als "v". Als Maske eingefärbt hat das Zeichen dagegen überall dieselbe Deckkraft.

   Die Maske kommt ohne "#" aus (Farbe als Wortname), weil ein Doppelkreuz in einer CSS-url() den Rest als Fragment
   abschneiden würde. Firefox zeigt an dieser Stelle ohnehin nichts an, dort bleibt die Regel wirkungslos. */
input[type="search"]::-webkit-search-cancel-button {
	-webkit-appearance: none;
	appearance: none;
	background-color: var(--text-muted);
	cursor: pointer;
	height: 1em;
	-webkit-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 6 L18 18 M18 6 L6 18' stroke='black' stroke-width='2.5' stroke-linecap='round' fill='none'/></svg>") center / contain no-repeat;
	mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 6 L18 18 M18 6 L6 18' stroke='black' stroke-width='2.5' stroke-linecap='round' fill='none'/></svg>") center / contain no-repeat;
	width: 1em;
}

input[type="search"]::-webkit-search-cancel-button:hover {
	background-color: var(--text);
}

input[type="text"]:focus-visible,
input[type="password"]:focus-visible,
input[type="search"]:focus-visible,
input[type="date"]:focus-visible,
input[type="time"]:focus-visible,
input[type="number"]:focus-visible,
select:focus-visible,
textarea:focus-visible {
	border-color: var(--control-border-hover);
	outline: none;
}

table {
	border-collapse: collapse;
	border-color: var(--line-table);
	border-spacing: 0;
	text-align: left;
}

/* Der Tabellenkopf ist ein abgesetztes Band, wie die Kopfzeile eines Dialogs - deutlich genug, um die Spalten
   zu tragen, aber ohne den Zeilen darunter die Aufmerksamkeit zu nehmen. */
th {
	background: var(--table-header-bg);
	color: var(--table-header-text);
	font-size: 0.9rem;
	font-weight: bold;
	white-space: nowrap;
}

/* Die Zellenlinien tragen die Struktur der Tabelle - neutral statt blau, siehe --line-table. */
th, td {
	border-color: var(--line-table);
	padding: 3px 7px;
}

.defaultTable td {
	overflow-wrap: anywhere;
}

th .sortIcon {
	color: #ccc;
	margin-left: 0.25em;
}

th .sortIcon.sortIconOnly {
	margin-left: 0;
}

th a,
td.dir a {
	color: inherit;
	text-decoration: none;
}

.subTh {
	float: right;
	font-size: 0.75rem;
	font-weight: normal;
	line-height: 1rem;
	margin-left: 2em;
}

.dir .timerState2 {
	vertical-align: bottom;
}

.count,
.unwatched,
.size,
.length,
.modified,
.age,
.timerCount {
	text-align: right;
}

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

.seasonEpisode {
	color: #68c;
}

.switchSender .senderName {
	color: #ccc;
	font-size: 0.75em;
	display: inline-block;
	margin-top: 0.2em;
	vertical-align: center;
}

.epgSelectBar {
	display: flex;
	flex-direction: row;
	align-items: center;
	/* Umbrechen statt quetschen. Ohne das drückte die Leiste auf dem Handy alles in eine Zeile: Die runden Knöpfe
	   kamen als 20x32 große Ovale heraus (flex-shrink ist voreingestellt 1), und rechts lief sie über den Rand
	   hinaus, sodass die ganze Seite seitlich zu schieben war. */
	flex-wrap: wrap;
	gap: 0.5em;
	margin: 1em 0;
}

/* Die Bedienelemente behalten ihre Maße - sie sollen in die nächste Zeile rutschen, nicht schmaler werden. Das
   gilt besonders für die Icon-Knöpfe, deren Rundung von gleicher Breite und Höhe abhängt. */
.epgSelectBar > *,
.epgSelectBar .epgViewOnly > *,
.epgSelectBar .epgSearchWrap > *,
.epgSelectBar .epgLiveWrap > *,
.epgSelectBar .filterSearchGroup > * {
	flex-shrink: 0;
}

/* ... mit Ausnahme der beiden Klammern: Ein Flex-Container bricht seinen Inhalt erst um, wenn er selbst schmaler
   wird als dieser. Mit dem flex-shrink:0 von oben behielt die Sendergruppe ihre 395px Inhaltsbreite und ragte auf
   jedem Telefon über den Rand, obwohl sie flex-wrap trägt. Sie muss also schrumpfen dürfen - umbrechen tut dann
   ihr Inhalt, und dessen Maße hält die Regel darüber fest. */
.epgSelectBar > .epgViewOnly,
.epgSelectBar > .epgSearchWrap {
	flex-shrink: 1;
	max-width: 100%;
}

/* Suchfeld, Optionen, Lupe und die beiden Zusatzknöpfe bleiben beim Umbruch beisammen - sonst rutschte die Lupe
   allein in die nächste Zeile, während das Feld in der vorigen hängen bliebe. */
/* Auswahlliste und ihre beiden Blätterpfeile als ein Bedienelement, nach dem Vorbild von .filterSearchGroup
   darüber: Die Rundungen fallen an den Berührungskanten weg, die Rahmen dazwischen ebenso, und der Abstand
   zwischen ihnen entfällt. Das zeigt die Zusammengehörigkeit - die Pfeile blättern genau in dieser Liste - und
   spart auf schmalen Geräten zweimal 0,5em Breite. Die Pfeile verlieren dabei ihre Kreisform; sie sind hier
   Teil eines längeren Elements, nicht freistehende Knöpfe. */
.epgSelectGroup {
	display: inline-flex;
}

.epgSelectGroup .defaultSelect {
	border-bottom-right-radius: 0;
	border-right: none;
	border-top-right-radius: 0;
}

.epgSelectGroup .iconOnlyBtn {
	border-radius: 0;
	border-right: none;
}

/* Die Außenkante bekommt den Radius des Feldes (8px), nicht den der Knöpfe: --control-radius ist 999px und
   ergäbe einen Halbkreis, während die linke Kante der Auswahlliste daneben bei 8px bleibt. Beide Enden desselben
   Bedienelements müssen gleich gerundet sein. */
.epgSelectGroup > :last-child {
	border-bottom-right-radius: var(--field-radius);
	border-right: 1px solid var(--control-border);
	border-top-right-radius: var(--field-radius);
}

/* Ein gesperrter Pfeil behält den Rahmen der Gruppe. Gedimmt wird nur, was er zeigt - sein eigener Rahmen ist
   hier keine Umrandung eines Knopfes mehr, sondern ein Stück der Umrandung des ganzen Elements, und eine blasse
   Stelle darin sähe aus wie ein Darstellungsfehler. */
.epgSelectGroup .iconOnlyBtn[disabled] {
	border-color: var(--control-border);
}

/* Auf schmalen Geräten füllt jede Gruppe ihre Zeile aus, statt eine feste Breite zu haben. Damit enden alle Zeilen
   bündig am rechten Rand, die Knöpfe daneben rücken dorthin, und die Auswahllisten werden so breit wie das
   Suchfeld - alles drei folgt aus derselben Regel.
   Eine feste Breite stand hier kurzzeitig und war der falsche Weg: Mit 235px blieben je nach Gerät 16 bis 149px
   rechts ungenutzt, und die Zeilen hörten mitten im Bild auf. */
@media (max-width: 640px) {
	.epgSelectBar > .epgSelectGroup,
	.epgSelectBar > .epgViewOnly,
	.epgSelectBar > .epgSearchWrap {
		flex: 1 1 100%;
	}

	/* Und innerhalb der Zeile dehnt sich das eigentliche Eingabeelement, nicht die Knöpfe daneben. */
	.epgViewOnly > .epgSelectGroup,
	.epgSearchWrap > .filterSearchGroup {
		flex: 1;
		min-width: 0;
	}

	.epgSelectGroup .defaultSelect,
	.filterSearchGroup .filterSearch {
		flex: 1;
		min-width: 0;
	}
}

.epgLiveWrap {
	align-items: center;
	display: inline-flex;
	gap: 0.5em;
}

.epgSearchWrap {
	align-items: center;
	display: inline-flex;
	/* Auf sehr schmalen Geräten (gemessen ab 320px) passen Feld, Optionen, Lupe und Aktualisieren auch zusammen
	   nicht mehr in eine Zeile - dann bricht die Klammer in sich um, statt hinauszuragen. */
	flex-wrap: wrap;
	gap: 0.5em;
}

/* Alle Bedienelemente der Leiste auf dieselbe Höhe und ohne eigenen Rand. Wer hier eines hinzufügt, trägt es mit
   ein: Ohne das margin:0 behält es den Standardrand des Browsers und sitzt sichtbar höher als seine Nachbarn -
   genau das passierte dem Aktualisieren-Knopf. */
.epgSelectBar #selectEpgBouquet,
.epgSelectBar #selectEpgService,
.epgSelectBar .switchSender,
.epgSelectBar .switchBouquet,
.epgSelectBar #watchLiveBtn,
.epgSelectBar #watchLiveExternalBtn,
.epgSelectBar .epgSearchWrap,
.epgSelectBar .filterSearchGroup,
.epgSelectBar #epgSearchInput,
.epgSelectBar .filterFlyoutToggleBtn,
.epgSelectBar #epgSearchBtn,
.epgSelectBar #epgRefreshBtn,
.epgSelectBar #epgPrimeDate,
.epgSelectBar #epgPrimeTime,
.epgSelectBar #epgLeaveSearchBtn {
	height: var(--control-height);
	margin: 0;
}

.epgSelectBar #selectEpgBouquet,
.epgSelectBar #selectEpgService {
	line-height: 1.1em;
}

.epgSelectBar button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
}

.epgSelectBar button i {
	padding: 0;
}

.desc,
.timeofday,
.timerEnd,
.epgEnd,
.repeatedInfo {
	color: #aaa;
	font-size: 0.75em;
}

.timerItem .time {
	vertical-align: top;
}
.epgTable .time {
	white-space: nowrap;
}
.timerItem .time .startTime,
.timerItem .time .stateInfo,
.timerItem .time .timerEnd,
.timerItem .time .repeatedInfo,
.epgItem .time .epgEnd {
	white-space: nowrap;
}

.timerItem .timerMeta,
.epgItem .epgMeta,
.epgItem .timerRange {
	font-size: 0.75rem;
	line-height: 1.2rem;
}
.timerItem .timerMeta .stateInfo,
.timerItem .timerMeta .timerEnd,
.epgItem .epgMeta .epgEnd {
	font-size: inherit;
}
.timerItem .timerMeta .timerEnd,
.epgItem .epgMeta .epgEnd {
	float: right;
}

.epgItem .timerRange.fullTimer.runningTimer {
	color: #6af;
}
.epgItem .timerRange.partialTimer.runningTimer {
	color: #68c;
}

.epgProgress .epgProgressBar,
.timerProgress .timerProgressBar {
	background-color: #68c;
	border-radius: 3px;
	height: 0.5em;
	margin: 0.2em 0;
}

.epgProgress .epgProgressBar {
	background-color: #aaa;
}

.playProgress {
	background-color: #666;
	border-radius: 3px;
	height: 0.5em;
	margin: 0.2em 0;
	position: relative;
	width: 100%;
}

.playProgress .playProgressBar {
	background-color: #aaa;
	border-radius: 3px;
	height: 0.5em;
	margin: 0.2em 0;
	position: relative;
	z-index: 1;
}

.playProgress .cutmark {
	background-color: #6af;
	border-radius: 1px;
	bottom: 0;
	pointer-events: none;
	position: absolute;
	top: 0;
	width: 1px;
	z-index: 2;
}

.playProgress .jumpmark {
	background-color: #b67b50;
	border-radius: 1px;
	bottom: 0;
	pointer-events: none;
	position: absolute;
	top: 0;
	width: 1px;
	z-index: 2;
}

.timerProgress,
.epgProgress {
	background-color: #346;
	border-radius: 3px;
	height: 0.5em;
	margin: 0.2em 0;
	width: 100%;
}

.epgProgress {
	background-color: #666;
}

.playNextEpisodeBtn {
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	font-weight: bold;
	margin: 0 0.25em 0 1em;
	padding: 0.2rem 0.7rem;
}

.playNextEpisodeBtn i {
	margin-right: 0.2em;
}

.playNextEpisodeDesc {
	color: #ccc;
	font-size: 0.75em;
}

.abandonedBookmarks {
	margin-bottom: 1rem;
}

.movieDirsTable .indent {
	color: #999;
	font-weight: bold;
}

.movieItem .title .isCutting,
.movieItem .title .isPlaying {
	display: block;
	float: right;
	margin: 0 0.25em 0 0.5em;
}

.movieItem .timerRunningInfo {
	display: flex;
	flex-direction: column;
	text-align: center;
}
.movieItem .timerRunningInfo .timerRunningIcon {
	display: block;
	font-size: 1.3em;
}

.movieItem .isCutting,
.movieItem .isPlaying {
	color: #6af;
	text-align: center;
}

.movieItem .isCutting .cuttingIcon,
.movieItem .isPlaying .playingIcon {
	display: block;
	font-size: 1.5em;
}
.movieItem .isPlaying .playingIcon {
	margin: 0 0.2em 0 0;
}

.movieItem .isCutting .cuttingText,
.movieItem .isPlaying .playingText {
	display: block;
	font-size: 0.75em;
}

.movieItem .type {
	text-align: center;
}

.movieItem .time {
	white-space: nowrap;
}

/* inline-flex, damit die Schaltfläche darin die Mitte der Zeile trifft: als Inline-Element richtete sie sich an
   der Schriftlinie aus und saß knapp 2px zu hoch. */
.autoTimerActions {
	align-items: center;
	display: inline-flex;
	position: relative;
}

.autoTimerActionFlyout {
	background-color: var(--surface);
	border: 1px solid var(--line);
	border-radius: 3px;
	color: #ddd;
	display: flex;
	flex-direction: column;
	left: 0;
	margin-top: 2px;
	opacity: 0;
	padding: 0;
	pointer-events: none;
	position: absolute;
	top: 100%;
	transition: opacity 0.3s ease;
	visibility: hidden;
	z-index: 20;
}

.autoTimerActionFlyout.open {
	opacity: 1;
	pointer-events: auto;
	visibility: visible;
}

.autoTimerActionFlyout .autoTimerAction {
	color: #ddd;
	cursor: pointer;
	padding: 0.5em 1em 0.5em 0.75em;
	white-space: nowrap;
}

.autoTimerActionFlyout .autoTimerAction i {
	margin-right: 0.5em;
}

.autoTimerActionFlyout .autoTimerAction:active {
	background-color: rgba(102, 153, 221, 0.2);
	color: #fff;
}

.timerItem .stateIcon,
.timerItem .testState,
.timerItem .box,
.timerItem .type,
.autoTimerItem .stateIcon,
.autoTimerItem .box,
.autoTimerItem .type,
.epgTable .timer {
	text-align: center;
	vertical-align: middle;
}

.autoTimerItem .meta {
	white-space: nowrap;
}
.autoTimerItem .meta i {
	color: #aaa;
}

.autoTimerItem:not(.autoTimerDisabled) .meta .timeRange,
.autoTimerItem:not(.autoTimerDisabled) .meta .timeRange i,
.autoTimerItem:not(.autoTimerDisabled) .meta .dateRange,
.autoTimerItem:not(.autoTimerDisabled) .meta .dateRange i,
.autoTimerItem:not(.autoTimerDisabled) .meta .weekdays,
.autoTimerItem:not(.autoTimerDisabled) .meta .weekdays i {
	color: #6af;
}

.autoTimerItem .filter {
	text-align: right;
}

.autoTimerItem .sender a {
	color: #ddd;
}

.autoTimerItem .more {
	color: #aaa;
	font-style: italic;
}

.autoTimerItem .sender hr {
	border: none;
	border-top: 1px dashed #999;
	margin: 0.5em 0;
}

.timerItem[data-state="3"] .title,
.timerItem[data-state="3"] .seasonEpisode,
.timerItem[data-state="3"] .time,
.timerItem[data-state="3"] .length,
.timerItem[data-state="3"] .type,
.timerItem[data-state="3"] .sender,
.timerItem[data-state="3"] .autoTimer,
.timerItem[data-state="3"] .tags,
.timerItem[data-state="3"] a,
.autoTimerItem.autoTimerDisabled > :not(.actions),
.autoTimerItem.autoTimerDisabled a,
.epgItem .partialTimer {
	color: #aaa;
}

.timerItem .cryptIcon {
	color: #999;
}

.timerState0,
.timerState0 .iconBtn {
	color: #fff;
}
.timerState1,
.timerState1 .iconBtn {
	color: #cc0;
}
.timerState2,
.timerState2 .iconBtn {
	color: #6af;
}
.timerState3,
.timerState3 .iconBtn {
	color: #0e0;
}
.timerDisabled,
.timerDisabled .iconBtn,
.stateIcon.autoTimerDisabled,
.stateIcon.autoTimerDisabled i {
	color: #e00;
}

.movieItem .stateInfo,
.timerItem .stateInfo {
	font-size: 0.75em;
}

.stateInfo .timerState1,
.stateInfo.timerState1 {
	color: #cc0;
}
.stateInfo .timerState2,
.stateInfo.timerState2 {
	color: #6af;
}
.stateInfo .timerState3,
.stateInfo.timerState3 {
	color: #0c0;
}
.stateInfo .timerDisabled,
.stateInfo.timerDisabled {
	color: #c00;
}

.overlaps {
	color: #cc0;
}

.timerMeta .overlaps {
	float: right;
	margin-right: 0.5em;
}

.movieDirItem .count,
.movieDirItem .unwatched,
.movieDirItem .size,
.movieDirItem .length,
.movieDirItem .modified,
.movieDirItem .age,
.movieItem .sender,
.movieItem .tags,
.timerItem .testMsg,
.timerItem .sender,
.timerItem .tags,
.timerItem .autoTimer,
.autoTimerItem .meta,
.autoTimerItem .sender,
.autoTimerItem .bouquets,
.autoTimerItem .tags {
	font-size: 0.75em;
}

.timerItem.skip * {
	color: #999;
}

.actions {
	white-space: nowrap;
}

.actions .actionWrapper {
	position: relative;
}

/* Die Aktionen einer Tabellenzeile: eine Abkürzungsleiste (.actionFlyout) neben dem "..."-Auslöser, und darunter
   hängt das Menü. Beide sind Geschwister und nicht mehr ineinander verschachtelt - das Menü enthält seit dem
   16.09.2026 IMMER alle Aktionen, auch die, für die daneben ein Knopf steht, und muss deshalb auch dann stehen
   bleiben, wenn die Leiste auf schmalen Bildschirmen entfällt (siehe den @media-Block weiter unten).
   position:relative wandert von .actionWrapper hierher, damit das Menü an dieser Reihe hängt. */
.actions .rowActions {
	align-items: center;
	display: flex;
	gap: 0.25em;
	position: relative;
}

.actions .actionFlyout {
	display: flex;
	flex-direction: row;
	gap: 0.25em;
	padding: 0.25em 0;
}

.actions.actionsSmall .actionFlyout {
	padding-bottom: 0;
	padding-top: 0;
}

/* Dieselbe Aktion steht zweimal im Markup: als Icon-Knopf in der Leiste und als beschrifteter Eintrag im Menü
   (beide aus demselben Makro, siehe movielist.html). Was sie unterscheidet, macht allein diese Regel - in der
   Leiste ist die Beschriftung ausgeblendet und ihre Bedeutung steht im title-Tooltip.
   Kindselektor, damit ein verschachteltes Menü seine Beschriftungen behält. */
.actions .actionFlyout > button > span,
.actions .actionFlyout > a > span {
	display: none;
}

.actions button {
	background-color: transparent;
	border: none;
	color: white;
	cursor: pointer;
	padding: 0.25rem 0.25rem;
}

.actions.actionsSmall button {
	padding: 0.1rem 0.1rem;
}

th.actions > button,
th.actions .actionWrapper > button {
	padding-bottom: 0;
	padding-top: 0;
}

.actions button i {
	font-size: 1.2rem;
}

button[disabled] i,
.actions button[disabled] i {
	color: #999;
}

/* Schriftfarbe mit abdunkeln, nicht nur das Icon (siehe Regel darüber): sonst steht ein graues Icon neben
   hellem Text und der Button wirkt halb deaktiviert. Entspricht dem Vorgehen bei .defaultCheckboxLabel. */
button[disabled],
.actions button[disabled] {
	color: #999;
	cursor: not-allowed;
}

/* "Mehr"-Menü (vertikales Popup für seltener genutzte Action-Buttons) -------------------------- */

/* z-index 8 hält das Menü unter der Kopfzeile (z-index 10). Es hängt per position:absolute an seinem Button und
   wandert beim Scrollen mit; ohne den niedrigeren Wert schöbe es sich über die Kopfzeile, denn bei gleichem
   z-index gewinnt das im Dokument spätere Element. So verschwindet es beim Hochscrollen sauber dahinter.
   Die beiden Flyouts der Kopfzeile selbst sind davon nicht betroffen: sie liegen innerhalb deren Stapelkontext
   und stehen damit trotz der 8 über dem Seiteninhalt. */
.actions .moreFlyout {
	background-color: var(--surface-raised);
	border: 1px solid var(--control-border);
	border-radius: 10px;
	color: var(--control-text);
	display: none;
	flex-direction: column;
	gap: 0.1em;
	margin-top: 2px;
	padding: 0.4em;
	position: absolute;
	right: 0;
	top: 100%;
	z-index: 8;
}

.actions .moreFlyout.open {
	display: flex;
}

/* Abstände in rem, nicht em: Knöpfe erben die kleinere Schrift des Browsers (13,3px), Links die volle -
   in em stünde ein Link wie "Schnitt bearbeiten" zwischen lauter Knöpfen sichtbar weiter rechts. Die Werte sind die,
   die ein Knopf vorher hatte. */
.actions .moreFlyout button,
.actions .moreFlyout a {
	align-items: center;
	color: white;
	display: flex;
	gap: 0.5rem;
	justify-content: flex-start;
	padding: 0.333rem 0.625rem;
	text-align: left;
	text-decoration: none;
	white-space: nowrap;
	width: 100%;
}

.actions .moreFlyout button:active:not([disabled]),
.actions .moreFlyout a:active {
	background-color: rgba(102, 153, 221, 0.2);
	border-radius: 6px;
	color: #fff;
}

/* Dieselbe Symbolgröße wie ".actions button i" - sonst beginnt der Text eines Links früher als der eines Knopfs. */
.actions .moreFlyout a i {
	font-size: 1.2rem;
}

.actions .moreFlyout button span,
.actions .moreFlyout a span {
	font-size: 0.85rem;
}

/* Gruppentrenner innerhalb eines "Mehr"-Menüs (Abspielen/Bearbeiten/Suchen ...). Dieselbe Linie wie zwischen Haupt-
   und "Mehr"-Bereich des zusammengelegten Menüs schmaler Bildschirme, damit im selben Menü nicht zwei verschiedene
   Trenner stehen. Ein eigenes Element statt border-top am ersten Eintrag einer Gruppe: Welcher Eintrag das ist,
   hängt an {% if %}-Bedingungen und wäre im Template nicht verlässlich zu treffen. */
.actions .moreFlyout .moreFlyoutSeparator {
	border-top: 1px solid var(--control-border);
	margin: 0.3em 0;
}

.actions .moreFlyout button[disabled] span {
	color: #999;
}

/* Aufklappbare Gruppe innerhalb eines "Mehr"-Menüs (siehe bindMoreFlyoutGroups in chrome.js): dieselbe Form wie das
   Power-Untermenü im Hauptmenü (.flyout-item.has-submenu) - Pfeil rechts, eingerückte Einträge unter einer
   gestrichelten Linie. Die Gruppe klappt innerhalb des Menüs auf statt daneben, damit das Menü unter seinem Knopf
   bleibt (siehe scrollFlyoutIntoView). Das display steht am :not([hidden]), weil es sonst das hidden schlüge. */
.actions .moreFlyout .moreFlyoutGroupToggle::after {
	content: "▼";
	font-size: 0.7rem;
	margin-left: auto;
	padding-left: 1em;
}

.actions .moreFlyout .moreFlyoutGroup.open > .moreFlyoutGroupToggle::after {
	content: "▲";
}

/* Oben derselbe Abstand wie an einem .moreFlyoutSeparator, auf beiden Seiten der Linie: ohne ihn klebte sie am
   Gruppenknopf, und der erste Eintrag stand enger darunter als die übrigen untereinander. */
.actions .moreFlyout .moreFlyoutGroupItems:not([hidden]) {
	border-top: 1px dashed var(--control-border);
	display: flex;
	flex-direction: column;
	gap: 0.1em;
	margin-bottom: 0.2em;
	margin-top: 0.3em;
	padding-top: 0.3em;
}

.actions .moreFlyout .moreFlyoutGroupItems button,
.actions .moreFlyout .moreFlyoutGroupItems a {
	padding-left: 1.35rem;
}

/* Sortierung: Pille mit Kriteriums- und Richtungssymbol (siehe inc/tools.html#sort_flyout) -------- */

/* Die Höhe steht fest statt aus der line-height zu entstehen, damit die Pille exakt so hoch ist wie die
   Elemente daneben (dieselbe Begründung wie bei .defaultBtn) - auf den TMDB-Seiten steht sie inzwischen in
   der Filterleiste statt in der Kopfzeile, wo dieselbe --control-height gilt. Der Selektor ist bewusst
   spezifischer als ".actions button" (transparent, randlos), das ihr sonst die Fläche nähme. */
.actions .sortPill {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	display: inline-flex;
	gap: 0.1em;
	height: var(--control-height);
	justify-content: center;
	padding: 0 0.6em;
}

.actions .sortPill:active {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Das Richtungssymbol tritt gegenüber dem Kriterium zurück - es beantwortet nur die Nebenfrage. */
.actions .sortPill .sortPillDir {
	font-size: 0.9rem;
	opacity: 0.75;
}

/* Der eingestellte Eintrag bleibt im Menü sichtbar markiert, damit die zwei Symbole der Pille nicht die
   einzige Auskunft darüber sind, wonach gerade sortiert wird. */
.actions .moreFlyout .sortOption.active {
	background-color: var(--control-bg-hover);
	border-radius: 6px;
	color: var(--control-text-hover);
}

.actions .moreFlyout .sortOption.active span {
	font-weight: bold;
}

/* .actionWrapper steht beim Tonspur-Flyout in der Info-Box der Startseite (anders als sonst in einer Tabellenzelle
   oder einem Flex-Container) im Fließtext der "Läuft"-Überschrift. Als Block-Element würde es dort einen
   Zeilenumbruch erzwingen und das Icon unter statt neben den Text legen. inline-block hält es in der Zeile,
   position:relative bleibt für das absolut positionierte .moreFlyout erhalten (siehe .actions .actionWrapper).
   Am zweiten Einsatzort, der Kopfzeile, gilt das nicht - dort steht der Wrapper in einem Flex-Container und
   .globalActions .actions .actionWrapper überschreibt das inline-block wieder.
   vertical-align: bottom, weil .db-headline .iconBtn direkte Geschwister (z.B. den Info-Button) so ausrichtet -
   ohne das hier zu wiederholen, würde der Wrapper stattdessen sein eigenes Standard-"baseline" nutzen und
   dadurch höher sitzen als ein Button, der direkt (ohne Wrapper) in derselben Zeile steht. */
.audioTrackActions .actionWrapper {
	display: inline-block;
	vertical-align: bottom;
}

/* Der Tonspur-Auslöser ist zwar ein .iconBtn wie seine Nachbarn, steht aber zusätzlich in .actions - und
   ".actions button" (eine Klasse + ein Typ) ist spezifischer als ".iconBtn" und überschreibt dessen Maße. Beides
   hier zurückholen, sonst säße das Icon größer und um die 0.25rem Innenabstand nach oben versetzt daneben.
   Bei der Größe bewusst "inherit" statt eines festen Werts: die beiden Einsatzorte geben ihren Icons
   unterschiedliche Maße vor (1rem in der Info-Box via .content .db-info .db-headline .iconBtn, in der Kopfzeile
   2.5em via .globalActions). Bewusst nur der Auslöser und nicht ".audioTrackActions .iconBtn": das träfe auch die
   Schaltflächen im Flyout, die ihre Maße weiter unten selbst regeln. */
.audioTrackActions .toggleMoreFlyout {
	padding: 0 5px;
}

.audioTrackActions .toggleMoreFlyout i {
	font-size: inherit;
}

/* Tonspur-Flyout (siehe inc/audioTrackFlyout.html): bei einer laufenden Aufnahme trägt eine Zeile zwei
   Schaltflächen (umschalten, umschalten+zurückspulen) statt einer - die Buttonbreite 100% von .moreFlyout
   button passt dafür nicht, hier stehen sie stattdessen nebeneinander in einer flexiblen Zeile. */
/* Der "Läuft"-Kopf der Info-Box (.db-headline) schreibt Großschreibung und weite Laufweite für sich selbst vor -
   beides hier zurücknehmen, sonst erben es die Tonspurnamen mit. (Schaltflächen sind von text-transform nicht
   betroffen: Buttons setzen es kraft User-Agent-Stylesheet ohnehin zurück.) line-height ebenso auf normal, damit
   das Flyout unabhängig davon bleibt, was sein jeweiliger Einsatzort für seine eigene Zeile vorgibt. */
.audioTrackFlyout {
	letter-spacing: normal;
	line-height: normal;
	text-transform: none;
}

/* gap etwas weiter als die 0.2em von früher: der Kreis rechts (s.u.) braucht Luft zur Zeile, sonst berührt
   seine Umrandung fast den Tonspurnamen. */
.audioTrackFlyout .audioTrackRow {
	align-items: center;
	display: flex;
	gap: 0.4em;
}

.audioTrackFlyout .audioTrackRow button {
	flex: 1;
	width: auto;
}

.audioTrackFlyout .audioTrackRow button[data-rc] {
	flex: none;
}

/* Die Zeile ist als Ganzes klickbar (Tonspur umschalten) und trägt rechts eine zweite, eigenständige
   Schaltfläche (umschalten und dabei zurückspulen). Ohne eigene Fläche verschmilzt die mit der Zeile und liest
   sich wie deren Beschriftung. Sie ist eine reine Icon-Schaltfläche und bekommt deshalb den Kreis der
   Formensprache (siehe :root); die kleine Höhe und die ruhige Grundfarbe halten sie als Zweitaktion hinter der
   Zeile zurück, die ja die häufigere Handlung trägt. Der Ruhezustand muss die Klickbarkeit allein zeigen -
   bedient wird per Touch, und Hover-Effekte gibt es in dieser Anwendung ohnehin nicht. */
.audioTrackFlyout .audioTrackRow .iconBtn {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	display: inline-flex;
	height: var(--control-height-small);
	justify-content: center;
	padding: 0;
	width: var(--control-height-small);
}

/* Im Kreis bezieht sich das Icon auf dessen Fläche, nicht mehr auf die bloßen Icons der Zeile - mit den 1.2rem
   aus ".actions button i" bliebe kaum Luft zum Rand. */
.audioTrackFlyout .audioTrackRow .iconBtn i {
	font-size: 1rem;
}

.audioTrackFlyout .audioTrackRow .iconBtn:active {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* font-size explizit wie .moreFlyout button span (dort per Nachfahren-Selektor gesetzt, hier ohne Button
   nicht getroffen) - sonst erbt die aktive Zeile die viel größere Schrift des "Läuft"-Kopfs und sticht
   trotz gleicher Zeilenhöhe wie die anderen Einträge unpassend heraus. */
.audioTrackFlyout .audioTrackName {
	align-items: center;
	color: #fff;
	display: flex;
	font-size: 0.85rem;
	gap: 0.6em;
	padding: 0.4em 0.75em;
	white-space: nowrap;
}

/* Icon so groß wie in den Schaltflächen der übrigen Zeilen (.actions button i). Ohne das erbt es die 0.85rem
   der Regel darüber und wäre als einziges kleiner - und weil die Icons die Tonspurnamen nach rechts schieben,
   stünde zugleich der aktive Name weiter links als die anderen. */
.audioTrackFlyout .audioTrackName i {
	font-size: 1.2rem;
}

/* Schnellzugriff in der Kopfzeile (siehe inc/quickAccess.html) ---------------------------------- */

/* Dieselbe Lage wie beim Tonspur-Auslöser: Er ist .iconBtn und steht zugleich in .actions - und ".actions button"
   (eine Klasse + ein Typ) ist spezifischer als ".iconBtn" und nähme ihm Innenabstand und Symbolgröße. Beides hier
   zurückholen, die Größe bewusst als "inherit": Sie kommt aus der Kopfzeile (2.5em, siehe .globalActions) und
   schrumpft auf schmalen Bildschirmen mit ihr. */
.quickAccessActions .toggleMoreFlyout {
	padding: 0 5px;
}

.quickAccessActions .toggleMoreFlyout i {
	font-size: inherit;
}

/* Ohne Einträge gibt es nichts aufzuklappen, dann verschwindet der Knopf ganz - wie der "Jetzt läuft"-Kasten, wenn
   nichts läuft (.nowPlayingEmpty). Im Markup bleibt der Rahmen trotzdem stehen, siehe inc/quickAccess.html. */
.quickAccessActions.quickAccessEmpty {
	display: none;
}

/* Wie beim Tonspur-Menü zurückzunehmen, was der Einsatzort für seine eigene Zeile vorgibt. */
.quickAccessFlyout {
	letter-spacing: normal;
	line-height: normal;
	text-transform: none;
}

/* Eine Zeile trägt fünf Elemente nebeneinander statt eines untereinander - dieselbe Ausnahme von der Breite 100%
   aus ".actions .moreFlyout button" wie bei .audioTrackRow. */
.quickAccessFlyout .quickAccessRow {
	align-items: center;
	display: flex;
	gap: 0.2em;
}

.actions .moreFlyout .quickAccessRow button {
	padding: 0.35em 0.4em;
	width: auto;
}

/* Der Titel nimmt den Rest der Zeile und wird notfalls abgeschnitten: Ein Aufnahmetitel kann sehr lang sein, und das
   Menü wird ohnehin nie verkleinert (siehe scrollFlyoutIntoView) - ohne Obergrenze wäre es irgendwann breiter als das
   Fenster. Vollständig steht er im title.
   flex: 1 richtet zugleich die Symbolspalten aller Zeilen aneinander aus, statt sie mit der Titellänge wandern zu
   lassen; min-width: 0 gehört dazu, sonst darf ein Flex-Element nicht unter seine Inhaltsbreite schrumpfen und das
   Abschneiden käme nie zum Zug.
   Seit 28.09.2026 ist der Titel ein Link (zur Aufnahme), und ".actions .moreFlyout a" machte ihn sonst zum
   Menüeintrag über die volle Breite - daher der Selektor mit dem Elementnamen. */
.actions .moreFlyout a.quickAccessTitle {
	display: block;
	flex: 1;
	font-size: 0.85rem;
	max-width: 22rem;
	min-width: 0;
	padding: 0.4em 0.25em;
	width: auto;
}

.actions .moreFlyout a.quickAccessTitle:hover {
	color: #6af;
}

/* Abgeschnitten wird im inneren <span>. Aus der Zeit, als der Titel einen data-tooltip trug: Der machte sein Element
   per position:relative zum Bezugsrahmen der Blase, ein overflow:hidden an derselben Stelle schnitt sie restlos weg
   (gemessen am 12.09.2026). Mit dem title des Links ist das gleichgültig, die Trennung schadet aber nicht. */
.quickAccessFlyout .quickAccessTitle > span {
	display: block;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Umbenennen und Entfernen treten hinter die drei Startknöpfe zurück: dünne Strichstärke (im Markup), gedämpfte
   Farbe, kein eigener Umriss. Sie sind die Pflege neben drei Wegen, die Aufnahme zu starten - und ein Fehlgriff beim
   Entfernen kostet einen Eintrag, den man erst wiederherstellen muss. Der Abstand steht vor dem ersten der beiden. */
.actions .moreFlyout .quickAccessRow button.quickAccessRename,
.actions .moreFlyout .quickAccessRow button.quickAccessRemove {
	color: var(--text-muted);
}

.actions .moreFlyout .quickAccessRow button.quickAccessRename {
	margin-left: 0.4em;
}

.actions .moreFlyout .quickAccessRow button.quickAccessRename i,
.actions .moreFlyout .quickAccessRow button.quickAccessRemove i {
	font-size: 1rem;
}

/* Der Umschalter zeigt immer nur den einen sinnvollen Eintrag: bei einer gesehenen Aufnahme "als ungesehen markieren"
   und umgekehrt (siehe movielist.html). Gilt in der Leiste wie im Menü - beide tragen dieselben zwei Knöpfe.

   Die drei Klassen sind Absicht und dürfen nicht auf ".movieItem .setWatched" zusammengestrichen werden: Die Regel,
   die einen Menüeintrag aufbaut (".actions .moreFlyout button"), setzt display:flex und läge mit einer Klasse
   weniger sonst darüber - dann stünden beide Einträge gleichzeitig im Menü. */
.movieItem[data-watched="true"] .setWatched,
.movieItem[data-watched="false"] .setUnwatched {
	display: none;
}

/* Der Knopf trägt zwei Symbole: eines für den Zustand und eines für die Aktion (siehe movielist.html). In der Leiste
   steht er ohne Beschriftung, dort gilt der Zustand; im Menü steht die Aktion als Text daneben, dort muss das Symbol
   zu ihr passen - sonst zeigt "Als gesehen markieren" ein durchgestrichenes Auge. */
.watchedIconAction {
	display: none;
}

.actions .moreFlyout .watchedIconState {
	display: none;
}

.actions .moreFlyout .watchedIconAction {
	display: inline;
}

.toggleBookmark .bookmarkIconActive,
.toggleBookmark .bookmarkIconInactive {
	display: none;
}
.toggleBookmark.active .bookmarkIconActive,
.toggleBookmark:not(.active) .bookmarkIconInactive {
	display: inline;
}

.addToLists .addToListsIconActive,
.addToLists .addToListsIconInactive {
	display: none;
}
.addToLists.active .addToListsIconActive,
.addToLists:not(.active) .addToListsIconInactive {
	display: inline;
}

/* Serien-Verknüpfen-Button neben der Breadcrumb (siehe movielist.html) - dieselbe Farbe wie .tmdbGotoSeries im
   Action-Menü der Zeilen, hier aber gegen .infoBar .iconBtn (color: var(--control-text)) durchgesetzt: */
.infoBar .iconBtn.tmdbGotoSeries {
	color: var(--group-mediathek-bright);
}

.iconBtn {
	background-color: transparent;
	border: none;
	color: white;
	cursor: pointer;
	padding: 0 5px;
}

/* In den Kopf- und Filterleisten stehen die Icon-Schaltflächen zwischen anderen Bedienelementen und werden
   deshalb wie diese gestaltet: rund, in derselben Höhe. Bewusst nur dort - in der Seiten-Kopfzeile und im
   Dialog-Kopf ist .iconBtn Teil der Chrome (Ein/Aus, Lautstärke, Schließen) und soll keine Fläche bekommen. */
.infoBar .iconBtn,
.filterBar .iconBtn {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	display: inline-flex;
	height: var(--control-height);
	justify-content: center;
	padding: 0;
	width: var(--control-height);
}

.infoBar .iconBtn:active,
.filterBar .iconBtn:active,
/* Aufgeklappte Filterleiste: derselbe Zustand wie bei .seg-btn.active und .tmdbIconBtn.active. */
.infoBar .filterToggleBtn.active {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Der Standardabstand der Schaltflächen stammt aus dem Textfluss und stört in diesen Leisten: sie sind
   Flex-Zeilen und regeln den Abstand über gap. Schlimmer noch, bei align-items:center wird die Margin-Box
   zentriert - ein Abstand nur unten hob die Schaltfläche um die Hälfte davon aus der Zeilenmitte. */
.infoBar .defaultBtn,
.infoBar .smallBtn,
.infoBar .miniBtn,
.filterBar .defaultBtn,
.filterBar .smallBtn,
.filterBar .miniBtn {
	margin: 0;
}

/* Schaltfläche mit Beschriftung: Pille. Die Höhe steht fest, statt aus der line-height zu entstehen - sonst
   stünde eine Schaltfläche, die nur ein Icon enthält, rund 9px flacher als die Beschriftete daneben. */
.defaultBtn,
.smallBtn {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.9rem;
	gap: 0.35rem;
	height: var(--control-height);
	justify-content: center;
	margin: 0 0.5em 0.25em 0;
	padding: 0 0.9rem;
	text-decoration: none;
}

.smallBtn {
	white-space: nowrap;
}

.defaultBtn i,
.smallBtn i {
	font-size: 1.1rem;
}

/* Kompakte Variante für dichte Zeilen (Filterleiste, Tabellenkopf): dieselbe Form, eine Nummer kleiner. */
.miniBtn {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.85rem;
	gap: 0.3rem;
	height: var(--control-height-small);
	justify-content: center;
	margin: 0 0 0.25em 0;
	padding: 0 0.7rem;
	vertical-align: middle;
}

.defaultBtn:active:not([disabled]),
.smallBtn:active:not([disabled]),
.miniBtn:active:not([disabled]) {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

.defaultBtn[disabled],
.smallBtn[disabled],
.miniBtn[disabled] {
	background-color: var(--control-bg-disabled);
	border-color: var(--control-border-disabled);
	color: var(--control-text-disabled);
}

.defaultBtn:focus-visible,
.smallBtn:focus-visible,
.miniBtn:focus-visible {
	border-color: var(--control-border-hover);
	outline: none;
}

/* Schaltfläche ohne Beschriftung: rund und so breit wie hoch - dieselbe Form wie die "..."-Menüs und die
   Zurück-/Blätter-Buttons. Die Breite folgt der Höhe der jeweils mitgegebenen Größe, .iconOnlyBtn wird sowohl
   mit .smallBtn als auch mit .miniBtn kombiniert (siehe epg.html bzw. autotimer.html). */
.iconOnlyBtn {
	border-radius: 50%;
	min-width: auto;
	padding: 0;
}

.defaultBtn.iconOnlyBtn,
.smallBtn.iconOnlyBtn {
	width: var(--control-height);
}

.miniBtn.iconOnlyBtn {
	width: var(--control-height-small);
}

.iconOnlyBtn i {
	display: block;
	margin: 0;
}

.defaultCheckbox {
	display: none;
}

/* Beschriftetes Kästchen als Pille - es verhält sich wie eine Schaltfläche zum Ein-/Ausschalten. */
.defaultCheckboxLabel {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-size: 0.9em;
	gap: 0.4em;
	line-height: 1em;
	padding: 0.35em 0.8em;
}

.defaultCheckboxLabel:active {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

.defaultCheckbox:disabled + .defaultCheckboxLabel {
	color: #999;
	cursor: not-allowed;
}

/* flex-shrink: 0 ist zwingend: das Label ist inline-flex, der Marker also ein Flex-Item. Ohne die Regel wird
   er zusammengedrückt, sobald der Text umbricht (schmales Display, langer Text) - der Marker ist dann schmaler
   als hoch und der Text rutscht nach links. Gleiches gilt für .defaultRadioLabel::before: */
.defaultCheckboxLabel::before {
	background-color: var(--page-bg);
	border: 1px solid var(--control-border);
	border-radius: 4px;
	content: "";
	display: inline-block;
	flex-shrink: 0;
	height: 1em;
	line-height: 1em;
	margin-right: 0.6em;
	width: 1em;
}

.defaultCheckbox:checked + .defaultCheckboxLabel::before {
	background-color: var(--control-border);
	border: 1px solid var(--control-border);
	border-radius: 4px;
	content: "✓";
	color: #fff;
	display: inline-flex;
	font-weight: bold;
	text-align: center;
}

.defaultCheckbox-x:checked + .defaultCheckboxLabel::before {
	content: "✘︎";
}

/* Radiobutton-Pendant zu .defaultCheckbox: gleiches Muster (verstecktes Input + Label mit
   gezeichnetem Marker), nur rund statt eckig und ohne Häkchen. */
.defaultRadio {
	display: none;
}

.defaultRadioLabel {
	align-items: center;
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-size: 1em;
	gap: 0.4em;
	line-height: 1em;
}

.defaultRadio:disabled + .defaultRadioLabel {
	color: #999;
	cursor: not-allowed;
}

.defaultRadioLabel::before {
	background-clip: content-box;
	background-color: transparent;
	border: 1px solid var(--control-border);
	border-radius: 50%;
	box-sizing: border-box;
	content: "";
	display: inline-block;
	flex-shrink: 0;
	height: 1em;
	line-height: 1em;
	margin-right: 0.6em;
	padding: 2px;
	width: 1em;
}

/* background-clip: content-box sorgt dafür, dass die Füllung innerhalb des Rahmens bleibt (Punkt in
   der Mitte statt Fläche bis zum Rand) - der Rahmen bleibt so auch im ausgewählten Zustand sichtbar.
   Der Punkt ist bewusst hell und nicht in der Rahmenfarbe: er ist die Markierung, wie das Häkchen bei
   .defaultCheckbox, und muss sich vom Rahmen absetzen. */
.defaultRadio:checked + .defaultRadioLabel::before {
	background-color: var(--text);
}

.editItem.active {
	background-color: var(--control-bg);
}

/* Edit-Form ------------------------------------------------------------------------------------ */

.editForm {
	background-color: var(--surface);
	border: 1px solid var(--line);
	border-radius: 5px;
	height: fit-content;
	margin: 1em 0 0 0;
	max-height: calc(100dvh - 6em);
	max-width: 29em;
	overflow-y: auto;
	padding: 1em 0.5em 1em 1em;
	position: sticky;
	scrollbar-gutter: stable;
	top: 5em;
}

/*.editMovieForm {
	min-width: 30em;
}

.editTimerForm {
	min-width: 30em;
}*/

/* Knapp gehaltener Zeilenabstand: die Bedienelemente sind mit der Pillenform höher geworden, das Formular soll
   aber weiterhin ohne senkrechtes Scrollen auf ein Tablet passen. */
.editForm .form-group {
	margin-bottom: 1.1em;
	min-height: 1.5em;
	overflow: hidden;
}

.editForm > .form-group:last-child {
	margin-bottom: 0;
}

.editForm #prevEditBtn,
.editForm #nextEditBtn,
.editForm #closeEditBtn {
	font-size: 1.2em;
	position: absolute;
	top: 0.5em;
}
.editForm #prevEditBtn {
	right: 3.75em;
}
.editForm #nextEditBtn {
	right: 2em;
}
.editForm #closeEditBtn {
	right: 0.25em;
}

.editForm button[disabled] i {
	color: #999;
}

.editForm .fieldLabel {
	display: block;
	font-weight: bold;
	margin-bottom: 0.3em;
}

.editForm .fieldLabelIcon {
	color: #aaa;
	display: inline-block;
}

.editForm .fieldLabel #tagManageBtn {
	margin-left: 0.4em;
}

.editForm .fieldLabel .fieldLabelIcon {
	font-size: 0.8em;
	margin-left: 0.2em;
}

.editForm input[type="text"],
.editForm textarea {
	width: 100%;
}

.editForm input[type="date"],
.editForm input[type="time"] {
	width: min-content;
}

.editForm input[type="number"] {
	field-sizing: content;
	min-width: 3ch;
}

.editForm .checkbox-group,
.editForm .radio-group {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.hiddenCheckbox,
.hiddenRadio,
.editForm .checkbox-group input[type="checkbox"],
.editForm .radio-group input[type="radio"] {
	display: none;
}

/* Sichtbar nur für Vorleseprogramme: Der Text bleibt im Dokument und in der Überschriftenfolge, nimmt aber keinen
   Platz ein. Bewusst nicht display:none - das nähme ihn auch dort heraus. Die EPG-Seite trägt ihre Überschrift so,
   weil dort die Reiterzeile unmittelbar darunter ohnehin sagt, worum es geht, und die 68px besser dem Programm
   zugutekommen. */
.visuallyHidden {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	margin: 0;
	overflow: hidden;
	padding: 0;
	position: absolute;
	white-space: nowrap;
	width: 1px;
}

/* Auswahl über verstecktes Input plus beschriftetes Label - die Labels verhalten sich wie kleine Schaltflächen
   und folgen deshalb deren Formensprache; das gewählte Label ist ausgefüllt wie ein aktives Segment. */
.hiddenCheckbox + label,
.hiddenRadio + label,
.editForm .checkbox-group label,
.editForm .radio-group label {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-size: 0.9em;
	gap: 0.3rem;
	margin: 0;
	padding: 0.2rem 0.7rem;
}

.hiddenCheckbox + label:active,
.hiddenRadio + label:active,
.editForm .checkbox-group label:active,
.editForm .radio-group label:active {
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

.hiddenCheckbox:checked + label,
.hiddenRadio:checked + label,
.editForm .checkbox-group input[type="checkbox"]:checked + label,
.editForm .radio-group input[type="radio"]:checked + label {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
	font-weight: bold;
}

.editForm .radio-group #editDisabled1:checked + label {
	background-color: #c33;
	border-color: #e55;
}

.editForm #showLongDesc {
	font-family: monospace;
	font-size: 1.2em;
	margin: 0;
}

.editForm .form-actions,
.editForm .form-field {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: 0.5em;
}

.editForm .form-field span {
	line-height: 1.5rem;
}
.editForm .form-field .inputDesc {
	line-height: 1.7rem;
}

.editForm .form-field--nowrap {
	flex-wrap: nowrap;
}

.editForm .form-field--vertical {
	flex-direction: column;
}

.editForm .form-field + .form-field {
	margin-top: 0.5em;
}

.editForm .form-actions button {
	flex: auto 1;
	margin: 0;
}
.editForm .form-actions-equal-buttons button {
	flex: 1;
	margin: 0;
}

/* In .form-field sollen input/textarea so breit wie möglich sein, .btn soll rechts daneben nur so breit wie nötig sein */
.editMovieForm .form-field input[type="text"],
.editMovieForm .form-field textarea {
	flex: 1 1 auto;
}

/* In .form-field sollen input/textarea so breit wie möglich sein, .btn soll rechts daneben nur so breit wie nötig sein */
.editMovieForm .form-field .editFileExt,
.editMovieForm .form-field .btn {
	flex: 0 1 auto;
	line-height: 1.7rem;
	margin: 0;
}

.editForm .more,
#editLocationEmptyInfo {
	color: #aaa;
	font-style: italic;
}

#editTextFiltersInfo label {
	font-weight: bold;
}

.movieListTable.editing .length,
.movieListTable.editing .type,
.movieListTable.editing .size,
.movieListTable.editing .time,
.movieListTable.editing .sender,
.movieListTable.editing .tags,
.timerTable.editing .time,
.timerTable.editing .length,
.timerTable.editing .type,
.timerTable.editing .sender,
.timerTable.editing .tags,
.timerTable.editing .autoTimer,
.autoTimerTable.editing .type,
.autoTimerTable.editing .meta,
.autoTimerTable.editing .filter,
.autoTimerTable.editing .sender,
.autoTimerTable.editing .tags,
.autoTimerTable.editing .timerCount {
	display: none;
}

#selectServiceBtn,
#selectBookmarkLocationBtn {
	margin-left: 0.5rem;
}

.toggleFormGroup {
	color: #aaa;
	cursor: pointer;
}
.toggleFormGroup::before {
	content: "▶ ";
	line-height: 1.2em;
}
.toggleFormGroup.open::before {
	content: "▼ ";
}

/* Einstellungen -------------------------------------------------------------------------------- */

/* Menü links, gewählter Bereich rechts - und bewusst ohne die Kachel-/Kasten-Optik des übrigen Programms.
   Bis zum 03.09.2026 standen alle Bereiche als Stapel von .db-info-Kästen untereinander. Das skalierte nicht:
   Jeder neue Bereich machte die Seite unübersichtlicher, und in den schmalen Kästen kämpften Formulare und
   Tabellen ständig um Platz (zuletzt zwang die Boxen-Tabelle auf dem Tablet einen waagerechten Scrollbalken).
   Kästen sind für eine Übersicht gedacht, auf der alles gleichzeitig sichtbar sein soll - eine Einstellungsseite
   ist das Gegenteil davon. */
.settingsLayout {
	align-items: flex-start;
	display: flex;
	gap: 1.5rem;
}

.settingsNav {
	display: flex;
	flex: 0 0 13rem;
	flex-direction: column;
	gap: 0.2rem;
}

.settingsNavItem {
	align-items: center;
	border-radius: var(--field-radius);
	color: var(--control-text);
	display: flex;
	gap: 0.6rem;
	padding: 0.5rem 0.8rem;
	text-decoration: none;
}

/* Der gewählte Bereich trägt dieselbe Hervorhebung wie überall ein gewähltes Segment (siehe --control-bg-hover). */
.settingsNavItem.active {
	background: var(--control-bg-hover);
	color: var(--control-text-hover);
}

/* min-width: 0, damit eine breite Tabelle die Spalte nicht aufbläht, sondern in ihrem eigenen Rahmen scrollt
   (siehe .settingsTableWrap) - ein Flex-Kind schrumpft sonst nie unter seine Inhaltsbreite.
   Die Obergrenze deckelt die Zeilenlänge: Ohne sie lief die Trennlinie unter der Bereichsüberschrift bei 1500px
   Fensterbreite 1150px weit über ein Formular von 26rem - die Überschrift gehörte dann sichtbar zu nichts mehr.
   Sie muss aber die vier Spalten der Tabellen fassen (siehe .settingsTable td:has(input)), deshalb so großzügig. */
.settingsPanels {
	flex: 1 1 auto;
	max-width: 62rem;
	min-width: 0;
}

.settingsPanel {
	display: none;
}

.settingsPanel.active {
	display: block;
}

/* Dieselbe Form wie die Kopfzeile eines Kastens (siehe .content .db-info .db-headline): Die Seite verlässt zwar
   die Kachel-Optik, soll aber nicht aus der Formensprache fallen. */
.settingsPanelTitle {
	align-items: center;
	border-bottom: 2px solid var(--line);
	color: #fff;
	display: flex;
	font-size: 1.1rem;
	font-weight: bold;
	gap: 0.4rem;
	letter-spacing: 0.2em;
	margin: 0 0 0.8rem 0;
	padding-bottom: 0.4rem;
	text-transform: uppercase;
}

/* Abschließende Angabe unter einer Tabelle - etwas Luft nach oben, damit sie nicht an der letzten Zeile klebt. */
.settingsPanelFooter {
	margin-top: 1rem;
}

/* Der negative obere Abstand von .settingsHint ist dafür gedacht, den Text dicht unter ein Eingabefeld zu ziehen.
   Hier steht darüber aber eine Textzeile, und dort klebte er daran. */
.settingsPanelFooter + .settingsHint {
	margin-top: 0.4rem;
}

/* Derselbe Fall eine Stufe größer: Folgt der Hinweis auf eine Tabelle, zieht ihn der negative obere Abstand von
   .settingsHint an deren letzte Zeile heran - der Satz über die Senderlogos klebte damit an der Box-Zeile darüber
   und las sich wie ein Teil von ihr. Nach einer Tabelle braucht es mehr Luft als nach einer Textzeile, deshalb
   nicht die 0.4rem von oben. Trifft nur diese eine Stelle: Auf keine andere Tabelle der Seite folgt ein Hinweis. */
.settingsTableWrap + .settingsHint {
	margin-top: 1rem;
}

/* Einleitender Satz unter der Bereichsüberschrift - erklärt, was der Bereich überhaupt einstellt. Braucht mehr
   Luft nach unten als ein Hinweis unter einem Feld, weil eine Tabelle folgt. */
/* Ohne eigene Breitenbegrenzung: Die Zeilenlänge deckelt bereits .settingsPanels (62rem), und alles andere im
   Bereich - Tabellen, Listen, Formulare - nutzt genau diese Breite. Mit 46rem brach allein der Einleitungstext
   früher um als der Inhalt, den er erklärt. */
.settingsPanelIntro {
	margin: 0 0 1rem 0;
}

/* Nur auf schmalen Bildschirmen sichtbar (siehe die Media Query am Ende dieses Blocks): Dort ersetzt der
   gewählte Bereich das Menü, und ohne diesen Knopf käme man nur über die Zurück-Taste des Browsers zurück.
   Bewusst ein nacktes Chevron und kein .iconBtn: Der runde Knopf wöge in einer Überschrift zu schwer. */
.settingsBack {
	background: none;
	border: none;
	color: var(--control-text);
	cursor: pointer;
	display: none;
	font-size: 1.1rem;
	letter-spacing: normal;
	line-height: 1;
	padding: 0.2rem 0.3rem 0.2rem 0;
}

.settingsSubheadline {
	color: #ddd;
	font-size: 1rem;
	margin: 1.5rem 0 0 0;
}

.settingsRows {
	display: grid;
	gap: 0.5rem;
}

/* Anders als .content .db-row bewusst ohne space-between: Im schmalen Kasten standen Beschriftung und Wert an
   dessen beiden Kanten, hier ist der Bereich so breit, dass sie dann nichts mehr miteinander zu tun hätten. */
.settingsRow {
	display: flex;
	font-size: 0.9rem;
	gap: 0.5rem;
}

/* Weiß und fett statt blau: Blau ist auf dieser Seite den Verweisen vorbehalten, und ein Wert ist keiner. Auf der
   Systemseite (.content .db-value) bleibt das alte Blau - dort steht kein einziger Link zwischen den Werten, die
   Farbe ist also eindeutig. */
.settingsValue {
	color: var(--text);
	font-weight: bold;
}

/* Beschriftung über dem Feld statt daneben, und eine Obergrenze für die Breite: Die Eingaben hier sind kurz,
   ein Passwortfeld über die volle Bereichsbreite sähe nach Versehen aus. */
/* Die Breitenbegrenzung sitzt an den Eingabefeldern und nicht am Formular: Gemeint waren immer nur die Felder - ein
   Passwortfeld über die volle Bereichsbreite sieht nach Versehen aus. Am Kasten gedeckelt traf sie aber auch die
   Erläuterungen darin, und die brachen dadurch selbst auf einem quer gehaltenen Tablet um (11.09.2026 gemeldet),
   während Tabellen und Listen darunter die ganze Breite nutzten. */
.settingsForm {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	margin-top: 0.5rem;
}

/* Beschriftungen in der normalen Textfarbe, nicht gedämpft: Auf einer Einstellungsseite steht viel kurzer Text,
   und in --text-muted sahen Beschriftung und Erläuterung gleich aus, obwohl das eine zum Feld darunter gehört und
   das andere nur dabeisteht. Die Erläuterungen (.settingsHint) bleiben deshalb gedämpft - der Unterschied trägt
   jetzt die Gliederung. */
.settingsForm label {
	color: var(--text);
	font-size: 0.85rem;
}

.settingsForm input,
.settingsForm select {
	margin-bottom: 0.6rem;
	max-width: 26rem;
	width: 100%;
}

.settingsForm .defaultBtn {
	align-self: flex-start;
}

/* Eine Zwischenüberschrift innerhalb eines Einstellungs-Bereichs: Der Trakt-Bereich trägt zwei Dinge, die
   Verbindung und die Übertragung der Sammlung, und ohne Trennung liest sich das zweite als Fortsetzung des ersten.
   Deutlich kleiner als die Bereichsüberschrift (.settingsPanelTitle), mit Linie darüber statt darunter - so
   schließt sie den Abschnitt davor ab, statt den eigenen zu unterstreichen. */
.settingsSubTitle {
	border-top: 1px solid var(--line-subtle);
	font-size: 1rem;
	margin: 1.6rem 0 0.6rem 0;
	padding-top: 1.2rem;
}

/* Kontrollkästchen und Auswahlknöpfe stehen neben ihrer Beschriftung, nicht darüber wie die Eingabefelder - und das
   Feld darf dabei nicht die Breite eines Eingabefelds annehmen (siehe .settingsForm input).

   Größer als eine gewöhnliche Feldbeschriftung (0,85rem, siehe .settingsForm label), nämlich so groß wie die
   Erläuterungen davor und danach (.settingsHint): Eine Beschriftung benennt nur das Feld darunter, hier steht
   dagegen die Entscheidung selbst - und die war kleiner gesetzt als der Text, der sie erklärt. */
.settingsForm .settingsCheck {
	align-items: center;
	display: flex;
	font-size: 0.95rem;
	gap: 0.45rem;
}

.settingsForm .settingsCheck input {
	margin: 0;
	width: auto;
}

/* Was von einer Wahl darüber abhängt, rückt ein - so ist ohne Lesen zu sehen, dass es dazugehört. */
.settingsIndent {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	margin: 0.4rem 0 0.6rem 1.4rem;
}

/* Eine Erläuterung zwischen den Auswahlknöpfen braucht Luft nach oben: Ohne sie klebt sie an der Beschriftung
   darüber und liest sich wie deren zweite Zeile - gerade die Warnung zum Entfernen gehört aber zur Wahl als
   Ganzes, nicht zur letzten Option. */
.settingsIndent .settingsHint {
	margin-top: 0.5rem;
}

/* Ein Hinweis direkt unter einem Kästchen braucht denselben Abstand wie einer zwischen Auswahlknöpfen: .settingsHint
   zieht sich oben um 0.3rem zusammen, damit es unter einer Überschrift nicht auseinanderfällt - unter einer
   Beschriftung klebt es dadurch fest und liest sich wie deren zweite Zeile.

   Der Vorfahre im Selektor ist nötig, nicht Zierde: .settingsHint steht weiter unten in dieser Datei, und bei
   gleicher Spezifität gewinnt die spätere Regel - eine Klasse allein bliebe hier wirkungslos (gemessen: 0 px
   Abstand). Derselbe Fallstrick wie bei den body.portalMode-Regeln. */
.settingsForm .settingsCheckHint {
	margin-top: 0.6rem;
}

/* Die Warnung zum Herausnehmen gilt nur für diese eine Option und erscheint deshalb erst, wenn sie gewählt ist.
   Bewusst allein per CSS und ohne JavaScript - dasselbe Muster wie beim FTP-Port der Dreambox (siehe
   .boxAdvanced:has(...)): So stimmt die Anzeige schon beim Aufbau der Seite und nicht erst beim ersten Klick. */
.settingsIndent:has(input[value="remove"]:not(:checked)) .traktRemoveWarning {
	display: none;
}

/* Zwei Schaltflächen nebeneinander statt untereinander; .settingsForm .defaultBtn richtet sie sonst einzeln links
   aus und stapelt sie. Umbrechend, damit sie auf dem Handy nicht über den Rand laufen. */
.settingsActionRow {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 0.4rem;
}

/* Auf schmalen Bildschirmen passen die Spalten nicht nebeneinander, und eine Tabelle schrumpft nicht unter ihren
   Inhalt - ohne diesen Rahmen ragte sie über die Kante hinaus und die Aktionssymbole standen sichtbar außerhalb
   (gemessen: 8px über den Rand, bei 390px Fensterbreite).
   Der Rahmen fängt das ab und macht daraus waagerechtes Scrollen. Auf breiten Bildschirmen ändert sich nichts:
   overflow-x: auto zeigt den Balken nur, wenn es tatsächlich etwas zu scrollen gibt. */
.settingsTableWrap {
	max-width: 100%;
	overflow-x: auto;
}

.settingsTable {
	margin-top: 0.5rem;
	width: 100%;
}

/* Mehr Luft als die globalen 3px (siehe "th, td"): Jene sind auf dichte Listen mit hunderten Zeilen ausgelegt,
   hier stehen Eingabefelder in den Zellen. Die bringen ihren eigenen Rahmen mit und klebten damit sichtbar
   aneinander - zwischen zwei Feldern lagen 6px, weniger als die Höhe ihrer eigenen Rundung.
   Die Kopfzeile behält etwas mehr als die Zeilen darunter: Sie ist eine gefüllte Fläche und wirkt sonst gedrückt. */
.settingsTable th {
	padding: 0.45rem 0.5rem;
}

.settingsTable td {
	padding: 0.3rem 0.5rem;
}

/* Unter dem Tabellenkopf noch einmal mehr: Er ist eine zusammenhängende Fläche mit eigenem Hintergrund, und ein
   Feld unmittelbar darunter wirkte, als gehörte es hinein statt darunter. Die Luft auf beide Seiten verteilt,
   weil eine Tabellenzeile keinen Außenabstand kennt. */
.settingsTable thead th {
	padding-bottom: 0.55rem;
}

.settingsTable tbody tr:first-child td {
	padding-top: 0.75rem;
}

/* Nur Eingabefelder füllen ihre Spalte - in ein Auswahlfeld tippt niemand etwas Langes, und über die halbe
   Spaltenbreite gezogen sah die Rollenauswahl aus, als fehlte ihr etwas (gemessen 290px für "admin"). */
.settingsTable input {
	width: 100%;
}

/* Ohne Untergrenze bestimmt der Inhalt die Spaltenbreite, und ein leeres Feld (etwa ein noch nicht gesetzter
   FTP-Benutzer) fiele auf wenige Pixel zusammen. Nur Zellen mit Eingabefeld, damit die Spalte mit den
   Aktionssymbolen schmal bleiben darf. */
.settingsTable td:has(input),
.settingsTable td:has(select) {
	min-width: 8rem;
}

.settingsTable .settingsTableActions {
	text-align: right;
	white-space: nowrap;
}

/* Ports und HTTPS einer Dreambox: eine ausklappbare Zeile unter der eigentlichen, statt weiterer Spalten. Sie
   stehen fast immer auf den Vorgabewerten (80/8001/21, kein HTTPS) - als eigene Spalten würden sie die Tabelle
   dauerhaft verbreitern für etwas, das man einmal im Leben anfasst. */
/* Dieselbe Zeile bei den Aufnahmeorten (Netzlaufwerk, Papierkorb) - mit eigener Klasse, weil settings.js die
   Box-Zeilen über .boxAdvancedRow[data-id] findet und eine Orts-Zeile mit gleicher Id sonst mitgriffe. */
.boxAdvancedRow,
.locAdvancedRow {
	display: none;
}

.boxAdvancedRow.open,
.locAdvancedRow.open {
	display: table-row;
}

/* Eine leichte Fläche darunter, damit die aufgeklappten Felder sichtbar zu der Zeile darüber gehören: Ohne sie
   stand der Hinweistext frei zwischen zwei Boxen und sah aus, als gälte er für die folgende. */
.boxAdvancedRow.open > td,
.locAdvancedRow.open > td {
	background: rgba(102, 153, 221, 0.07);
	padding-bottom: 0.6rem;
}

/* Der negative Abstand von .settingsHint zieht den Text dicht unter ein Feld - hier steht er unter einer ganzen
   Zeile von Feldern und braucht Luft nach oben statt nach unten. */
.boxAdvancedRow .settingsHint,
.locAdvancedRow .settingsHint {
	margin: 0.5rem 0 0 0;
}

.boxAdvanced {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 1.2rem;
}

/* Dieselbe Textfarbe wie die Beschriftungen der übrigen Formulare (siehe .settingsForm label). */
.boxAdvanced label {
	align-items: center;
	color: var(--text);
	display: flex;
	font-size: 0.85rem;
	gap: 0.4rem;
	white-space: nowrap;
}

/* Ohne das zögen die Felder über die ganze Zeilenbreite (siehe ".settingsTable input"), was in einer Zelle mit
   colspan die volle Tabelle ist. Eine Portnummer hat höchstens fünf Ziffern, ein Kontrollkästchen gar keine. */
.boxAdvanced input[type="number"] {
	width: 5.5rem;
}

.boxAdvanced .boxAdvancedCheck input {
	width: auto;
}

/* Mehrere Feldzeilen untereinander (Ports, dann Senderlogos) - derselbe Abstand wie zwischen umbrechenden Feldern
   einer Zeile; ohne ihn stieß das Pfadfeld unmittelbar an das Portfeld darüber. */
.boxAdvanced + .boxAdvanced {
	margin-top: 0.4rem;
}

/* .miniBtn trägt einen Außenabstand nach unten, der die Knöpfe hier gegenüber den Feldern daneben um knapp 2px nach
   oben verschob - align-items: center zentriert die Außenkante, nicht den Knopf. */
.boxAdvanced .miniBtn {
	margin: 0;
}

/* Der Pfad eines eigenen Papierkorbs nur, wenn auch "eigener Pfad" gewählt ist - wie der FTP-Port allein per CSS,
   damit ein eingetragener Pfad beim Hin- und Herschalten erhalten bleibt. */
.locAdvancedRow .locTrashPathField,
#newLocTrashPath {
	display: none;
}

.locAdvancedRow:has(.locTrashMode option[value="PATH"]:checked) .locTrashPathField {
	display: flex;
}

.settingsForm:has(#newLocTrashMode option[value="PATH"]:checked) #newLocTrashPath {
	display: block;
}

/* Ein Pfad braucht die Breite, die in der Zeile übrig ist - die Nachbarn sind ein Kästchen und eine Auswahl. */
.locAdvancedRow .locTrashPathField {
	flex: 1 1 22rem;
}

.locAdvancedRow .locTrashPath {
	width: 100%;
}

/* Ohne FTP gibt es auch keinen FTP-Port. Bewusst allein per CSS und ohne JavaScript: Das Feld bleibt im Markup und
   wird beim Speichern normal mitgelesen, so dass ein einmal eingetragener Port erhalten bleibt, wenn FTP
   zwischendurch aus und wieder an war. */
.boxAdvanced:has(.boxFtpEnabled:not(:checked)) .boxFtpPortField {
	display: none;
}

/* Die Warnung zu HTTPS nur, solange HTTPS auch angehakt ist. Das :has muss an der Zeile ansetzen und nicht an
   .boxAdvanced: Der Hinweis steht nicht in der Feldzeile, sondern darunter - gemeinsamer Vorfahre ist erst die
   Tabellenzeile. */
.boxAdvancedRow:has(.boxHttps:not(:checked)) .boxHttpsHint {
	display: none;
}

/* Ohne das ist die ausgegraute Attrappe (ein span) sichtbar größer als die echten Schaltflächen daneben: .iconBtn
   setzt keine Schriftgröße, und ein <button> erbt sie nicht, sondern bekommt die kleinere Vorgabe des Browsers.
   Beide auf die Schriftgröße der Tabelle zu setzen, gleicht sie an. */
.settingsTable .iconBtn {
	font-size: inherit;
}

/* Gliedert eine Tabelle des Einstellungsbereichs in Gruppen: Administratoren gegen die übrigen Rollen (siehe
   UserHandler#getUsers), Ordner gegen einzelne Aufnahmen (siehe ShareHandler#getOverview) - und die Cache-Tabelle der
   System-Seite nach Menüpunkten (siehe SystemStatus#getCacheRows). Bewusst die
   zurückhaltendste Linie der Anwendung (--line-subtle, "die Andeutung einer Kante innerhalb einer Fläche"): Sie
   gliedert eine Liste *innerhalb* eines Bereichs und darf deshalb nicht so schwer wiegen wie die Linie unter dessen
   Überschrift, die 2px in --line trägt (siehe .settingsPanelTitle).
   Die Luft darum herum macht die Gruppierung mehr aus als die Linie selbst. Sie muss auf zwei Zeilen verteilt
   werden - unter der letzten davor und über der ersten danach -, weil eine Tabellenzeile keinen Außenabstand
   kennt. Dafür das :has() auf die Vorgängerzeile; einen Vorgänger-Selektor gibt es sonst nicht. */
.settingsTable .settingsGroupStart td,
.cacheTable .settingsGroupStart td {
	border-top: 1px solid var(--line-subtle);
	padding-top: 0.7rem;
}

.settingsTable tr:has(+ .settingsGroupStart) td,
.cacheTable tr:has(+ .settingsGroupStart) td {
	padding-bottom: 0.7rem;
}

/* Die Cache-Tabelle schließt mit derselben Linie ab, die ihre Gruppen trennt (Wunsch des Nutzers) - sonst endete die
   letzte Gruppe offen, während jede andere eine Kante hat. */
.cacheTable tbody tr:last-child td {
	border-bottom: 1px solid var(--line-subtle);
	padding-bottom: 0.7rem;
}

/* Erläuterung unter einem Feld - etwa welches ffmpeg die automatische Suche tatsächlich gefunden hat. Steht
   unmittelbar am Feld statt in einer Fußnote: Sie beantwortet die Frage, die man beim Ausfüllen hat. */
/* Erklärender Fließtext, kein Kleingedrucktes - deshalb in normaler Textfarbe und mit dem Zeilenabstand der
   Hilfeseite, an der sich das hier ausrichtet. Grau auf Dunkelblau war schlicht schwer zu lesen (11.09.2026 vom
   Nutzer gemeldet), und bei 0.85rem standen die Zeilen zusätzlich so dicht, dass ein dreizeiliger Hinweis wie ein
   Block wirkte.

   Gedämpft bleibt, was wirklich Nebensache ist - dafür gibt es .tmdbEmpty und .settingsUserSelf. */
.settingsHint {
	color: var(--text);
	font-size: 0.95rem;
	line-height: 1.6;
	margin: -0.3rem 0 0.6rem 0;
	overflow-wrap: anywhere;
}

/* Blau heißt hier ab jetzt "anklickbar" - genau wie auf der Hilfeseite (.helpSection a). Werte tragen es nicht mehr,
   sonst wäre die Farbe zweideutig, siehe .settingsValue. */
.settingsHint a {
	color: #6af;
}

/* Ein weiterer Gedanke innerhalb desselben Hinweises (Befund - Warnung - Bezugsquelle, siehe settings.html): Mit
   bloßem <br/> klebten die drei aneinander und lasen sich wie ein Absatz.

   Der Abstand muss größer sein als der zwischen zwei Zeilen desselben Absatzes, sonst trennt er nichts - bei 0.95rem
   und line-height 1.6 sind das 0.57rem, und die früheren 0.5rem lagen sogar darunter. */
.settingsHintPart {
	margin-top: 0.9rem;
}

/* Das wirklich Nebensächliche innerhalb eines Hinweises - seit der Hinweis selbst in normaler Textfarbe steht,
   braucht es dafür eine eigene Klasse (siehe .settingsHint). */
.settingsHintAside {
	color: var(--text-muted);
}

/* Der Pfad ist die Antwort, der Rest drumherum nur Beschriftung. Derselbe gedämpfte Blauton wie die
   Festbreitenschrift der Hilfeseite (.helpSection code) - und bewusst ein anderer als das kräftige Blau der
   Verweise daneben: Was anklickbar ist, soll sich von dem unterscheiden, was nur hervorgehoben ist. */
.settingsHint code,
.settingsPath {
	color: #68c;
	font-family: monospace, monospace;
	font-size: 0.95em;
}

.settingsHintWarn {
	color: #e55;
	margin-right: 0.35em;
}

/* "(gesetzt)" hinter der Beschriftung eines Geheimnisses, das nicht angezeigt wird - grün wie überall das
   Erledigte (siehe --accent-watched). */
.settingsIsSet {
	color: var(--accent-watched);
	font-size: 0.85em;
}

/* Der Gerätecode für die Trakt-Anmeldung (siehe trakt.js). Er wird auf einem anderen Gerät abgetippt, also zählt
   hier nur Lesbarkeit: groß, mit weiten Zeichenabständen und in einer Schrift, die 0 und O auseinanderhält. Das
   Blau ist dasselbe, das in der ganzen Anwendung einen Wert kennzeichnet (siehe .settingsHint code). */
/* Der Anmeldekasten ist eine Handlungsanweisung und kein Hinweistext - deshalb hebt er sich von .settingsHint ab:
   größere Schrift, mehr Luft nach oben. Vorher stand die eigentliche Aufforderung in derselben kleinen Schrift wie
   die Einleitung darüber und ging neben dem großen Code unter. */
.traktCodeBox {
	margin-top: 1.2rem;
}

.traktStep {
	font-size: 1.05rem;
	line-height: 1.5;
	margin: 0 0 0.6rem;
}

/* Eine Schaltfläche, die mitten in einem Satz steht und deshalb wie ein Verweis aussieht - hier führt sie aber nicht
   fort, sondern öffnet einen Dialog. Ein .defaultBtn mitten im Fließtext risse die Zeile auseinander. */
/* Die Liste der übernehmbaren Filme im Dialog (siehe inc/traktNewMoviesDialog.html). Eine Zeile je Film, damit die
   Kästchen untereinander stehen und sich schnell abhaken lassen. */
.traktNewMoviesToolbar {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	margin-bottom: 0.8rem;
}

.traktNewMoviesCount {
	color: var(--text-muted);
	margin-left: auto;
}

.traktWarn {
	background: #3a2a2a;
	border-radius: 4px;
	color: var(--text);
	margin: 0 0 0.9rem;
	padding: 0.5rem 0.7rem;
}

.traktWarn i {
	color: #e55;
	margin-right: 0.4em;
}

/* Die Liste selbst scrollt, nicht der Dialog: Sie bekommt den Rest der Höhe und ihren eigenen Rollbalken - dieselbe
   Aufteilung wie bei den Treffern der Folgensuche (siehe .tmdbEpisodeSearchResults). Ohne overflow-y dehnte sie den
   Dialog über den Bildschirm hinaus, und die letzten Einträge waren unerreichbar. */
.default-dialog-tall .traktNewMoviesList {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
}

.traktNewMovieRow {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	padding: 0.15rem 0;
}

/* Ein Eintrag, den es bei TMDB nicht mehr gibt (bei Trakt bleiben solche stehen, dort sind z.B. Sportereignisse
   erlaubt). Er lässt sich nicht übernehmen, deshalb abgewählt, gesperrt und durchgestrichen - der Versuch wäre nur
   ein Fehlschlag am Ende des Laufs. Er bleibt trotzdem sichtbar: Sonst wunderte man sich, warum die Liste kürzer ist
   als die Zahl im Hinweis darüber. */
.defaultCheckboxLabel.traktNewGone {
	color: var(--text-muted);
	text-decoration: line-through;
}

.linkBtn {
	background: none;
	border: 0;
	color: #6af;
	cursor: pointer;
	font-family: inherit;
	font-size: inherit;
	padding: 0;
}

.linkBtn:hover {
	text-decoration: underline;
}

/* Der Hinweis, dass ein Verweis aus DreamProxy hinausführt (siehe inc/tools.html#ext_link_icon). Kleiner als der
   Text daneben und mit etwas Abstand: Es ist eine Randbemerkung zum Link, kein Teil seiner Beschriftung. */
.extLinkIcon {
	font-size: 0.8em;
	margin-left: 0.3em;
}

.traktLink {
	color: #6af;
	font-weight: 600;
	text-decoration: underline;
}

.traktCodeRow {
	align-items: center;
	display: flex;
	gap: 0.6rem;
}

/* Der verbundene Zustand - genauso laut wie die Aufforderung im unverbundenen, aus demselben Grund: Beides
   beantwortet die Frage, woran man gerade ist. */
.traktConnected {
	align-items: center;
	display: flex;
	font-size: 1.05rem;
	gap: 0.4rem;
	margin: 1.2rem 0 0.9rem;
}

.traktConnectedIcon {
	color: var(--accent-watched);
	font-size: 1.3rem;
}

/* Der Rückfall - gedämpft, damit er die eigentliche Aufforderung darüber nicht schwächt, aber in normaler Größe:
   Wer hier landet, muss ihn lesen können. */
.traktStepHint {
	color: var(--text-muted);
	margin: 0.9rem 0 0.3rem;
}

.traktWaiting {
	font-size: 1.05rem;
	margin: 1rem 0 0;
}

.traktUserCode {
	color: var(--text);
	font-family: monospace, monospace;
	font-size: 1.6rem;
	font-weight: bold;
	letter-spacing: 0.2em;
	user-select: all;
}

.settingsUserSelf {
	color: var(--text-muted);
	font-size: 0.85em;
	margin-left: 0.35em;
}

/* Name und das "(du)" dahinter gehören in eine Zeile: Umbrochen sah der Zusatz aus, als stünde dort ein zweiter
   Benutzer. Die Spalte wird dadurch so breit wie der längste Name - auf dem Handy heißt das etwas mehr
   waagerechtes Scrollen, was hier ohnehin schon nötig ist. Die Obergrenze dafür setzt das maxlength am Feld
   "Benutzer anlegen" (siehe settings.html). */
.settingsUserName {
	white-space: nowrap;
}

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

/* Der Punkt für "gerade aktiv" - grün wie überall in der Anwendung "gesehen"/erledigt (siehe --accent-watched). */
.settingsUserActive {
	background: var(--accent-watched);
	border-radius: 50%;
	display: inline-block;
	height: 0.5em;
	margin-right: 0.4em;
	vertical-align: middle;
	width: 0.5em;
}

/* Freigaben: je Konto eine Überschrift mit der Zahl und dem Knopf, der alle davon aufhebt. Der Knopf steht an der
   rechten Kante, weil er die Gruppe als ganze betrifft - die Papierkörbe der einzelnen Zeilen sitzen darunter in
   derselben Flucht (siehe .settingsTableActions). Umbrechen darf die Zeile, sonst würde der Knopf auf dem Handy
   die Zahl verdrängen. */
.shareGroupTitle {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-bottom: 0.5rem;
}

.shareGroupName {
	align-items: center;
	display: inline-flex;
	gap: 0.35em;
}

.shareGroupCount {
	color: var(--text-muted);
	font-size: 0.85em;
	font-weight: normal;
}

.shareGroupTitle .deleteUserSharesBtn {
	margin-left: auto;
}

.shareEmpty {
	align-items: center;
	color: var(--text);
	display: flex;
	font-size: 1rem;
	gap: 0.4em;
	margin-top: 0.8rem;
}

/* Feste Spaltenbreiten: Je Konto steht eine eigene Tabelle da, und mit automatischer Breite richtete sich jede
   nach ihrem eigenen längsten Eintrag - die Spalte "Art" begann dann in jeder Gruppe an einer anderen Stelle.
   Nebenwirkung und Absicht zugleich: Die Tabelle bleibt genau so breit wie der Bereich und scrollt nicht mehr
   waagerecht, der Name bricht stattdessen um. */
.shareTable {
	table-layout: fixed;
}

.shareTable .shareColKind {
	width: 9rem;
}

.shareTable .shareColDate {
	width: 9rem;
}

.shareTable .shareColActions {
	width: 3rem;
}

/* Eigene Klasse statt .shareTable: Die Spalten sind andere (Aufrufe/Wiedergaben statt Art), und die
   Aktionsspalte trägt zwei Symbole (Kopieren, Aufheben) statt eines. Die Breiten stehen hier ausdrücklich, weil
   "table-layout: fixed" ohne sie alle Spalten gleich breit macht - der Aufnahmetitel bekäme dann so viel Platz wie
   ein Datum. */
.shareLinkTable {
	table-layout: fixed;
}

.shareLinkTable .shareColDate {
	width: 9rem;
}

.shareLinkTable .shareColUntil {
	width: 14rem;
}

.shareLinkTable .shareColActions {
	width: 4.5rem;
}

.shareLinkColCount {
	text-align: center;
	width: 5.5rem;
}

/* Unter dem Datum statt daneben: Nebeneinander drängten Datum und Auswahlfeld die Spalte auf eine Breite, die dem
   Titel links fehlte. */
.shareLinkDurationSelect {
	margin-top: 0.3rem;
	max-width: 100%;
}

/* Der Hinweis unter einer Zwischenüberschrift: .settingsHint zieht sich mit einem negativen Rand nach oben an die
   Panel-Überschrift heran - unter einer h4 stieße er dort hinein. */
.settingsSubheadline + .settingsHint {
	margin-top: 0.35rem;
}

/* Die beiden Freigabe-Arten sichtbar trennen: Ohne Linie liefe die Übersicht der Links unmittelbar in die
   Überschrift der Benutzer-Freigaben, und beide läsen sich wie ein Block. */
[data-panel="freigaben"] .settingsTableWrap + .settingsSubheadline,
[data-panel="freigaben"] .shareEmpty + .settingsSubheadline {
	border-top: 1px solid var(--line-subtle);
	margin-top: 2rem;
	padding-top: 1.5rem;
}

/* Adresse und Kopieren-Knopf in einer Zeile. Eine eigene Zeile statt .default-dialog-actions: Jene ist für
   Schaltflächen gedacht, ist rechtsbündig und bringt einen Abstand nach oben mit, der hier den Zusammenhang zum
   Titel darüber zerrisse. */
.shareLinkDialogUrlRow {
	align-items: center;
	display: flex;
	gap: 0.4rem;
	margin: 0.8rem 0 0.5rem 0;
}

/* Breit genug, dass eine übliche Adresse ganz hineinpasst - sie ist der Inhalt dieses Dialogs, und eine
   abgeschnittene Adresse sieht aus, als stimmte etwas nicht. Auf dem Handy begrenzt der Bildschirm. */
#shareLinkDialog {
	min-width: min(34rem, 92vw);
}

/* min-width: 0, sonst wächst das Feld über den Dialog hinaus: Ein Eingabefeld bringt eine Mindestbreite mit, die
   ein Flex-Kind sonst nie unterschreitet - die Adresse ist aber lang. */
.shareLinkDialogUrl {
	flex: 1;
	min-width: 0;
}

/* Zwei Zeilen in einer Zelle: oben, was freigegeben ist, darunter wo es liegt. Der Ordner steht klein darunter,
   weil derselbe Aufnahmetitel an mehreren Stellen vorkommen kann - ohne ihn ließen sich zwei Zeilen nicht
   auseinanderhalten. */
/* Pfade haben keine Trennstellen, an denen ein Umbruch von selbst passieren würde - ohne das hier stünde ein
   langer Ordnername über die Spalte hinaus. */
.shareEntryName {
	overflow-wrap: anywhere;
}

.shareEntryBelow {
	color: var(--text-muted);
	font-size: 0.85em;
}

.shareEntryKind {
	align-items: center;
	display: flex;
	gap: 0.35em;
	white-space: nowrap;
}

.shareEntryCount {
	color: var(--text-muted);
	font-size: 0.85em;
}

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

/* Übriggebliebene Dateien (siehe movieleftovers.html) --------------------------------------------
   Feste Spaltenbreiten aus demselben Grund wie bei .shareTable: Ohne sie verteilt der Browser den Platz nach dem
   Inhalt, und der Dateiname - die einzige Spalte, die wirklich Breite braucht - bekäme so viel wie ein Datum. */
.leftoverTable {
	table-layout: fixed;
	width: 100%;
}

.leftoverTable .leftoverNum {
	text-align: right;
	width: 6rem;
}

/* Symbol und Text als ein Block, wie in der Art-Spalte der Freigaben (.shareEntryKind). Der Text darf umbrechen -
   "Begleitdatei mit unpassendem Namen" passt in keine Spaltenbreite, die dem Dateinamen links noch Platz lässt.

   Das Flex steht am span und nicht an der Zelle: Ein "display: flex" auf einem td nimmt dieses aus dem Tabellenfluss,
   es zählt dann nicht mehr als Spalte - gemessen kam bei 390px eine 123px breite Aktionsspalte neben einem 123px
   breiten Dateinamen heraus. */
.leftoverTable .leftoverKind {
	color: var(--text-muted);
	width: 13rem;
}

.leftoverKindLabel {
	align-items: baseline;
	display: inline-flex;
	gap: 0.35em;
}

.leftoverTable .leftoverDate {
	color: var(--text-muted);
	white-space: nowrap;
	width: 9rem;
}

.leftoverTable .leftoverAction {
	text-align: right;
	width: 3rem;
}

/* Ein Enigma2-Dateiname ist lang und hat keine Trennstellen, an denen ein Umbruch von selbst geschähe - ohne das
   hier stünde er über die Spalte hinaus (dieselbe Falle wie bei .shareEntryName). */
.leftoverName {
	overflow-wrap: anywhere;
}

.leftoverDir {
	color: var(--text-muted);
	font-size: 0.85em;
	overflow-wrap: anywhere;
}

/* Ordner und - auf schmalen Bildschirmen - die Art in einer Zeile unter dem Dateinamen. Umbrechend, weil beides
   zusammen auf einem Telefon selten nebeneinander passt. */
.leftoverSub {
	display: flex;
	flex-wrap: wrap;
	gap: 0.15rem 0.6rem;
}

/* Breit trägt die eigene Spalte die Art; hier wäre sie eine Wiederholung (siehe movieleftovers.html). Muss nach
   .leftoverKindLabel stehen - gleiche Spezifität, es gewinnt die spätere Regel. */
.leftoverKindInline {
	color: var(--text-muted);
	display: none;
	font-size: 0.85em;
}

/* Schmale Bildschirme: Menü und Bereich teilen sich den Platz nicht, sondern lösen einander ab - erst die Liste
   als ganze Seite, nach der Auswahl der Bereich mit Zurück-Knopf. Nebeneinander blieben von 390px Breite abzüglich
   des Menüs kaum 240px für das Formular übrig. */
@media (max-width: 640px) {
	.settingsLayout {
		display: block;
	}

	/* Als durchgehende Liste statt einzelner Pillen: Über die volle Breite gezogen sind es keine Schaltflächen
	   mehr, sondern Zeilen - dieselbe Form, die auch sonst auf dem Handy eine Auswahl trägt. */
	.settingsNav {
		gap: 0;
	}

	.settingsNavItem {
		border-bottom: 1px solid var(--line-subtle);
		border-radius: 0;
		padding: 0.9rem 0.4rem;
	}

	/* Das Chevron macht sichtbar, dass der Eintrag hier auf eine eigene Ansicht führt - anders als auf breiten
	   Bildschirmen, wo der Bereich einfach daneben stehen bleibt. */
	.settingsNavItem::after {
		color: var(--text-muted);
		content: "\203A";
		margin-left: auto;
	}

	/* Die Hervorhebung des gewählten Eintrags entfällt: Sobald ein Bereich offen ist, ist das Menü ohnehin nicht
	   mehr zu sehen, und beim Zurückgehen wäre eine hervorgehobene Zeile eine Aussage über nichts. */
	.settingsNavItem.active {
		background: none;
		color: var(--control-text);
	}

	/* Das Attribut setzt settings.js, sobald ein Bereich gewählt ist - auf breiten Bildschirmen ist es immer
	   gesetzt, deshalb steht diese Regel nur hier. */
	.settingsLayout[data-panel] .settingsNav {
		display: none;
	}

	/* Breiter als die 8rem auf großen Bildschirmen, nicht schmaler: Die Tabelle scrollt hier ohnehin waagerecht,
	   also kostet Breite nichts - abgeschnittener Text dagegen schon. Bei 8rem endete die Adresse als
	   "192.168.178.2" und der Platzhalter als "Passwort ges". */
	.settingsTable td:has(input),
	.settingsTable td:has(select) {
		min-width: 11rem;
	}

	/* Zurücknehmen, was "table td" weiter unten für schmale Bildschirme setzt: break-all trennt mitten im Wort,
	   und das zerlegte hier das "(du)" hinter dem eigenen Namen nach dem "d". Hier gefahrlos, weil in dieser
	   Tabelle nur kurze Wörter stehen - kein Dateiname, der für sich genommen breiter als die Spalte wäre
	   (dieselbe Überlegung wie bei .cacheTable). */
	.settingsTable td {
		overflow-wrap: break-word;
		word-break: normal;
	}

	.settingsBack {
		align-items: center;
		display: inline-flex;
	}

	/* Die Spalte "Seit" fällt weg, damit der Papierkorb ohne waagerechtes Scrollen erreichbar bleibt: Zurücknehmen
	   ist der Zweck dieser Liste, und das Datum ist die einzige Spalte, die nur berichtet. Bei der Benutzertabelle
	   steht dagegen in jeder Spalte etwas Veränderliches - die scrollt deshalb lieber. */
	.shareTable .shareColDate,
	.shareTable .shareEntryDate {
		display: none;
	}

	/* Bei 390px bleibt für die Art weniger Platz - aber nicht weniger als "Ordner (190)" braucht: Bei 7,5rem brach
	   ausgerechnet der Ordner mit den meisten Aufnahmen als einziger um. */
	.shareTable .shareColKind {
		width: 8.5rem;
	}

	.shareEntryKind {
		flex-wrap: wrap;
		white-space: normal;
	}

	/* Dieselbe Überlegung wie eine Regel weiter oben bei den Freigaben: Das Änderungsdatum ist die einzige Spalte,
	   die nur berichtet - der Papierkorb muss dagegen erreichbar bleiben, ohne seitwärts zu scrollen. */
	.leftoverTable .leftoverDate {
		display: none;
	}

	/* Die Art wandert unter den Dateinamen, statt zu verschwinden: Bei 390px blieben neben ihrer 13rem-Spalte und
	   den beiden rechten keine 40px für den Namen übrig, und der brach dann Buchstabe für Buchstabe um (gemessen:
	   8246px Seitenhöhe für neun Zeilen). */
	.leftoverTable .leftoverKind {
		display: none;
	}

	.leftoverKindInline {
		display: inline-flex;
	}

	/* Schmaler, damit der Dateiname den gewonnenen Platz auch bekommt - "801 Byte" ist der längste Wert. */
	.leftoverTable .leftoverNum {
		width: 5rem;
	}
}

/* Anmeldeseite --------------------------------------------------------------------------------- */

/* Steht für sich allein, ohne Kopfzeile und Seitenleiste (siehe login.html). Der Kasten sitzt waagerecht mittig und
   senkrecht im oberen Drittel statt exakt mittig: Auf dem Handy klappt beim Tippen die Tastatur auf, und ein mittig
   zentriertes Formular rutscht dann unter sie. */
.loginBody {
	align-items: center;
	background: var(--page-bg);
	display: flex;
	justify-content: center;
	min-height: 100dvh;
	padding: 1rem;
}

/* display und margin-top überschreiben die Regel für "main" weiter oben: Die trägt sonst das Flex-Layout der
   Hauptseite (Seitenleiste neben Inhalt) hier herein und stellt das Logo neben das Formular statt darüber. */
.loginBox {
	align-self: start;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 10px;
	display: block;
	margin-top: max(2rem, 12dvh);
	max-width: 22rem;
	padding: 1.5rem;
	width: 100%;
}

/* position: relative als Anker für das TEST-Schild: Es ist absolut positioniert (siehe .testTag) und landete ohne
   positionierten Vorfahren in der Ecke des Fensters statt neben dem Logo. */
.loginLogo {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	justify-content: center;
	margin-bottom: 1.5rem;
	position: relative;
}

.loginLogo img {
	height: 2.5rem;
}

.loginForm {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
}

.loginForm label {
	color: var(--text-muted);
	font-size: 0.85rem;
}

.loginForm input {
	margin-bottom: 0.75rem;
	width: 100%;
}

.loginSubmit {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--field-radius);
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	gap: 0.4rem;
	height: var(--control-height);
	justify-content: center;
	margin-top: 0.25rem;
	width: 100%;
}

.loginSubmit:active {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

.loginError {
	align-items: center;
	color: #e55;
	display: flex;
	font-size: 0.9rem;
	gap: 0.4rem;
	margin-bottom: 0.5rem;
}

/* Die öffentliche Freigabelink-Seite (shareLink.html). Die Aufnahme selbst trägt .recordingCard und braucht deshalb
   keine eigene Gestaltung - hier steht nur, was die Seite drumherum ausmacht: eine Spalte, die auf dem Handy die
   volle Breite nutzt und auf dem Schreibtisch breit genug für ein Video bleibt. */
.shareLinkBody {
	background: var(--page-bg);
	min-height: 100dvh;
	padding: 1rem;
}

.shareLinkPage {
	display: block;
	margin: max(1.5rem, 6dvh) auto 2rem auto;
	max-width: 46rem;
}

/* Erscheint erst mit der Wiedergabe (siehe shareLink.js). 16:9 von vornherein, damit die Karte darunter beim
   Einblenden nicht springt, sobald die Maße des Videos bekannt werden. */
.shareLinkVideo {
	aspect-ratio: 16 / 9;
	background: #000;
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	display: block;
	margin-bottom: 0.6rem;
	width: 100%;
}

.shareLinkStatus {
	color: var(--text-muted);
	font-size: 0.85rem;
	margin-top: 0.6rem;
	min-height: 1.2em;
	text-align: center;
}

/* Auf dieser Seite sind die beiden START-Knöpfe die einzige Handlung - auf dem Handy sollen sie deshalb die volle
   Breite bekommen statt in einer halben Zeile zu kleben, wie sie es in einer Liste vieler Karten täten.
   width: 100% muss dabei sein: Die Knopfgruppe ist selbst ein Flex-Kind der Karte und wäre sonst nur so breit wie
   ihr Inhalt - das "stretch" darin hätte dann nichts, worauf es strecken könnte. */
.shareLinkCard .recordingCardActions {
	align-items: stretch;
	flex-direction: column;
	width: 100%;
}

.shareLinkCard .recordingCardActions > button {
	height: var(--control-height);
	justify-content: center;
}

@media (min-width: 30rem) {
	.shareLinkCard .recordingCardActions {
		flex-direction: row;
		width: auto;
	}
}

/* Der abgelaufene Link: dieselbe Kachelform wie die Karte, nur mit der Meldung statt der Aufnahme. */
.shareLinkGone {
	align-items: center;
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	color: var(--text);
	display: flex;
	gap: 0.5rem;
	justify-content: center;
	padding: 1.2rem 1rem;
}

.shareLinkGone i {
	color: #e55;
}

/* Ohne Seitenmenü fehlt dem Inhalt der linke Rand, den sonst die Leiste beisteuert (siehe .main-content) - die
   Kacheln klebten an der Fensterkante. */
body.portalMode .main-content {
	padding: 1.2rem;
}

/* Alle Portal-Regeln mit "body" davor: Ohne das verlieren sie gegen gleich spezifische Regeln, die weiter unten in
   dieser Datei stehen - der Gesehen-Schalter der Folgenkachel blieb genau so sichtbar
   (".tmdbEpisodeInfoTop .tmdbToggleWatchedBtn", Zeile ~9020). Ein Element davor genügt, um zu gewinnen, und ist
   weniger fehleranfällig, als diesen Block ans Dateiende zu verschieben und dort zu vergessen.

   Kacheln im Portal: reduziert auf das, was ein Streaming-Konto etwas angeht (siehe AccessControl).
   Bewusst über CSS und nicht über Bedingungen in den Makros: inc/tmdbMeta.html wird von vielen Seiten benutzt, eine
   Handvoll Regeln hier erwischt alle auf einmal, ohne gemeinsam genutzte Makros umzubauen. Der Preis ist, dass das
   Markup im Quelltext stehen bleibt - bei Gesehen-Status und Bewertungen ist das vertretbar, bei Geheimnissen wäre es das
   nicht. */
body.portalMode .tmdbBadge.watched,
body.portalMode .tmdbTileWatchedCount,
body.portalMode .tmdbTileMoreActions,
body.portalMode .tmdbTileActions,
body.portalMode .playFolderNextEpisode,
body.portalMode .playMovie {
	display: none;
}

/* Beide Balken raus - auch der für die Sammlung. Er beantwortet die Frage "wie vollständig ist mein Bestand", und
   die stellt sich nur, wer sammelt. Ob überhaupt etwas da ist, sagt weiterhin das Archiv-Zeichen an der Kachel
   (grau, wenn nur teilweise); genaue Zahlen stehen auf der Detailseite. */
body.portalMode .tmdbProgress,
body.portalMode .tmdbProgressTip {
	display: none;
}

/* Die Bezeichnung der Fassung vor den beiden Stream-Knöpfen - nur bei mehreren, sonst stünden dort mehrfach
   dieselben zwei Knöpfe ohne Unterscheidung (siehe tmdbmoviedetail.html). */
.portalStreamLabel {
	color: var(--text-muted);
	font-size: 0.85rem;
	margin-right: 0.2rem;
	white-space: nowrap;
}

/* Sämtliche "..."-Menüs. Fast jeder .actionWrapper der Anwendung umschließt genau ein solches Menü, deshalb die eine
   Regel statt einer Aufzählung einzelner Stellen. Was darin an Erlaubtem stand - die Stream-Knöpfe - steht im Portal
   jetzt frei daneben (siehe tmdbmoviedetail.html). */
body.portalMode .actionWrapper {
	display: none;
}

/* Die Ausnahmen - und sie waren ein echter Fehler. Nachgezählt sind es 34 .actionWrapper, nicht 13, und vier davon
   sind kein "..."-Menü, sondern tragen Auskünfte, die einen Zuschauer sehr wohl angehen. Sie verschwanden trotzdem.

   Bei dreien fällt es nur im aufwendigeren Fall auf, was das Suchen erschwert hat: Eine einzelne Tonspur, ein einzelner
   Trailer und eine einzelne Bewertungsquelle stehen als schlichtes Element da und blieben sichtbar - erst bei mehreren
   wird daraus ein Klappmenü, und genau der informativere Fall fiel weg.

   - Sortier-Pille (inc/tools.html#sort_flyout): Sortieren ändert nichts, wie Suche und Filter, die bewusst dableiben.
     Sichtbar wurde es daran, dass die Filterzeile zu weit eingerückt aussah - der leere .sortActions-Container blieb
     als Flex-Element stehen und steuerte weiter seinen Abstand bei.
   - Bewertung (#ratingFlyout): Auf den Kacheln steht sie, auf der Detailseite fehlte sie.
   - Technik-Pillen (#techPills): Tonspuren und Untertitel der Aufnahme - was man vor dem Abspielen wissen will.
   - Trailer und lokale Videoclips (#videoLinks/#localVideoLinks): gehören zum Anschauen, nicht zur Verwaltung.

   Die pauschale Regel darüber bleibt bewusst stehen: Ein neu hinzugefügtes Menü ist damit im Portal automatisch weg,
   statt vergessen zu werden - dieselbe Richtung wie bei AccessControl. Neue Ausnahmen kommen hierher. */
body.portalMode .sortActions .actionWrapper,
body.portalMode .tmdbTechActions .actionWrapper,
body.portalMode .actionWrapper:has(> .tmdbRating),
body.portalMode .actionWrapper:has(> .tmdbYoutubeLink),
body.portalMode .actionWrapper:has(> .tmdbLocalVideoLink) {
	display: block;
}

/* Der Gesehen-Status gehört dem Admin, nicht dem Streaming-Nutzer: Er sagt nichts darüber aus, was *der* schon gesehen
   hat, und einen eigenen führt DreamProxy für ihn nicht. Deshalb überall weg, nicht nur unveränderbar. */
body.portalMode .tmdbToggleWatchedBtn,
body.portalMode .tmdbStat.watched,
body.portalMode .tmdbAddRecordingBtn {
	display: none;
}

/* "Verknüpfte Inhalte": weder anlegen noch lösen. Das sind von Hand gepflegte Bezüge des Admins (Abschlussfilm zu
   einer Serie und dergleichen) - ein Streaming-Nutzer soll sie sehen, aber nicht anfassen. */
body.portalMode .tmdbRelatedAddBtn,
body.portalMode .tmdbRelatedRemoveBtn {
	display: none;
}

/* Die beiden Stream-Knöpfe stehen im Portal frei statt in einem "..."-Menü, wo sie ihr Aussehen herbekamen - ohne
   diese Regeln waren sie unformatierte Browser-Schaltflächen (heller Grund, schwarze Schrift, 2px Rand).
   Sie erben deshalb hier dasselbe Aussehen wie der Abspielen-Knopf, den sie ersetzen. */
.tmdbRecordingChip .streamMovie,
.tmdbRecordingChip .streamExternal {
	align-items: center;
	background: transparent;
	border: none;
	color: inherit;
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.82rem;
	gap: 0.35rem;
	/* Rechts genauso viel wie der Chip links vorgibt: Der Chip polstert links 0,8rem und rechts nur 0,3rem, weil
	   dort sonst das "..."-Menü sitzt - ohne das klebte die Beschriftung an der Kante. */
	padding: 0.3rem 0.5rem 0.3rem 0;
}

/* Kopfzeile des Portals: Zahnrad und Abmelden so groß wie die Box-Schaltflächen, an deren Stelle sie sitzen -
   als <a> statt <button> fielen sie sonst auf die Schriftgröße des Fließtextes zurück und wirkten verloren. */
body.portalMode .globalActions .iconBtn {
	font-size: 1.4rem;
	height: var(--control-height);
	width: var(--control-height);
}

/* Die linke Gruppe der Portal-Kopfzeile (nur das Zahnrad). Sie trägt dieselbe Klasse wie die Gruppe rechts, damit
   Symbolgröße und Rand aus denselben Regeln kommen und beide Seiten auch auf dem Handy gleich weit von der Kante
   stehen; umgedreht wird hier nur die Richtung. Ohne flex-Wachstum, sonst schöbe die Gruppe das absolut gesetzte
   Logo nicht, wohl aber die rechte Gruppe von der Kante weg. */
body.portalMode .portalLeftActions {
	flex: 0 0 auto;
	justify-content: flex-start;
	padding-left: 1em;
	padding-right: 0;
}

/* Ohne Menü-Knopf links stünde das Logo sonst angeklebt am linken Rand. Absolut zentriert und nicht per
   Flex-Verteilung: So sitzt es in der Mitte des Fensters, unabhängig davon, wie breit die Schaltflächen daneben
   gerade sind. */
body.portalMode header .logo {
	left: 50%;
	position: absolute;
	transform: translateX(-50%);
}

/* Der Filter nach Gesehen-Status: Er ändert zwar nichts, aber er filtert nach einer Angabe, die es im Portal sonst
   nirgends mehr gibt (siehe oben) - ein Filter auf Unsichtbares ist nur verwirrend. Der Sammlungs-Filter daneben
   bleibt, dessen Zeichen steht ja weiterhin an jeder Kachel. */
body.portalMode [data-flyout="Watched"] {
	display: none;
}

/* Der TMDB-Link war in der Kachel vor allem eine Abkürzung für den Admin; auf den Detailseiten steht er weiterhin.
   Der Trailer-Link (.tmdbYoutubeLink) bleibt - er gehört zum Anschauen. */
body.portalMode .tmdbTileLinks .tmdbExternalLink:not(.tmdbYoutubeLink) {
	display: none;
}

/* Bleibt von der Zeile nichts übrig, soll sie auch keinen Platz mehr beanspruchen. Übrig bleiben kann nur der
   Trailer-Link - alles andere darin ist oben ausgeblendet. */
body.portalMode .tmdbTileLinks:not(:has(.tmdbYoutubeLink)) {
	display: none;
}

/* Das Herz der Merkliste (siehe inc/tmdbMeta.html#watchlistHeart). Auf der Kachel sitzt es in derselben Zeile wie die
   Kennzeichen oben rechts und übernimmt deren Maße - so bleibt die Ecke ein Block statt zwei verschiedener Dinge
   nebeneinander. Ohne body.portalMode davor: Die Klasse gibt es sonst nirgends, und gerendert wird das Herz ohnehin
   nur im Portal. */
.tmdbWatchlistBtn {
	align-items: center;
	background: rgba(17,17,51,0.85);
	border: none;
	border-radius: 50%;
	color: #fff;
	cursor: pointer;
	display: flex;
	font-size: 1rem;
	height: 1.6rem;
	justify-content: center;
	padding: 0;
	width: 1.6rem;
}

.tmdbWatchlistBtn.on {
	color: var(--accent-watchlist);
}

/* Während die Antwort unterwegs ist: Der Knopf bleibt stehen, wird aber sichtbar taub - umgeschaltet wird erst, wenn
   der Server bestätigt hat (siehe watchlist.js). */
.tmdbWatchlistBtn:disabled {
	cursor: default;
	opacity: 0.5;
}

/* Auf den Detailseiten steht das Herz frei in der Kopfzeile statt klein auf einem Poster: ohne eigene Fläche und so
   hoch wie die Schaltflächen daneben. */
.tmdbWatchlistBtnLarge {
	background: none;
	font-size: 1.5rem;
	height: var(--control-height);
	width: var(--control-height);
}

/* Freigegebene Aufnahmen (siehe shares.html) ---------------------------------------------------- */

/* Die dritte Kachel der Portal-Startseite: flach und über die volle Breite der beiden großen darüber. Sie ist ein
   Nachschlag, kein gleichrangiger Einstieg - deshalb liegend statt hochkant und ohne Poster-Mosaik. */
.portalTile.portalTileFlat {
	align-items: center;
	/* Kein Seitenverhältnis: Die Kachel ist so hoch, wie ihr Inhalt sie macht - das ist es, was sie flach hält. */
	aspect-ratio: auto;
	flex-direction: row;
	gap: 0.6rem;
	/* .portalTiles ist ein Raster mit zwei Spalten; über beide reicht man nur so, nicht mit flex-basis. */
	grid-column: 1 / -1;
	justify-content: center;
	padding: 0.9rem 1rem;
}

.portalTile.portalTileFlat i {
	font-size: 1.5rem;
}

/* Auf der flachen Kachel steht die Zahl neben dem Namen statt darunter - in Klammern, damit sie sich nicht wie ein
   zweiter Titel liest. */
.portalTileFlat .portalTileCount::before {
	content: "(";
}

.portalTileFlat .portalTileCount::after {
	content: ")";
}

/* Die freigegebenen Ordner: eine Reihe flacher Kacheln, die weiterführen. */
.shareSectionTitle {
	align-items: center;
	display: flex;
	font-size: 1rem;
	gap: 0.4rem;
	margin: 1.2rem 0 0.6rem 0;
}

/* Untereinander statt nebeneinander: Die Ordner sind nach ihrem Pfad hierarchisch sortiert (siehe
   SharesPage#getOverviewPage), und untereinander gelesen erkennt man diese Ordnung sofort - nebeneinander springt der
   Blick über die Reihen und sie geht verloren. Nebenbei bekommt die Seite denselben Rhythmus wie die Aufnahmeliste
   darunter, und die Pfade haben Platz, ohne umbrechen zu müssen. */
.shareFolders {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	margin-bottom: 1.4rem;
}

.shareFolder {
	align-items: center;
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	color: inherit;
	display: flex;
	gap: 0.5rem;
	padding: 0.7rem 0.9rem;
	text-decoration: none;
}

.shareFolder:hover {
	border-color: var(--accent-collected);
}

.shareFolder > i {
	color: var(--accent-collected);
	font-size: 1.3rem;
}

.shareFolderName {
	flex: 1;
	font-weight: bold;
	min-width: 0;
	/* Kein overflow-wrap:break-word: Das bricht mitten im Ordnernamen. Wo umgebrochen werden darf, sagt das <wbr>
	   hinter jedem Schrägstrich (siehe shares.html); reicht auch das nicht, läuft der Name lieber über. */
}

.shareFolderCount {
	color: var(--text-muted);
	font-size: 0.8rem;
	white-space: nowrap;
}

/* Die Aufnahmen selbst: flache Kacheln statt einer Tabelle. Was hier zählt, ist "was ist das und will ich es sehen?" -
   also Titel, Kurzbeschreibung und die drei Angaben, die dabei helfen. Größe, Typ und Tags bleiben der Aufnahmeliste
   des Administrators vorbehalten.

   Die Karte selbst heißt .recordingCard und nicht mehr .shareItem: Die Trefferliste der globalen Suche zeigt dieselbe
   Karte, und beide bauen sie aus demselben Makro (siehe inc/tools.html#recordingCard). Der Rahmen darum bleibt
   seitenspezifisch (.shareList bzw. .searchRecordings) - er trägt nur Abstand und Richtung. */
.shareList {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.recordingCard {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1rem;
	justify-content: space-between;
	padding: 0.7rem 0.9rem;
}

.recordingCardMain {
	flex: 1;
	min-width: 12rem;
}

.recordingCardTitle {
	font-weight: bold;
}

.recordingCardDesc {
	color: #ccc;
	font-size: 0.88rem;
	margin-top: 0.15rem;
}

.recordingCardMeta {
	color: var(--text-muted);
	display: flex;
	flex-wrap: wrap;
	font-size: 0.82rem;
	gap: 0.2rem 0.9rem;
	margin-top: 0.35rem;
}

.recordingCardMeta span {
	align-items: center;
	display: inline-flex;
	gap: 0.3rem;
}

/* Die beiden Abspiel-Knöpfe: dieselben Farben wie in den großen Folgenkacheln (siehe .tmdbEpisodeActions .streamMovie).
   Vorher waren sie durchsichtig mit dünnem Rand und hoben sich kaum vom Kachelhintergrund ab - der ist hier derselbe
   wie dort (var(--surface)), also muss es der Knopf auch sein. */
.recordingCardActions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}

/* Nur die unmittelbaren Knöpfe: Steht dort die geteilte Schaltfläche (Abspielen samt "..."-Menü, siehe
   tools.recordingCard), trägt deren .tmdbRecordingChip die Pille - seine beiden Knöpfe müssen randlos und
   durchsichtig bleiben, sonst stehen dort zwei Pillen nebeneinander statt einer geteilten. */
.recordingCardActions > button {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 999px;
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.8rem;
	gap: 0.3rem;
	height: 1.75rem;
	padding: 0 0.8rem;
	white-space: nowrap;
}

.recordingCardActions > button:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Der Ordner einer gefundenen Aufnahme, gedämpft unter dem Titel: Erst er beantwortet, welche von drei gleichnamigen
   Aufnahmen das ist. Nur in der Suche, bei den Freigaben steht der Ordner in der Überschrift der Seite. */
.recordingCardFolder {
	align-items: center;
	color: var(--text-muted);
	display: flex;
	font-size: 0.82rem;
	gap: 0.3rem;
	margin-top: 0.15rem;
}

/* Aufnahme-Infos-Dialog (siehe MovieInfoDialog, movieInfo.js) --------------------------------------

   Eigene Breite statt der schmalen Vorgabe von .default-dialog (min(40rem, 100%)), aus demselben Grund wie beim
   TMDB-Detail-Popup (.tmdbDetailDialog): Eckdaten, Pillen und die Dateitabelle brauchen mehr Raum in der Breite als
   ein Bestätigungsdialog. Nur so hoch wie sein Inhalt statt fensterhoch - bei einer kurzen Aufnahme ohne
   Beschreibung stünde darunter sonst viel Leerraum; erst eine lange Beschreibung lässt ihn bis knapp vors
   Fensterende wachsen, dann scrollt der Inhalt.

   Das Flex-Gerüst ist für dieses Scrollen zwingend, nicht bloß Formsache: Ohne es begrenzt die max-height zwar den
   Dialog, aber nicht seinen Inhalt - der wächst weiter, das overflow-y unten greift nie, und bei einem langen Text
   (gemessen am Tablet quer: "Die unglaubliche Reise in einem verrückten Raumschiff") lief der Rest unten aus dem
   Dialog heraus. Erst Flex-Spalte plus min-height:0 am Kind zwingt es auf die verbleibende Höhe. Die Kopfzeile
   behält ihre eigene (flex:none), damit sie beim Scrollen stehen bleibt. */
.movieInfoDialog {
	display: flex;
	flex-direction: column;
	max-height: calc(100% - 2rem);
	max-width: calc(100% - 2rem);
	width: 40rem;
}

.movieInfoDialog .default-dialog-header {
	flex: none;
}

.movieInfoDialog .default-dialog-content {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
}

.movieInfo {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
}

.movieInfoTitle {
	align-items: baseline;
	display: flex;
	flex-wrap: wrap;
	font-size: 1.15rem;
	font-weight: bold;
	gap: 0.4rem;
}

.movieInfoDesc {
	color: #ccc;
	font-size: 0.9rem;
	margin-top: -0.3rem;
}

/* Die Eckdaten - Dauer, Zeitpunkt, Sender, Größe, Typ - in normaler statt gedämpfter Schrift: Anders als bei der
   Aufnahmekarte der Suche (.recordingCardMeta) ist das hier die Angabe, wegen der man den Dialog überhaupt öffnet,
   nicht eine Randnotiz unter dem eigentlichen Treffer. */
.movieInfoFacts {
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem 1rem;
}

.movieInfoFacts span,
.movieInfoLibrary a {
	align-items: center;
	display: inline-flex;
	gap: 0.35rem;
}

/* Technik- und Tag-Pillen in einer gemeinsamen Zeile - dieselbe Flex-Regel wie .tmdbTechPills, hier aber auch
   Elternelement der einzeln stehenden Tag-Pillen (tmdbMeta.tagPills liefert keinen eigenen Rahmen mit). */
.movieInfoPills {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}

.movieInfoLibrary {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
}

/* Nur das Symbol trägt das Mediathek-Grün, nicht der ganze Verweis: Dieselbe Farbe wie die Sprung-Symbole im
   Aktionsmenü der Aufnahmeliste (.tmdbGotoMovie/.tmdbGotoSeries), womit an jeder Stelle der Anwendung dasselbe
   Grün "das führt in die Mediathek" bedeutet. Der Text daneben bleibt in der Linkfarbe - er ist hier der
   eigentliche Titel und keine Beschriftung eines Symbolknopfs. */
.movieInfoLibrary a i {
	color: var(--group-mediathek-bright);
}

.movieInfoSection {
	border-top: 1px solid var(--line-subtle);
	padding-top: 0.7rem;
}

.movieInfoSectionTitle {
	align-items: center;
	color: var(--text-muted);
	display: flex;
	font-size: 0.78rem;
	font-weight: 600;
	gap: 0.4rem;
	letter-spacing: 0.02em;
	margin: 0 0 0.3rem 0;
	text-transform: uppercase;
}

/* Der Kopier-Knopf neben "Beschreibung": größer als die gesperrte Kleinschrift der Überschrift, damit er als
   Bedienelement lesbar bleibt, und die Sperrung selbst zurückgenommen - sie schöbe sonst eine Lücke hinter das
   Zeichen (dieselbe Stelle wie bei .helpAnchorLink in den Einstellungen). Direkt neben dem Wort statt rechtsbündig:
   Er gehört zu diesem einen Text, nicht zur Breite des Dialogs. */
.movieInfoCopyBtn {
	font-size: 1rem;
	letter-spacing: normal;
	line-height: 1;
}

.movieInfoLongDesc {
	font-size: 0.92rem;
	line-height: 1.45;
	white-space: pre-wrap;
}

/* Die Dateiangaben - gedämpft und als schmale zweispaltige Tabelle, weil sie fast nie die Frage sind, wegen der man
   den Dialog öffnet, aber die einzige Stelle bleiben, an der Pfad, genaue Größe und Begleitdateien überhaupt zu
   sehen sind. */
.movieInfoFileGrid {
	color: var(--text-muted);
	column-gap: 0.8rem;
	display: grid;
	font-size: 0.82rem;
	grid-template-columns: max-content 1fr;
	row-gap: 0.3rem;
}

.movieInfoFileValue {
	color: #ccc;
	word-break: break-word;
}

.movieInfoPath {
	font-family: monospace;
}

.movieInfoMissing {
	color: #c88;
	margin-left: 0.5rem;
}

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

/* Oben derselbe Abstand wie bei der Zählzeile aller anderen Seiten (.infoBar): Das Suchfeld ist hier das erste
   Element und klebte sonst unter der Kopfzeile. */
.searchForm {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 1rem 0;
}

/* Bezugspunkt für die Vorschlagsliste, die unter dem Feld hängt: */
.searchFieldWrap {
	position: relative;
}

/* Ohne das säße der Knopf 1,8px höher als das Feld: .defaultBtn bringt für dichte Leisten 0,25em Abstand nach unten
   mit, und in einer Zeile mit "align-items: center" zentriert Flex die Außenkanten - der Abstand schiebt den Knopf
   also nach oben. Beide sind 32px hoch, es war nie ein Höhen-, sondern ein Abstandsunterschied (nachgemessen). */
.searchForm .defaultBtn {
	margin: 0;
}

.searchPageInput {
	width: 18rem;
}

@media (max-width: 480px) {
	.searchPageInput {
		width: 100%;
	}

	.searchFieldWrap {
		flex: 1;
	}

	/* Auf dem Handy trägt der Knopf nur noch die Lupe und wird rund - beschriftet nahm er rund 100 der 374px der Zeile
	   ein, die dem Suchfeld fehlten und damit auch dem Optionen-Flyout darunter, das genau so breit ist. Rund und ohne
	   Beschriftung wie jeder Icon-Knopf der Anwendung (siehe .searchRowInfo); die Breite kommt aus der Höhe, damit es
	   ein Kreis ist und nicht ein Oval. Die Beschriftung fehlt nicht: Das Symbol ist die Lupe, der Knopf trägt sein
	   title, und abgeschickt wird meist mit der Eingabetaste. */
	.searchForm .searchSubmit {
		border-radius: 50%;
		flex-shrink: 0;
		padding: 0;
		width: var(--control-height);
	}

	.searchForm .searchSubmit span {
		display: none;
	}
}

.searchFieldWrap .searchSuggestions {
	border: 1px solid var(--line);
	border-radius: 8px;
	left: 0;
	position: absolute;
	right: 0;
	top: calc(100% + 0.3rem);
	z-index: 8;
}

/* Das Optionen-Flyout der Suche ist so breit wie das Suchfeld statt so breit wie sein Umschaltknopf: Bei den übrigen
   Filter-Flyouts sind die Einträge kurze Schlagworte, hier trägt jede Option einen erklärenden Satz, und mit dem
   Grundmuster (Breite aus dem Inhalt, mindestens 12rem) brach fast jeder davon um.
   Dafür wird der Bezugsrahmen umgehängt - vom Knopf (.filterFlyoutWrapper) auf .searchFieldWrap, dieselbe
   Verankerung, die auch die Vorschlagsliste benutzt. Eine feste Breite wäre hier falsch: Nachgemessen endet das
   Suchfeld je nach Fenster zwischen 242 und 427px vom linken Rand, und weil das Panel rechtsbündig hängt, ragte
   alles Breitere links aus dem Bild (mit 26rem auf dem Handy 115px weit). Am Feld ausgerichtet kann das nicht
   passieren. */
.searchForm .filterFlyoutWrapper {
	position: static;
}

.searchForm .filterFlyoutPanel {
	left: 0;
	right: 0;
	width: auto;
}

.searchOptionHint {
	color: var(--text-muted);
	font-size: 0.8rem;
	margin-top: 0.4rem;
}

/* Überschrift der Suchweisen-Auswahl: Ohne sie stünden drei Auswahlknöpfe zwischen zwei Kästchen, ohne dass zu sehen
   wäre, worüber sie überhaupt entscheiden. Der zugehörige Schlusshinweis gilt für alle drei und rückt deshalb an
   den unteren Rand der Gruppe statt an einen der Knöpfe. */
.searchOptionGroupLabel {
	color: var(--text-muted);
	font-size: 0.8rem;
	font-weight: bold;
	margin-bottom: 0.35rem;
	text-transform: uppercase;
}

.searchOptionHint + .defaultRadio + .defaultRadioLabel {
	margin-top: 0.5rem;
}

.searchOptionGroupHint {
	border-top: 1px dashed var(--control-border);
	margin-top: 0.5rem;
	padding-top: 0.4rem;
}

/* Die Reiterzeile kann auf dem Handy nicht umbrechen (die Pille wäre sonst zerrissen), also wird sie geschoben.
   Der Selektor nennt beide Klassen mit Absicht: ".segmentedToggle" setzt weiter unten "overflow: hidden", damit die
   ausgefüllten Endsegmente der Pillenform folgen - diese Regel steht davor und verlöre bei gleicher Spezifität, das
   Schieben war dadurch abgeschaltet. Und die Reiter dürfen nicht schrumpfen, sonst quetscht Flex sie in die Breite
   des Fensters, statt sie überstehen zu lassen. */
.segmentedToggle.searchTabs {
	margin-bottom: 1rem;
	max-width: 100%;
	overflow: auto hidden;
}

.searchTabs .seg-btn {
	flex-shrink: 0;
}

/* Eine Gruppe ohne Treffer ist gedämpft, aber anklickbar: Sie sagt dann "hier war nichts", und bei Filmen und Serien
   steht dort der Knopf zur TMDB-Suche - gerade bei null Treffern das Interessante. Gesperrt (:disabled) war sie bis
   zum 05.09.2026 und damit unerreichbar. Nicht im ausgewählten Zustand dämpfen: Sonst wäre der offene Reiter der
   einzige, dem man seine Auswahl nicht ansieht. */
.searchTabs .seg-btn.searchTabEmpty:not(.active) {
	color: var(--text-faint);
}

.searchTabCount {
	color: var(--text-muted);
	font-size: 0.8rem;
}

.searchTabs .seg-btn.active .searchTabCount {
	color: inherit;
}

/* Die Überschrift der Kachelreihe entfällt: Die Reiterzeile benennt die Gruppe bereits (siehe search.html). */
.searchPanel .tmdbTitleCardSection h3 {
	display: none;
}

.searchGroupAction {
	margin-top: 1rem;
}

.searchRecordings,
.searchRows {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

/* Eine Trefferzeile für alles, was keine Kachel ist (Folgen, Timer, AutoTimer, Notizen): links, worum es geht,
   rechts die Einordnung. Dieselbe Fläche wie die Aufnahme-Karte, nur schmaler - hier gibt es nichts zu drücken
   außer der Zeile selbst. */
.searchRow {
	align-items: center;
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	color: inherit;
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem 1rem;
	justify-content: space-between;
	padding: 0.6rem 0.9rem;
}

.searchRow:hover {
	border-color: var(--accent-collected);
}

/* Nur die Timer-Zeile ist zweigeteilt: der Link auf den Eintrag und daneben der Info-Knopf (siehe search.html).
   Der Link übernimmt dabei die Aufteilung, die sonst die Zeile selbst trägt. */
.searchRowLink {
	color: inherit;
	display: flex;
	flex: 1;
	flex-wrap: wrap;
	gap: 0.3rem 1rem;
	justify-content: space-between;
	min-width: 0;
}

/* Ohne Beschriftung ist die Schaltfläche rund, nicht pillenförmig - so wie überall sonst in der Anwendung, wo ein
   Symbol allein steht (siehe .infoBar .iconBtn). Höhe und Breite sind gleich, das Symbol steht mittig. */
.searchRowInfo {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	flex-shrink: 0;
	font-size: 0.9rem;
	height: 1.75rem;
	justify-content: center;
	padding: 0;
	width: 1.75rem;
}

.searchRowInfo:active:not(:disabled) {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Gesperrt, weil es zu dieser Folge keine Inhaltsangabe gibt - der Platz bleibt trotzdem belegt, damit die Spalten
   der Liste untereinander stehen (siehe search.html). */
.searchRowInfo:disabled {
	color: var(--text-faint);
	cursor: default;
	opacity: 0.5;
}

.searchRowDisabled {
	opacity: 0.55;
}

/* Die drei Zustände einer Sendung in der EPG-Gruppe. Sie sind der Grund, warum diese Gruppe überhaupt eine eigene
   Auszeichnung braucht: Ihre Liste umfasst Wochen, und ohne Unterschied stünde darin alles gleich gewichtet
   nebeneinander - was läuft, was kommt und was längst vorbei ist.

   Abgelaufen wird nur gedämpft, nicht ausgegraut wie .searchRowDisabled: Ein deaktivierter Timer ist abgeschaltet,
   eine gelaufene Sendung dagegen völlig in Ordnung - sie steht nur nicht mehr zur Auswahl. Sichtbar ist sie
   ohnehin erst auf einen ausdrücklichen Klick hin (siehe search.html). */
.searchRowPast {
	opacity: 0.7;
}

/* Was gerade läuft, ist die einzige Zeile mit einem Jetzt-Bezug - ein schmaler Streifen am linken Rand, wie ihn die
   Menügruppen der Seitenleiste tragen. Eine Einfärbung der ganzen Zeile wäre zu viel für eine Auskunft, die sich
   binnen einer Stunde erledigt hat.
   Das linke Polster gleicht die zwei zusätzlichen Pixel des Streifens aus (.searchRow hat 1px Rand und 0.9rem
   Polster), damit der Text aller Zeilen auf derselben Senkrechten beginnt. */
.searchRowRunning {
	border-left: 3px solid var(--accent-collected);
	padding-left: calc(0.9rem - 2px);
}

/* Dasselbe Blau wie der laufende Timer und der Fortschrittsbalken der EPG-Seite (#6af): Es bedeutet dort wie hier
   "das geschieht gerade". */
.searchEpgNow {
	color: var(--accent-collected);
	font-weight: bold;
}

/* Liegt schon ein Timer auf der Sendung, führt dieses Symbol zu ihm. Es sitzt im Raster der runden Schaltflächen
   (.searchRowInfo) und ist deshalb keins - ein Link, der aussieht wie seine Nachbarn, in der Farbe, die die
   EPG-Seite dem Timer gibt. Löschen gibt es hier nicht; dafür führt der Weg zur Timer-Seite. */
a.searchEpgTimerSet {
	color: var(--accent-collected);
	text-decoration: none;
}

/* Der Menü-Auslöser der EPG-Trefferzeile soll aussehen wie der Info-Knopf neben ihm - rund, mit Rahmen. Er trägt
   dafür dieselbe Klasse (.searchRowInfo), kommt damit aber nicht durch: ".actions button" macht Schaltflächen in
   Aktionsspalten flächen- und randlos und gewinnt als Klasse-plus-Element gegen eine Klasse allein. Deshalb hier
   noch einmal, spezifischer - und mit derselben Symbolgröße, denn ".actions button i" setzt 1.2rem, während die
   runden Knöpfe der Zeile bei 0.9rem stehen. */
.searchRow .actions button.toggleMoreFlyout {
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	height: 1.75rem;
	padding: 0;
	width: 1.75rem;
}

.searchRow .actions button.toggleMoreFlyout i {
	font-size: 0.9rem;
}

.searchRow .actions button.toggleMoreFlyout:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Der Schalter für die abgelaufenen Sendungen. Gedämpft wie jeder Hinweis dieser Seite (Rot bleibt Fehlern
   vorbehalten), die Schaltfläche darin als Textlink. */
.searchEpgPastHint {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}

.searchRowMain {
	flex: 1;
	min-width: 12rem;
}

.searchRowTitle {
	align-items: center;
	display: flex;
	font-weight: bold;
	gap: 0.4rem;
}

/* Die "1x01"-Angabe vor dem Folgentitel: dieselbe gedämpfte Auszeichnung wie in den Folgenlisten. */
.searchRowLabel {
	color: var(--text-muted);
	font-weight: normal;
}

.searchRowSub {
	color: var(--text-muted);
	display: block;
	font-size: 0.85rem;
	margin-top: 0.15rem;
}

/* Bei den Folgen steht die Zusatzzeile ausnahmsweise oben (der Serienname, nach dem sortiert wird) - der Abstand
   gehört dann darunter statt darüber. */
.searchRowSeries {
	margin: 0 0 0.15rem 0;
}

.searchRowMeta {
	align-items: center;
	color: var(--text-muted);
	display: flex;
	flex-wrap: wrap;
	font-size: 0.82rem;
	gap: 0.2rem 0.9rem;
}

.searchRowMeta > span {
	align-items: center;
	display: inline-flex;
	gap: 0.3rem;
}

/* Der gefundene Begriff: im Notiz-Ausschnitt der Trefferliste (siehe search.js) und auf der Zielseite, auf die ein
   Treffer führt (mark.hlTerm, siehe highlight.js). Eingefärbter Text statt gelber Fläche, die im dunklen Schema
   hart hereinschlüge - und beide Stellen sehen gleich aus, weil es dasselbe meint. */
.searchPanel mark,
mark.hlTerm {
	background: transparent;
	color: var(--accent-collected);
	font-weight: bold;
}

.searchHistory {
	margin-top: 1.5rem;
}

.searchHistoryList {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}

/* Die früheren Begriffe als Pillen: jeder ist ein Link, das x daneben vergisst ihn. */
.searchHistoryItem {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 999px;
	display: inline-flex;
	font-size: 0.85rem;
	gap: 0.2rem;
	padding: 0.2rem 0.4rem 0.2rem 0.8rem;
}

.searchHistoryDelete {
	background: none;
	border: none;
	color: var(--text-muted);
	cursor: pointer;
	display: inline-flex;
	padding: 0 0.2rem;
}

/* Startseite eines Streaming-Kontos: Titel, zwei große Kacheln, darunter dieselben Posterreihen wie beim Admin.
   Senkrecht zentriert wird nichts mehr - die Seite ist jetzt voll genug, um von oben zu beginnen. */
.portalTitle {
	font-size: clamp(1.3rem, 3vw, 2.2rem);
	font-weight: bold;
	letter-spacing: 0.03em;
	margin: 0.5rem 0 1.2rem 0;
	text-align: center;
}

/* Immer zwei Spalten, auch auf dem Handy: Untereinander schöbe die zweite Kachel die Posterreihen aus dem Bild,
   und "Filme oder Serien" ist eine Entscheidung, die man nebeneinander trifft. */
.portalTiles {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(2, 1fr);
	margin: 0 auto 2rem auto;
	max-width: 44rem;
}

.portalTile {
	align-items: center;
	aspect-ratio: 16 / 9;
	background: linear-gradient(160deg, #22315c 0%, var(--surface) 60%);
	border: 1px solid var(--line);
	border-radius: 14px;
	color: var(--text);
	display: flex;
	justify-content: center;
	overflow: hidden;
	position: relative;
	text-decoration: none;
	transition: border-color 0.15s, transform 0.15s;
}

/* Kein :hover - die Anwendung verzichtet bewusst darauf (siehe [data-tooltip]); der Druckpunkt zeigt die Reaktion. */
.portalTile:active {
	border-color: var(--control-border-hover);
	transform: scale(0.99);
}

/* Das Postermosaik füllt die Kachel und liegt hinter dem Text. Stark abgedunkelt und leicht unscharf: Es soll nach
   Mediathek aussehen, nicht mit der Beschriftung um Aufmerksamkeit ringen. */
.portalTileMosaic {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	inset: 0;
	opacity: 0.35;
	position: absolute;
}

.portalTileMosaic img {
	filter: blur(1px);
	height: 100%;
	object-fit: cover;
	width: 100%;
}

/* Verlauf über dem Mosaik, damit die Beschriftung auf jedem Poster lesbar bleibt - ein Poster kann hell sein. */
.portalTile::after {
	background: linear-gradient(180deg, rgba(13, 20, 38, 0.35) 0%, rgba(13, 20, 38, 0.85) 100%);
	content: "";
	inset: 0;
	position: absolute;
}

.portalTileBody {
	align-items: center;
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	/* Über den Verlauf, der als ::after eine eigene Ebene aufspannt. */
	position: relative;
	z-index: 1;
}

.portalTileBody i {
	color: #6af;
	font-size: clamp(1.8rem, 4vw, 3rem);
}

.portalTileName {
	font-size: clamp(1rem, 2vw, 1.6rem);
	font-weight: bold;
	letter-spacing: 0.05em;
	text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
}

.portalTileCount {
	color: var(--control-text);
	font-size: clamp(0.75rem, 1.2vw, 1rem);
	text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
}

/* Hinweiskasten auf der Startseite, solange Dreambox oder Aufnahmeort fehlen (siehe index.html). Auffällig genug,
   um nach der Ersteinrichtung nicht übersehen zu werden, aber kein Fehler - deshalb der ruhige Blauton der Familie
   statt Rot. */
.setupTodo {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 6px;
	margin-bottom: 1rem;
	max-width: 46rem;
	padding: 0.8rem 1rem;
}

.setupTodoTitle {
	align-items: center;
	color: #fff;
	display: flex;
	font-weight: bold;
	gap: 0.4rem;
	margin-bottom: 0.4rem;
}

.setupTodo ul {
	color: var(--text-muted);
	line-height: 1.5;
	margin: 0;
	padding-left: 1.2rem;
}

.setupTodo a {
	color: #6af;
}

/* Einleitender Text der Ersteinrichtung, über dem Formular (siehe setup.html). */
.setupIntro {
	color: var(--text-muted);
	font-size: 0.9rem;
	line-height: 1.45;
	margin: 0 0 1.2rem 0;
	text-align: left;
}

/* System-Seite --------------------------------------------------------------------------------- */

/* Die Cache-Übersicht wird so breit wie ihr Inhalt - nicht über die ganze Seite gezogen, aber auch nicht gedeckelt:
   Bis zum 16.10.2026 stand hier max-width 60rem bei width 100%, und als die Zeilen "Ordner und Aufnahmen" und
   "Lesezeichen der Box" hinzukamen, brachen in jeder Spalte Einträge um, obwohl die Seite breit genug war (gemeldet
   vom Nutzer). Umgebrochen wird jetzt nur, wenn der Platz wirklich fehlt. Keine Prozentbreite in einer Zelle: Die
   Knopfspalte trug "width: 1%", und eine solche Spalte zwingt eine Tabelle mit width:auto auf die volle Breite. */
.cacheTable {
	max-width: 100%;
	width: auto;
}

/* Oben ausgerichtet: Auf schmalen Bildschirmen brechen einzelne Zellen um, und mittig gesetzt verschwimmen dann die
   Zeilengrenzen (Wunsch des Nutzers, 26.09.2026). */
.cacheTable td {
	vertical-align: top;
}

.cacheTable .cacheContent,
.cacheTable .cacheInterval {
	color: var(--text-muted);
}

/* Auffällig, aber nicht alarmierend: Die Zeile bleibt lesbar, das Symbol trägt die Aussage. Ein "hängt" heißt
   nicht zwingend Fehler - nach einem Neustart ist der 24-Stunden-Cache schlicht noch nie gelaufen. */
.cacheTable .cacheStale td {
	color: #e55;
}

.cacheTable .cacheStaleIcon {
	margin-right: 0.35em;
}

/* Der Neu-einlesen-Knopf am Zeilenende: nur das Symbol, ohne Fläche - er steht in jeder Zeile, und zwölf Knöpfe mit
   Rahmen hätten mehr Gewicht als die Angaben daneben. */
.cacheTable td.cacheRefresh {
	text-align: right;
	white-space: nowrap;
}

.cacheRefreshBtn {
	background: none;
	border: none;
	border-radius: 50%;
	color: var(--text-muted);
	cursor: pointer;
	font-size: 1.1rem;
	line-height: 1;
	/* Der negative Rand hebt den Innenabstand auf, damit das Symbol auf der Höhe der ersten Textzeile steht. */
	margin: -0.3rem 0;
	padding: 0.3rem;
}

.cacheRefreshBtn:hover {
	background-color: rgba(255, 255, 255, 0.1);
	color: inherit;
}

.cacheRefreshPlaceholder {
	display: inline-block;
	visibility: hidden;
}

.cacheRefreshBtn:disabled {
	cursor: default;
	opacity: 0.4;
}

@media (max-width: 640px) {
	/* Vier Spalten passen hier nicht nebeneinander: .defaultTable td trennt notfalls mitten im Wort
	   (overflow-wrap: anywhere), aus "Aufnahmeorte" wird dann "Aufnah meorte". Das Intervall weicht als erstes -
	   es ist unveränderlicher Zusatz, kein Zustand. Die verbleibenden Spalten brechen wieder nur zwischen Wörtern;
	   die Inhaltsspalte behält das harte Trennen, weil dort die längsten Texte stehen. */
	.cacheTable .cacheInterval,
	.cacheTable th:nth-child(4) {
		display: none;
	}

	/* word-break muss mit zurückgenommen werden, nicht nur overflow-wrap: Auf schmalen Bildschirmen setzt weiter
	   unten "table td" beides, und break-all trennt für sich genommen schon mitten im Wort. Hier ist das gefahrlos,
	   anders als bei den Aufnahme-Tabellen: In dieser Tabelle stehen nur kurze Wörter, kein Dateiname, der für
	   sich genommen breiter als die Spalte wäre. */
	.cacheTable td {
		overflow-wrap: normal;
		word-break: normal;
	}
}

/* Werkzeuge für die Entwicklung, kein Alltagsweg: klein, grau und am Seitenende - vorher waren es vier
   Kacheln in voller Größe, die mehr Gewicht hatten als alles darüber. */
.devLinks {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem;
	margin-top: 2rem;
}

.devLinks a {
	align-items: center;
	color: var(--text-muted);
	display: inline-flex;
	font-size: 0.85rem;
	gap: 0.35em;
	text-decoration: none;
}

.devLinks a:active {
	color: #fff;
}

/* Screenshot ----------------------------------------------------------------------------------- */

.screenshotControls {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-bottom: 1rem;
}

.screenshotControls .defaultBtn {
	margin: 0;
}

/* Vier Arten passen auf dem Telefon nicht in eine Zeile; die Pille wird geschoben statt umgebrochen (wie die
   Reiter der Suche, siehe .segmentedToggle.searchTabs). */
.segmentedToggle.screenshotModes {
	max-width: 100%;
	overflow: auto hidden;
}

.screenshotModes .seg-btn {
	flex-shrink: 0;
}

/* Nachricht an den Fernseher ------------------------------------------------------------------ */

.boxMessageTarget {
	margin-top: 0;
}

.boxMessageForm textarea {
	margin-bottom: 0.6rem;
	max-width: 26rem;
	width: 100%;
}

/* Vier Arten passen auf dem Telefon nicht in eine Zeile - geschoben statt umgebrochen wie bei .screenshotModes. */
.segmentedToggle.boxMessageTypes {
	align-self: flex-start;
	margin-bottom: 0.6rem;
	max-width: 100%;
	overflow: auto hidden;
}

.boxMessageTypes .seg-btn {
	flex-shrink: 0;
}

.boxMessageForm .settingsHint {
	max-width: 26rem;
}

/* Die Gruppe steht im Spalten-Flex von .settingsForm und muss dessen Abstände selbst weitergeben. */
.boxMessageTimeGroup {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
}

#boxMessageStatus h3 {
	margin-top: 1.5rem;
}

.boxMessageCard {
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--field-radius);
	max-width: 26rem;
	padding: 0.6rem 0.8rem;
}

.boxMessageCard p {
	margin: 0 0 0.4rem;
}

/* Der Text geht mit seinen Zeilenumbrüchen an die Box und wird hier genauso gezeigt. */
.boxMessageCardText {
	overflow-wrap: anywhere;
	white-space: pre-wrap;
}

.boxMessageCardMeta {
	color: var(--text-muted);
	font-size: 0.85rem;
}

.boxMessageAnswer {
	align-items: center;
	display: flex;
	font-weight: bold;
	gap: 0.4rem;
}

.boxMessageAnswer .boxMessageCardMeta {
	font-weight: normal;
}

.boxMessageCard .defaultBtn {
	margin: 0.2rem 0 0;
}

/* Schachbrett unter Bildern, die durchsichtig sein können (das OSD der Box). Es liegt am Bild selbst und nicht am
   Rahmen, damit es genau dessen Fläche zeigt; ein undurchsichtiges Bild deckt es vollständig zu. */
.transparencyGrid {
	background-color: #3a3f4b;
	background-image: repeating-conic-gradient(#4b5160 0 25%, transparent 0 50%);
	background-size: 16px 16px;
}

.currentScreenshot {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 8px;
	margin-bottom: 0.75rem;
	max-width: 40rem;
	padding: 0.75rem;
}

.currentScreenshotStage {
	align-items: center;
	aspect-ratio: 16 / 9;
	background: #000;
	border-radius: 4px;
	display: flex;
	justify-content: center;
	overflow: hidden;
	position: relative;
}

/* Knopf und Bild füllen die Fläche, das Bild wird darin eingepasst (object-fit). Das [hidden] muss eigens stehen:
   Jede Author-Regel mit display schlägt das hidden-Attribut - vor dem ersten Bild stand sonst ein leeres <img> mit
   seinem Alt-Text da. */
.currentScreenshotOpen {
	background: none;
	border: none;
	cursor: zoom-in;
	display: block;
	height: 100%;
	inset: 0;
	padding: 0;
	position: absolute;
	width: 100%;
}

.currentScreenshotImage {
	display: block;
	height: 100%;
	object-fit: contain;
	width: 100%;
}

/* Während neu geholt wird, bleibt das bisherige Bild gedämpft stehen, darüber dreht sich der Spinner. */
.currentScreenshot.loading .currentScreenshotOpen {
	opacity: 0.4;
}

.currentScreenshotSpinner {
	animation: spin 1s linear infinite;
	border: 4px solid rgba(255, 255, 255, 0.2);
	border-radius: 50%;
	border-top-color: #6af;
	display: none;
	height: 2.5rem;
	pointer-events: none;
	position: absolute;
	width: 2.5rem;
}

.currentScreenshot.loading .currentScreenshotSpinner {
	display: block;
}

.currentScreenshotStatus {
	color: var(--text);
	margin: 0;
	padding: 1rem;
	position: relative;
	text-align: center;
}

.currentScreenshotStatus.isError {
	color: #d44;
}

.currentScreenshotActions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-bottom: 1.5rem;
}

.currentScreenshotActions .defaultBtn {
	margin: 0;
}

.screenshotCount {
	color: var(--text-muted);
	font-weight: normal;
}

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

.screenshotTile {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	color: #ddd;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	padding: 0.6rem;
}

/* Feste 16:9-Fläche, damit das Raster steht, bevor die Vorschau geladen ist (loading="lazy"). Das Display-Bild ist
   5:3 und wird darin nur verkleinert, nicht beschnitten. */
.screenshotThumb {
	align-items: center;
	aspect-ratio: 16 / 9;
	background: #000;
	border: none;
	border-radius: 4px;
	cursor: zoom-in;
	display: flex;
	justify-content: center;
	overflow: hidden;
	padding: 0;
	width: 100%;
}

.screenshotThumb img {
	display: block;
	max-height: 100%;
	max-width: 100%;
}

.screenshotTileInfo {
	font-size: 0.8rem;
	line-height: 1.4;
	min-width: 0;
}

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

.screenshotTileActions {
	display: flex;
	gap: 0.25rem;
	justify-content: flex-end;
	margin-top: auto;
}

.screenshotTileActions .iconBtn {
	font-size: 1.15rem;
}

/* Auf dem Telefon zwei Spalten statt einer: Eine Kachel über die volle Breite zeigt kaum mehr als das große Bild
   darüber, und fünf Einträge wären schon drei Bildschirmhöhen. */
@media (max-width: 600px) {
	.screenshotTiles {
		gap: 0.6rem;
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.screenshotTile {
		padding: 0.4rem;
	}
}

/* Tooltip -------------------------------------------------------------------------------------- */

[data-tooltip] {
	cursor: help;
	position: relative;
}

[data-tooltip]:before, [data-tooltip]:after {
	opacity: 0;
	pointer-events: none;
	visibility: hidden;
	z-index: 200;
}

[data-tooltip]:before {
	background-color: var(--surface-raised);
	border-radius: 6px;
	bottom: 100%;
	color: #fff;
	content: attr(data-tooltip);
	font-size: 0.9em;
	font-weight: normal;
	line-height: 1.5em;
	margin-bottom: 5px;
	/* Schmaler als das Fenster und umbrechend: Eine Blase, die breiter als der sichtbare Bereich ist, lässt sich
	   auch durch Verschieben nicht mehr hineinbekommen (siehe positionTooltip in chrome.js). Kurze Texte -
	   der Normalfall - bleiben durch width:fit-content weiterhin einzeilig. */
	max-width: min(24rem, calc(100vw - 1rem));
	padding: 0.25em 1em;
	position: absolute;
	right: 0;
	text-align: center;
	/* Waagerechte Korrektur aus chrome.js; ohne sie bleibt es bei der rechtsbündigen Ausrichtung: */
	transform: translateX(var(--tooltipShift, 0));
	width: fit-content;
}

[data-tooltip]:after {
	border-top: 5px solid hsla(0, 0%, 20%, 0.9);
	border-right: 5px solid transparent;
	border-left: 5px solid transparent;
	bottom: 100%;
	content: " ";
	font-size: 0;
	left: 50%;
	line-height: 0;
	margin-bottom: 0;
	margin-left: -5px;
	position: absolute;
	width: 0;
}

/* Nach unten geklappt, weil über dem Element zu wenig Platz ist (gesetzt von positionTooltip in chrome.js).
   Der Pfeil wird dabei mitgedreht: Sein oberer Rand trägt die Farbe, für die Spitze nach oben muss sie an den
   unteren. */
.tooltipBelow:before {
	bottom: auto;
	margin-bottom: 0;
	margin-top: 5px;
	top: 100%;
}

.tooltipBelow:after {
	border-bottom: 5px solid hsla(0, 0%, 20%, 0.9);
	border-top-color: transparent;
	bottom: auto;
	top: 100%;
}

/* Der einzige verbliebene Hover-Effekt, und das mit Absicht - hier ist das Kleben auf Touch-Geräten kein Fehler,
   sondern der einzige Weg, den Tooltip überhaupt zu lesen: Angetippt bleibt er stehen, bis daneben getippt wird.
   Deshalb weder :active (nur sichtbar, solange gedrückt wird) noch eine Eingrenzung per @media (hover: hover),
   die ihn auf Touch-Geräten ganz verschlucken würde. Wo das Stehenbleiben stört, trägt das Element stattdessen
   ein title-Attribut. */
[data-tooltip]:hover:before, [data-tooltip]:hover:after {
	opacity: 1;
	pointer-events: auto;
	visibility: visible;
}

.tippy-box {
	background-color: var(--surface-raised);
	padding: 0 3px 5px 3px;
	width: 50em;
	z-index: 200;
}
.tippy-content {
	font-family: monospace;
	font-size: 1em;
	overflow: hidden;
}

/* Toast Notification --------------------------------------------------------------------------- */

/* Läuft als "manual" Popover (siehe toast.js) statt als gewöhnliches position:fixed-Element, damit sie auch über
   einem offenen <dialog> sichtbar ist - ein <dialog> wird beim Öffnen in den Browser-"Top Layer" gehoben, der immer
   über gewöhnlich positionierten Elementen liegt, egal wie hoch deren z-index ist. Popover landen ebenfalls im Top
   Layer und darüber, wenn sie nach dem Dialog geöffnet werden. border/bottom/right setzen dabei die abweichenden
   UA-Vorgaben des [popover]-Attributs zurück (border: solid, inset: 0), die sonst durchschlagen würden. */
.toast {
	background-color: var(--surface-raised);
	border: none;
	border-radius: 10px;
	bottom: auto;
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.7);
	color: var(--text);
	left: 50%;
	max-width: 40vw;
	min-width: 250px;
	opacity: 0;
	padding: 1em 1.5em;
	pointer-events: none;
	position: fixed;
	right: auto;
	text-align: center;
	top: 1em;
	transform: translateX(-50%);
	transition: opacity 0.3s ease-in-out;
	visibility: hidden;
	z-index: 1000;
}

.toast.show {
	opacity: 1;
	pointer-events: auto;
	visibility: visible;
}

.toast.info {
	background-color: var(--surface-raised);
	border: 1px solid var(--control-border);
	color: #fff;
}

.toast.success {
	background-color: #363;
	border: 1px solid #6b6;
	color: #fff;
}

.toast.error {
	background-color: #633;
	border: 1px solid #b66;
	color: #fff;
}

/* Das Schließkreuz bleibender Meldungen (showToast mit duration = 0, siehe toast.js). Absolut positioniert und der
   Text bekommt rechts Platz dafür: Der Toast ist mittig gesetzt, ein mitfließendes Kreuz würde diese Mitte
   verschieben und den Text bei jeder Meldung anders stehen lassen. */
.toast:has(.toastClose) {
	padding-right: 2.8em;
}

.toastClose {
	background: none;
	border: none;
	color: inherit;
	cursor: pointer;
	font-size: 1rem;
	line-height: 1;
	opacity: 0.7;
	padding: 0.3em;
	position: absolute;
	right: 0.5em;
	top: 0.5em;
}

.toastClose:hover {
	opacity: 1;
}

.default-dialog {
	background: var(--surface-dialog);
	border: 1px solid var(--control-border);
	border-radius: 12px;
	box-shadow: 0 8px 24px rgba(0,0,0,0.7);
	color: var(--text);
	max-width: min(40rem, 100%);
	padding: 0;
}

.default-dialog-large {
	flex: max-content;
	max-width: none;
}

/*
 * Dialog, der zusätzlich die volle Fensterhöhe nutzt (statt nur so hoch zu sein wie sein Inhalt) - für Dialoge mit
 * langen, scrollenden Listen wie die TMDB-Suche: sonst bliebe unten Platz ungenutzt, während die Trefferliste in
 * einem schmalen Ausschnitt scrollt. Der Rand von 1rem oben/unten hält den Dialog vom Fensterrand weg.
 *
 * Der Inhalt wird dafür zur Flex-Spalte, damit das scrollende Element darin (siehe .default-dialog-tall .tmdbSearchResults)
 * den verbleibenden Raum bekommt; min-height/overflow sorgen dafür, dass es selbst scrollt, statt den Dialog zu dehnen.
 */
.default-dialog-tall {
	display: flex;
	flex-direction: column;
	height: calc(100% - 2rem);
}

.default-dialog-tall .default-dialog-content {
	display: flex;
	flex-direction: column;
	min-height: 0;
	overflow: hidden;
}

/* Suchzeile und Schaltflächen behalten ihre Höhe, nur die Trefferliste wächst und scrollt: */
.default-dialog-tall .tmdbSearchRow,
.default-dialog-tall .tmdbEpisodeSearchRow,
.default-dialog-tall .tmdbScanReviewBar,
.default-dialog-tall .default-dialog-actions {
	flex: none;
}

/* Die Flyouts in der Suchzeile (Tags in der Folgensuche, Suchoptionen in der TMDB-Suche) klappen absolut positioniert
   über die Trefferliste - das overflow:hidden oben würde sie abschneiden. Sichtbar wurde das nur, solange die Liste
   noch leer war: Danach reicht der Inhalt tief genug, dass das Panel innerhalb des abgeschnittenen Bereichs bleibt.
   Gescrollt wird ohnehin nur die Trefferliste selbst (beide bringen overflow-y mit), der Dialoginhalt muss dafür
   nichts abschneiden. */
#tmdbEpisodeSearchDialog .default-dialog-content,
#tmdbSearchDialog .default-dialog-content {
	overflow: visible;
}

/* Der Tag-Button sitzt am rechten Rand der Suchzeile; nach links aufklappen hält das Panel innerhalb des Dialogs.
   Mit dem sonst üblichen left:0 ragte es darüber hinaus und schöbe den mittig ausgerichteten Dialog aus dem Bild. */
#tmdbEpisodeSearchTagFilter .filterFlyoutPanel {
	left: auto;
	right: 0;
}

.default-dialog-tall .tmdbSearchResults,
.default-dialog-tall .tmdbEpisodeSearchResults,
.default-dialog-tall .tmdbScanReviewList {
	flex: 1;
	max-height: none;
	min-height: 0;
}

/* Das Scan-Ergebnis nimmt die volle Höhe nur, wenn die Liste sie braucht - daher Obergrenze statt fester Höhe. Die
   Suche darf fest hoch bleiben: Dort tippt man weiter und lädt laufend neue Treffer nach, ein springender Dialog wäre
   dabei unruhig. Das Ergebnis dagegen steht einmal fest, und bei zwei Treffern bliebe der halbe Dialog leer. */
#tmdbScanReviewDialog .default-dialog-tall {
	height: auto;
	max-height: calc(100% - 2rem);
}

.default-dialog-backdrop[open] {
	display: flex;
	justify-content: center;
	align-items: center;
	height: 100vh;
	margin: 0;
	max-height: 100vh;
	max-width: 100vw;
	padding: 0;
	position: fixed;
	width: 100vw;
}

.default-dialog::backdrop,
.default-dialog-backdrop {
	backdrop-filter: blur(2px);
	background: rgba(0,0,0,0.6);
}

/* Groß-Ansicht eines einzelnen Bilds (z.B. Episoden-Still), siehe openImageLightbox() in dialogs.js. Kein
   .default-dialog-Wrapper nötig: die Backdrop-Klick-Logik oben schließt hier bei jedem Klick, auch auf das Bild
   selbst - genau das gewünschte Verhalten, weil es innerhalb des Bilds nichts zu bedienen gibt. */
.imageLightboxBackdrop {
	border: none;
	cursor: zoom-out;
	max-width: 100vw;
	max-height: 100vh;
}

/* Höhere Spezifität als .default-dialog-backdrop[open] (Klasse+Attribut) nötig, sonst gewinnt dessen padding:0. */
.imageLightboxBackdrop[open] {
	padding: 1.5rem;
}

.imageLightboxImg {
	border-radius: 8px;
	box-shadow: 0 8px 24px rgba(0,0,0,0.7);
	max-width: 100%;
	max-height: calc(100vh - 3rem);
	object-fit: contain;
}

/* Wiedergabe auf dem eigenen Gerät (siehe player.js). Anders als die Bild-Groß-Ansicht schließt hier NICHT jeder
   Klick: Im Video wird bedient (Pause, Fortschritt, Lautstärke), und ein Fingertipp daneben soll nicht mitten im
   Film alles beenden - deshalb der eigene Schließknopf in der Kopfzeile. */
.videoPlayerBackdrop {
	background: transparent;
	border: none;
	max-width: 100vw;
	max-height: 100vh;
	overflow: visible;
}

.videoPlayerBackdrop[open] {
	padding: 0;
}

.videoPlayerBox {
	background: var(--surface-dialog);
	border: 1px solid var(--control-border);
	border-radius: 12px;
	box-shadow: 0 8px 24px rgba(0,0,0,0.7);
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.videoPlayerHeader {
	align-items: center;
	background: var(--control-bg-hover);
	border-bottom: 1px solid var(--control-border);
	display: flex;
	gap: 0.5rem;
	min-height: 2.5rem;
	padding: 0 0.4rem 0 0.8rem;
}

/* Lange Aufnahmenamen dürfen den Kopf nicht auseinanderziehen - der Schließknopf muss erreichbar bleiben. */
.videoPlayerTitle {
	color: var(--control-text-hover);
	flex: 1;
	font-size: 0.95rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.videoPlayerClose {
	flex: none;
}

/* Das Video bestimmt die Größe des Dialogs, bleibt aber im Bildschirm: Platz für Kopfzeile und Rand abziehen.
   aspect-ratio ist hier das Entscheidende: Ohne die Angabe behält das Element seine Standardhöhe von 150px bzw.
   wird von max-height aufgezogen, und das Bild schwimmt mit schwarzen Streifen darin. Da praktisch alle Aufnahmen
   16:9 sind, sitzt der Rahmen damit auf dem Bild. Der schwarze Grund fängt die wenigen Ausnahmen ab. */
.videoPlayerVideo {
	aspect-ratio: 16 / 9;
	background: #000;
	display: block;
	height: auto;
	max-width: calc(100vw - 2rem);
	max-height: calc(100vh - 6rem);
	width: min(80rem, calc(100vw - 2rem));
}

.videoPlayerStatus {
	color: var(--text-muted);
	font-size: 0.85rem;
	padding: 0.5rem 0.8rem;
	text-align: center;
}

/* Kopfzeile des Dialogs: abgesetzt vom Dialogkörper, aber aus derselben Palette - und unten von einer Linie
   begrenzt, damit sie auch ohne starken Farbunterschied als Band lesbar bleibt. */
.default-dialog-header {
	align-items: center;
	background: var(--control-bg-hover);
	border-bottom: 1px solid var(--control-border);
	border-radius: 11px 11px 0 0; /* 1px weniger als der Dialog, sonst blitzt dessen Rahmen an den Ecken durch */
	display: flex;
	font-size: 1rem;
	gap: 0.5rem;
	margin: 0 0 0.3rem 0;
	min-height: 2.5rem;
	padding: 0.5rem 1rem;
}

/* Buttons in der Kopfzeile (Kopieren, Schließen): rechtsbündig neben dem Titel, der dafür in einem eigenen
   <span> steckt - sonst würde ein per .text() gesetzter Titel den Button mit entfernen. Flex statt float,
   damit Titel und Button beide vertikal mittig in der Kopfzeile sitzen: als Inline-Inhalt saß der Titel
   sonst auf der Textbaseline und hatte oben und unten unterschiedlich viel Luft. */
.default-dialog-header .copyToClipboardBtn,
.default-dialog-header .dialogCloseBtn {
	line-height: 1.3rem;
	margin-left: auto;
}

/* Schließen-Kreuz bewusst größer als die Standard-Button-Schriftgröße (~13px), damit es als Bedienelement
   klar erkennbar ist: */
.default-dialog-header .dialogCloseBtn i {
	font-size: 1.5rem;
	line-height: 1.5rem;
}

.default-dialog-content {
	padding: 1rem 1rem;
}

.default-dialog-content .default-dialog-msg {
	font-size: 0.95rem;
	margin: 0;
	white-space: pre-wrap;
}

/* Mit eigenem Zeilenabstand: Geerbt kam "normal" heraus (~1.2), und bei 0.75rem klebten die Zeilen eines
   mehrzeiligen Hinweises aneinander - dieselbe Korrektur wie beim Hinweiskasten (.tmdbMissingNotice). */
.default-dialog-content .default-dialog-msg-small {
	color: #ccc;
	font-size: 0.75rem;
	line-height: 1.55;
	margin: 0.5rem 0 0 0;
	white-space: pre-wrap;
}

/* Leitet einen neuen Abschnitt im Dialog ein. Ohne den größeren Abstand liest sich so ein Satz wie die Fortsetzung
   des Hinweises darüber - beide sind .default-dialog-msg-small und stünden sonst als ein Absatz da (siehe den
   Import-Dialog, wo unter dem Hinweis zum Löschen die Frage zum Gesehen-Status beginnt). */
.default-dialog-content .default-dialog-msg-small.sectionLead {
	margin-top: 1.4rem;
}

.default-dialog-row,
.default-dialog-checkboxes {
	margin: 1rem 0;
}

/* Tag-Dialog einer Aufnahme (siehe inc/tmdbRecordingTagsDialog.html): Aufnahme-Auswahl oben, Anlegen-Zeile unten.
   Das :not([hidden]) ist nötig, weil ein gesetztes display sonst das hidden-Attribut überstimmt - die Auswahl
   erscheint nur bei mehreren Aufnahmen. */
.recordingTagsPicker:not([hidden]),
.recordingTagsAddRow {
	align-items: center;
	display: flex;
	gap: 0.5rem;
}

.recordingTagsPicker {
	margin-top: 0.5rem;
}

.recordingTagsPicker select {
	flex: 1;
	min-width: 0;
}

.recordingTagsAddRow .dialogInput {
	flex: 1;
	min-width: 0;
}

.default-dialog-row .defaultInput {
	width: 100%;
}

/* Im Dialog stehen die Kästchen als Zeilen im Formular, nicht als Chips: Fläche und Rahmen entfallen deshalb,
   nur das Kästchen selbst bleibt (gleiche Überlegung wie im Filter-Menü, siehe .filterFlyoutPanel). */
.default-dialog-row .defaultCheckboxLabel,
.default-dialog-checkboxes .defaultCheckboxLabel {
	background: transparent;
	border-color: transparent;
	padding-left: 0;
	padding-right: 0;
}

.default-dialog-row .defaultCheckboxLabel:active,
.default-dialog-checkboxes .defaultCheckboxLabel:active {
	background: transparent;
	border-color: transparent;
	color: var(--control-text-hover);
}

.default-dialog-table-row {
	max-height: 70vh;
	overflow: auto;
}

#tagManageDialog {
	max-width: min(48rem, 100%);
}

/* Der Textbereich bringt von sich aus nur die Breite seiner cols-Vorgabe mit (~20 Zeichen) - für Fließtext zu
   schmal, während der Dialog daneben noch Platz hätte (siehe inc/tmdbNoteDialog.html): */
#tmdbNoteInput {
	max-width: 100%;
	width: 32rem;
}

.tagManageTable {
	border: none;
	width: 100%;
}

.tagManageTable th {
	background: transparent;
	border: none;
}

.tagManageTable td {
	border: none;
}

/* Der Tabellen-Header sitzt ganz oben im scrollbaren .default-dialog-table-row (overflow: auto), das nach oben
   öffnende Standard-Tooltip (siehe "[data-tooltip]:before/:after") würde dort abgeschnitten - deshalb hier nach
   unten öffnen lassen. */
.tagManageTable th[data-tooltip]:before {
	bottom: auto;
	margin-bottom: 0;
	margin-top: 5px;
	top: 100%;
}

.tagManageTable th[data-tooltip]:after {
	border-bottom: 5px solid hsla(0, 0%, 20%, 0.9);
	border-top: none;
	bottom: auto;
	margin-bottom: 0;
	top: 100%;
}

#tagManageDialog .default-dialog-table-row {
	margin: 0.5rem 0;
}

#tagManageDialog .default-dialog-table-row table {
	margin: 0.25rem auto;
}

.tagManageTable th.tagManageCountCol,
.tagManageTable td.tagManageCountCol {
	text-align: right;
}

.tagManageTable th.tagManageCountCol i {
	font-size: 1rem;
}

.tagManageTable td.tagManageNameCol {
	font-weight: bold;
	overflow: hidden;
	text-overflow: ellipsis;
}

.tagManageTable td.tagManageActionsCol {
	text-align: right;
	white-space: nowrap;
}

.tagManageTable td.tagManageActionsCol button {
	margin: 0 0 0 0.3em;
}

.default-dialog-table-row table {
	margin: 0.5rem auto;
	width: 100%;
}

.default-dialog-actions {
	display: flex;
	gap: 0.6rem;
	justify-content: flex-end;
	margin: 1.5rem 0 0 0;
}

.default-dialog-actions .defaultBtn {
	margin: 0;
	min-width: 6.5rem;
}

/* Kästchen in der Knopfzeile, links neben den Knöpfen (showConfirm, inActions). Es nimmt den freien Platz und darf
   nicht schmaler werden als sein Text - passt beides nicht nebeneinander, bricht die Zeile um und das Kästchen steht
   über den Knöpfen. max-width fängt den Fall ab, dass der Text allein schon breiter ist als die Zeile. */
.default-dialog-actions:has(> .default-dialog-actions-lead:not([hidden])) {
	flex-wrap: wrap;
}

.default-dialog-checkboxes.default-dialog-actions-lead {
	align-self: center;
	flex: 1 0 auto;
	margin: 0;
	max-width: 100%;
}

#infoPopup .default-dialog-actions {
	margin: 0;
}
#infoPopup .default-dialog-actions .infoPopupBtn {
	margin-top: 1.5rem;
}

@keyframes spin {
	0% { transform: rotate(0deg); }
	100% { transform: rotate(360deg); }
}

/* Der Spinner soll senkrecht mittig zum Text seiner Meldung stehen, egal ob die eine Zeile hat oder zwei. Dafür wird
   die Meldung selbst zur Flex-Zeile, sobald sie einen Spinner enthält - der Text bildet darin das erste (anonyme)
   Flex-Element. Als gefloateter Block hing der Spinner stattdessen am oberen Rand der Meldung und saß bei
   einzeiligem Text sichtbar zu tief. Der Kindselektor grenzt die Regel auf den Spinner der Meldung selbst ein. */
.default-dialog-msg:has(> .infoPopupSpinner) {
	align-items: center;
	display: flex;
	gap: 1em;
}

.infoPopupSpinner {
	animation: spin 1.5s linear infinite;
	border: 4px solid var(--control-bg);
	border-radius: 50%;
	border-top: 4px solid #6af;
	display: block;
	/* Nicht mitschrumpfen und rechtsbündig bleiben - beides übernahm vorher der float. */
	flex: none;
	height: 1.5em;
	margin-left: auto;
	width: 1.5em;
}

/* Eine Icon-Schaltfläche, deren Aktion gerade läuft: Statt eines eigenen Spinners dreht sich ihr Sinnbild selbst -
   beim Aktualisieren-Knopf der Aufnahmen-Liste ist das ohnehin der Kreispfeil. Wichtig für den Refresh beim Neuladen
   der Seite (siehe movieList.js), denn dort gibt es sonst kein Zeichen dafür, dass noch etwas läuft. */
.iconBtnBusy i {
	animation: spin 1s linear infinite;
	display: inline-block;
}

/* Kleiner Inline-Spinner fürs Icon einer Schaltfläche mit länger laufender Aktion (z.B. TMDB-Verknüpfen) - dieselbe
   Drehanimation wie der Dialog-Spinner oben, aber inline im Buttontext statt als eigener Block. */
.tmdbBtnSpinner {
	animation: spin 1s linear infinite;
	display: inline-block;
}

.servicesTable .actions button,
.bouquetsTable .actions button,
.dayFiltersTable .actions button {
	padding: 0.25em 0.5em;
}

#showTimerLogDialog .default-dialog-row {
	margin: 0;
}
#showTimerLogDialog table {
	margin: 0.5rem auto;
	width: 100%;
}
#showTimerLogDialog table .code {
	text-align: center;
}

.default-dialog .defaultAccordion {
	margin-top: 1em;
}

/* Die Bereiche trennt eine schmale Lücke, durch die der Dialoghintergrund scheint, statt einer Trennlinie:
   Zugeklappt stoßen die Namensbänder sonst mit ihrer eigenen hellen Kante an die Linie und es sieht aus wie zwei
   Linien untereinander. overflow lässt die rechteckigen Bänder der Rundung des Rahmens folgen - sonst schaut in
   jeder der vier Rundungen ihre eckige Ecke heraus. */
.defaultAccordion {
	border: 1px solid var(--line);
	border-radius: 6px;
	color: var(--text);
	display: flex;
	flex-direction: column;
	gap: 3px;
	overflow: hidden;
	width: 100%;
}

.defaultAccordionItem {
	min-width: 31rem;
}

.defaultAccordionItemName {
	background-color: var(--surface-band);
	color: var(--table-header-text);
	cursor: pointer;
	padding: 0.3em 0.5em;
}
.defaultAccordionItemName i {
	float: right;
	line-height: 1.2em;
}
.defaultAccordionItem.open .openIcon,
.defaultAccordionItem .closeIcon {
	display: none;
}
.defaultAccordionItem .openIcon,
.defaultAccordionItem.open .closeIcon {
	display: block;
}

.defaultAccordionContent {
	padding: 0.75em 0.75em;
}

.textFiltersTable {
	width: 100%;
}
.textFiltersTable th {
	background: var(--table-header-bg);
	color: var(--table-header-text);
	font-weight: bold;
	padding: 0 7px;
}
.textFiltersTable td {
	padding: 0;
}
.textFiltersTable td.actions {
	padding: 0 7px;
}
.textFiltersTable .textFilter input {
	min-width: 20rem;
	width: 100%;
}

/* Modern select + button row --------------------------------------------------------------- */

.select-row {
	align-items: center;
	display: inline-flex;
	gap: 0.5rem;
	margin: 0.5rem 0 1rem 0;
}

/* Der Pfeil wird selbst gezeichnet, nicht dem Browser überlassen (appearance: none plus eigenes Symbol).
   Grund ist nicht Geschmack, sondern dass jedes Gerät ein anderes zeichnet: Auf dem Telefon des Nutzers kam ein
   deutlich dünnerer Haarstrich heraus als im Chromium hier, und an der Strichstärke eines nativen Carets lässt
   sich nichts einstellen. Mit eigenem Symbol ist es überall dasselbe - dieselbe Form (Phosphor "caret-down") und
   dieselbe Stärke wie die Pfeile daneben.
   Der Farbwert steht als Zahl im Bild, weil eine CSS-Variable in einer data-URI nicht ankommt; er ist
   --control-text (#cfe0f5). Wer die Palette ändert, ändert ihn hier mit.
   Das erlaubt zugleich, den Platz um den Pfeil zu bestimmen, was beim nativen nicht ging: Der saß am äußersten
   Rand, während links 0,75rem Luft standen - jetzt ist es 0,5rem links und 0,625rem rechts neben dem Pfeil. */
.defaultSelect {
	appearance: none;
	background-color: var(--control-bg);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23cfe0f5' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 6 8 10.5 12.5 6'/%3E%3C/svg%3E");
	background-position: right 0.625rem center;
	background-repeat: no-repeat;
	background-size: 0.85rem;
	border: 1px solid var(--control-border);
	border-radius: var(--field-radius);
	color: var(--control-text);
	font-family: Verdana, sans-serif;
	font-size: 0.9rem;
	height: var(--control-height);
	line-height: 1.4;
	max-width: 100%;
	padding: 0 1.75rem 0 0.5rem;
	position: relative;
}

.defaultSelect optgroup {
	color: #fff;
	font-style: normal;
	font-weight: bold;
}
.defaultSelect optgroup,
.defaultSelect option {
	background-color: var(--surface-raised);
	color: var(--control-text);
}
.defaultSelect option[data-is-info] {
	font-style: italic;
}
.defaultSelect option[disabled] {
	color: #999;
	font-style: italic;
}
.defaultSelect option[data-is-marker] {
	color: #d44;
	font-style: italic;
}

.defaultSelect:focus {
	border-color: var(--control-border-hover);
	box-shadow: 0 0 0 3px rgba(136,140,204,0.12);
	outline: none;
}

.modern-btn {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	cursor: pointer;
	font-weight: bold;
	padding: 0.45rem 0.6rem;
}

.modern-btn:active {
	filter: brightness(0.95);
}

.modern-btn:active {
	transform: translateY(1px);
}

.modern-btn i {
	font-size: 1.1rem;
	line-height: 1;
}

/* ---------------------------------------------------------------------------------------------- */

/* Segmented toggle styles for index view */
/* Umschalter mehrerer Ansichten: außen eine Pille, innen die Segmente durch Trennlinien geteilt. Das gewählte
   Segment ist ausgefüllt - dieselben Farben, die ein Bedienelement beim Drücken trägt. */
.segmentedToggle {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	display: inline-flex;
	font-size: 0.85rem;
	height: var(--control-height);
	overflow: hidden; /* damit die ausgefüllten Endsegmente der Pillenform folgen */
	white-space: nowrap;
}

.segmentedToggle .seg-btn {
	align-items: center;
	border-right: 1px solid var(--control-border);
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	gap: 0.3rem;
	height: 100%;
	padding: 0 0.8rem;
	text-decoration: none;
}

.segmentedToggle .seg-btn:last-child {
	border-right: none;
}

.segmentedToggle .seg-btn:active:not(.active) {
	background: var(--control-bg-hover);
	color: var(--control-text-hover);
}

.segmentedToggle .seg-btn.active {
	background: var(--control-bg-hover);
	color: var(--control-text-hover);
}

.segmentedToggle .seg-btn:focus-visible {
	outline: 2px solid var(--control-border-hover);
	outline-offset: -2px;
}

.segmentedToggle .prevNextButtons {
	align-items: center;
	display: inline-flex;
	height: 100%;
}

/* Der Abstand sitzt symmetrisch an jedem der beiden Pfeile selbst statt am Container außenrum - sonst
   steht das Icon nicht mittig in seiner Fläche (der Container-Rand zählt nur einseitig mit). */
.segmentedToggle .prevNextButtons > * {
	align-items: center;
	display: inline-flex;
	height: 100%;
	padding: 0 0.5rem;
}

/* Die beiden Pfeile setzen sich optisch voneinander ab wie die übrigen Segmente der Pille - derselbe
   Trennstrich wie bei .seg-btn, hier auf das erste der beiden Elemente (Link oder deaktivierter Pfeil). */
.segmentedToggle .prevNextButtons > :first-child {
	border-right: 1px solid var(--control-border);
}

/* Dashboard tiles (index overview) ------------------------------------------------------------- */

.content .dashboard {
	align-items: flex-start;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: 1rem;
	margin: 1rem 0 1rem 0;
}

/* Auf der System-Seite stehen die Kästen nebeneinander und sollen gleich hoch sein, statt jeder für sich an seinem
   Inhalt zu enden - sie tragen unterschiedlich viele Zeilen. flex-start oben verhindert genau das, deshalb hier
   stretch. Greift nur im Nebeneinander: Unterhalb von 1024px stapelt .dashboard zu einer Spalte (siehe dortige
   Media Query, die align-items ohnehin überschreibt), und in Spaltenrichtung bestimmt align-items die Breite. */
.content .dashboard-info {
	align-items: stretch;
}

.content .db-info {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 6px;
	color: #ddd;
	flex-grow: 1;
	max-width: 100%;
	padding: 0.8rem;
	width: 26rem;
}

/* Die vier Kästen der System-Seite brechen je nach Fensterbreite auf zwei Zeilen um. Ohne Obergrenze zöge sich ein
   allein stehender Kasten der letzten Zeile über die ganze Seite (flex-grow oben) - bei der User-Box mit ihren zwei
   Zeilen sieht das aus wie ein Fehler.
   Die Regel steht bewusst hier und nicht bei den übrigen System-Regeln weiter oben: Sie muss nach .content .db-info
   stehen, um dessen max-width zu schlagen (gleiche Spezifität, es gewinnt die spätere), und vor der
   1024px-Media-Query, die sie unterhalb wieder aufhebt - dort bekommt jeder Kasten die volle Breite. */
.dashboard-info .db-info {
	max-width: 34rem;
}

/* Die Änderungen der Über-Seite stehen als letzte Kachel über die ganze Breite: Ihre Stichpunkte sind lange Zeilen,
   die in 34rem mehrfach umbrachen, und allein in der letzten Zeile ließe die Obergrenze oben die Seite halb leer. */
.dashboard-info .db-info.aboutChangelogTile {
	flex-basis: 100%;
	max-width: none;
}

.content .db-info .db-headline {
	border-bottom: 2px solid var(--line);
	color: #fff;
	font-size: 1.1rem;
	font-weight: bold;
	letter-spacing: 0.2em;
	margin: 0 0 0.6rem 0;
	padding-bottom: 0.4rem;
	text-transform: uppercase;
}

.content .db-info .db-headline .iconBtn,
.content .db-info .db-headline .videoSizeIcon {
	font-size: 1rem;
	vertical-align: bottom;
}

.content .db-rows + .db-headline {
	margin-top: 1.5rem;
}

.content .db-info .db-headline-right {
	float: right;
	letter-spacing: normal;
	text-transform: none;
}

.content .db-info .db-headline-sub {
	color: #ccc;
	font-size: 0.9rem;
	font-weight: normal;
	letter-spacing: normal;
	text-transform: none;
}

.content .db-info .db-headline .db-headline-sub {
	line-height: 1.5rem;
}

.content .disabled,
.content .disabled i {
	color: #999;
}

.content .db-rows {
	display: grid;
	gap: 0.5rem;
}

.content .db-row {
	align-items: center;
	display: flex;
	font-size: 0.9rem;
	gap: 0.5rem;
	justify-content: space-between;
}

.content .db-value {
	color: #6af;
	font-weight: bold;
}

/* Über-Seite: Fließtext in einem .db-row. Ohne diese Regel gilt die Zeile darüber - ein Flex-Kasten mit
   space-between, der die Teile eines Satzes an die beiden Kanten zöge (dieselbe Falle wie ein <mark> in einem
   Flex-Kasten, siehe highlight.js). Hier soll der Text schlicht fließen. */
.content .db-row.aboutText {
	display: block;
	line-height: 1.5;
}

/* Name und Lizenz bleiben die zwei Enden der Zeile; nur wenn die Fassungen lang werden (Apache Commons nennt
   sechs), darf die Lizenz umbrechen statt den Namen zu quetschen. Sie behält dabei ihre rechte Kante - ohne das
   margin sprang sie in der zweiten Zeile nach links und sah aus wie ein eigener, zusammenhangloser Eintrag. */
.content .db-row.aboutComponent {
	align-items: baseline;
	flex-wrap: wrap;
}

.content .db-row.aboutComponent .db-value {
	margin-left: auto;
}

/* Verweise im Fließtext dieser Seite müssen als solche zu erkennen sein. Die allgemeine Regel setzt jeden Link weiß
   (siehe "a" ganz oben), was auf einer Kachel richtig ist - dort ist die ganze Fläche klickbar und der Titel steht
   für sich -, mitten in einem Satz aber nicht vom übrigen Text zu unterscheiden. Blau wie die Werte der Kästen
   (.content .db-value), damit dafür keine dritte Farbe entsteht. */
.content .db-row.aboutText a,
.content .db-row.aboutAuthor a {
	color: #6af;
}

/* Hilfeseite: Fließtext zum Lesen, nicht zum Überfliegen - deshalb als eine Spalte in begrenzter Breite statt in
   den Kacheln der Über-/System-Seite. Über etwa 70 Zeichen je Zeile verliert man beim Zeilenwechsel die Zeile. */
.helpPage {
	max-width: 52rem;
}

/* Seiten ohne Zählzeile (System, Einstellungen) haben nichts, woran der Hilfe-Knopf hängen könnte - hier trägt ihn
   die Überschriftenzeile. Die Überschrift behält ihre Abstände, .tmdbHeaderActions schiebt sich mit seinem
   margin-left:auto wie überall an den rechten Rand. */
.pageTitleRow {
	align-items: center;
	display: flex;
}

/* Das Fragezeichen am rechten Ende einer Abschnittsüberschrift (siehe tools.html#help_link). Dasselbe Zeichen in
   derselben Farbe und Größe wie im Hilfe-Knopf der Seite (.tmdbIconBtn) - nur ohne dessen Fläche und Rahmen: Es ist
   erkennbar dieselbe Sache, aber ein Angebot und keine Handlung. Heller oder größer als dort wirkte es wie ein
   zweiter, wichtigerer Knopf. letter-spacing wird zurückgenommen, weil die Überschriften gesperrt sind und die
   Sperrung sonst als Lücke hinter dem Zeichen stünde. */
.helpAnchorLink {
	color: var(--control-text);
	font-size: 1.1rem;
	letter-spacing: normal;
	margin-left: auto;
}

.helpIntro {
	color: #aaa;
}

/* Das Inhaltsverzeichnis: die Abschnitte in einer Zeile, umbrechend. Es ist kurz genug, dass eine Liste
   untereinander nur Platz kostete, den der erste Abschnitt besser gebrauchen kann. */
.helpToc {
	border-bottom: 1px solid var(--line);
	border-top: 1px solid var(--line);
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem 0.9rem;
	margin: 1.2rem 0;
	padding: 0.8rem 0;
}

/* Verweise im Fließtext und im Verzeichnis tragen das kräftige Blau der Werte - bewusst ein anderer Ton als die
   Pfade in Festbreitenschrift (#68c, siehe unten): Was anklickbar ist, soll sich von dem unterscheiden, was nur
   hervorgehoben ist. */
.helpToc a,
.helpSection a {
	color: #6af;
}

/* Ein Trennpunkt zwischen den Einträgen: Bloßer Abstand reichte nicht, weil die Titel selbst aus mehreren Wörtern
   bestehen ("Filme und Serien zuordnen") - man las nicht, wo einer aufhört und der nächste anfängt. Der Punkt sitzt
   als ::after am Eintrag und nicht als eigenes Element, damit die Umbruchstellen die der Links bleiben; am letzten
   entfällt er. Gedämpft, weil er trennt und nicht anklickbar ist. */
.helpToc a:not(:last-child)::after {
	color: #667;
	content: "·";
	margin-left: 0.9rem;
}

.helpSection {
	margin-bottom: 2rem;
}

.helpSection h3 {
	margin-bottom: 0.6rem;
}

.helpSection p,
.helpSection li {
	line-height: 1.6;
}

.helpSection ul {
	margin: 0.6rem 0;
	padding-left: 1.2rem;
}

.helpSection li {
	margin-bottom: 0.5rem;
}

/* Pfade und Dateinamen im Text abheben, ohne dass daraus ein Codeblock wird - genau wie .settingsHint code, das
   dieselbe Aufgabe an anderer Stelle löst: Farbe statt Kasten. Ein Kasten mit eigenem Hintergrund war hier zuerst
   drin und ist wieder raus, weil er zwei Fehler auf einmal hatte: Der Unterschied zum Seitenhintergrund war so klein,
   dass man ihn kaum sah, und sein Innenabstand riss den Text auseinander, wo eine Angabe in Klammern steht.

   "monospace, monospace" ist kein Vertipper, sondern der bekannte Kniff: Steht dort nur einmal die Gattung, nimmt der
   Browser seine eigene, kleinere Vorgabegröße für Festbreitenschrift - der Text steht dann sichtbar tiefer als die
   Zeile drumherum. Mit der doppelten Nennung gilt wieder die Größe der Umgebung. */
.helpSection code,
.helpIntro code {
	/* Der gedämpfte Blauton der Fortschrittsbalken (siehe .timerProgressBar), nicht das kräftige #6af der Werte und
	   Verweise: Ein Pfad mitten im Satz soll auffindbar sein, aber nicht wie ein Link aussehen und nicht die Zeile
	   an sich ziehen. */
	color: #68c;
	font-family: monospace, monospace;
	font-size: 0.95em;
}

/* Die Angaben zur Person am Fuß der Kachel - Unterschrift, nicht Messwert (siehe about.html). Die Linie darüber
   trennt sie vom Programmstand, ohne dass es dafür eine eigene Kachel bräuchte. */
.content .db-row.aboutAuthor {
	border-top: 1px solid var(--line);
	display: block;
	line-height: 1.6;
	margin-top: 0.4rem;
	padding-top: 0.6rem;
}

/* Die Änderungen je Paket (siehe changelog.txt). */
.aboutChangelog {
	margin: 0.2rem 0 0.4rem;
	padding-left: 1.2rem;
}

.aboutChangelogOlder summary {
	color: #6af;
	cursor: pointer;
	margin-bottom: 0.4rem;
}

/* Die Fassung steht hinter dem Namen, aber gedämpft: Sie beantwortet eine Nachfrage, sie ist nicht die Aussage
   der Zeile. */
.aboutVersion {
	color: #aaa;
	font-weight: normal;
	margin-left: 0.4rem;
}

.content .db-sep {
	border: none;
	border-top: 1px solid var(--line);
	margin: 0.5em 0;
}

.content .tiles--flex {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
}

.content .tiles--grid {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(auto-fill, minmax(max(15vw, 9rem), 1fr));
}

.content .tile {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	color: #ddd;
	padding: 1rem;
	text-align: center;
}

.content .tiles--flex .tile {
	flex-grow: 1;
	min-width: 9rem;
}

.content .tile .tileIcon {
	color: #68c;
	font-size: min(6rem, 10vw);
}

.content .tile .tileMetaIcon {
	font-weight: bold;
	margin-right: 0.2rem;
	margin-top: 0.5rem;
}

/* Angehobene Fläche statt des alten #335: das lag wie der frühere Seitenhintergrund bei 240° und fiel neben der
   entsättigten Kachel (223°) als Farbwechsel statt als Aufhellen ins Auge. */
.content .tile:active {
	background: var(--surface-raised);
	box-shadow: 0 6px 18px rgba(0,0,0,0.45);
	color: #fff;
}
.content .tile:active .tileIcon {
	color: #6af;
}
	
.content .tile .tile-text {
	font-size: 1rem;
	font-weight: bold;
	margin-top: 0.5rem;
}

.content .tile .tile-meta {
	color: #aaa;
	font-size: 0.85rem;
	margin-top: 0.3rem;
}

/* Startseite: Kacheln zu Gruppen zusammengefasst, analog zu den Trennlinien-Gruppen im Flyout-Menü,
   nur mit einem farbigen, senkrecht beschrifteten Balken statt einer einfachen Linie, weil hier
   mehrspaltig statt einspaltig gelayoutet wird. */
/* align-items: stretch (Default), damit nebeneinander stehende Gruppen gleich hoch werden - die
   Gruppen mit weniger Zeilen wachsen dabei auf die Höhe der größten, siehe .tile-row unten.
   Der Außenabstand saß früher am .dashboard-Wrapper, den die Startseite seit dem Wegfall der Info-Box
   nicht mehr braucht - die Gruppenkacheln stehen dort jetzt allein und über die volle Breite. */
.content .tiles--grouped {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	margin: 1rem 0;
}

.content .tile-group {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	display: flex;
	flex-grow: 1;
	min-width: 16rem;
	overflow: hidden;
}

.content .tile-group-label {
	align-items: center;
	color: #fff;
	display: flex;
	flex-shrink: 0;
	font-size: 0.85rem;
	font-weight: bold;
	justify-content: center;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	width: 1.8rem;
}

.content .tile-group-label span {
	transform: rotate(180deg);
	writing-mode: vertical-rl;
}

.content .tile-group--recording .tile-group-label { background: var(--group-recording); }
.content .tile-group--mediathek .tile-group-label { background: var(--group-mediathek); }
.content .tile-group--misc .tile-group-label { background: var(--group-misc); }

.content .tile-group-rows {
	display: flex;
	flex-direction: column;
	flex-grow: 1;
}

/* flex: 1 verteilt die Höhe der Gruppenkachel gleichmäßig auf ihre Zeilen - Gruppen mit weniger
   Einträgen bekommen dadurch höhere Zeilen statt einer kürzeren Kachel. */
.content .tile-row {
	align-items: center;
	color: #ddd;
	display: flex;
	flex: 1;
	gap: 0.75rem;
	padding: 0.7rem 1rem;
	text-decoration: none;
}

.content .tile-row + .tile-row {
	border-top: 1px solid var(--line);
}

.content .tile-row:active {
	background: var(--surface-raised);
	color: #fff;
}

.content .tile-row .tileIcon {
	color: #68c;
	flex-shrink: 0;
	font-size: 1.8rem;
}

.content .tile-row:active .tileIcon {
	color: #6af;
}

.content .tile-row .tile-text {
	font-size: 1rem;
	font-weight: bold;
}

.content .tile-row .tile-meta {
	color: #aaa;
	font-size: 0.85rem;
	margin-top: 0.2rem;
}

.content .tile-row .tileMetaIcon {
	font-weight: bold;
	margin-right: 0.2rem;
}

/* Gleicher Rotton wie .cacheStaleIcon auf der System-Seite selbst - dieselbe Prüfung, nur als Symbol statt Zeile. */
.content .tile-row .tileMetaWarning {
	color: #e55;
	margin-left: 0.2rem;
}

/* Kachelseiten: Listen und Kategorien ----------------------------------------------------------- */

/* Die Übersicht der Listen und die der Kategorien sind seit dem 22.09.2026 gleich gebaut (Kachel mit Symbol, Name,
   Anzahl und Farbe; Klick führt auf die Detailseite), und ebenso ihre beiden Detailseiten. Die Regeln nennen deshalb
   nicht mehr eine der beiden Seiten, sondern hängen an .tilesPage und an den vier geteilten Klassen .tileLink,
   .tileActions, .createTileBtn und .tileGroupHeading. Vorher stand derselbe Satz Regeln zweimal da, einmal unter
   ".listsPage" und einmal unter ".categoriesPage", und lief bei jeder Änderung auseinander. */

.tilesPage .tileGroupHeading {
	align-items: center;
	display: flex;
	font-size: 1.1rem;
	gap: 0.4rem;
	margin: 1.2rem 0 0.6rem 0;
}

.tilesPage .tilesEmpty {
	color: #aaa;
	font-size: 0.9rem;
	margin: 0 0 0.5rem 0;
}

/* Das Symbol der Liste/Kategorie in der Kopfzeile ihrer Detailseite. */
.tilesPage .tileDetailIcon {
	color: #68c;
	margin-right: 0.3rem;
}

/* Knöpfe im .segmentedToggle (Reiter der Suche, Ansichten der EPG-Seite, Formatwahl, ...; anfangs nur der
   Bearbeiten-Umschalter, die übrigen Segmente waren Links): Browser-Rahmen und -Hintergrund weg, der Trennstrich
   bleibt. Bis zum 16.10.2026 nahm "border: none" ihn mit, weil diese Regel spezifischer ist als die für .seg-btn -
   alle Knopf-Pillen standen ohne Trennstriche da, während die aus Links (Box-Umschalter bei Timer/AutoTimer) sie
   hatten. */
.segmentedToggle button.seg-btn {
	background: transparent;
	border: none;
	border-right: 1px solid var(--control-border);
	cursor: pointer;
	font-family: inherit;
	font-size: inherit;
}

.segmentedToggle button.seg-btn:last-child {
	border-right: none;
}

/* min(9.25rem, 47%) statt eines festen Werts: auf dem Handy ist die Spalte schmaler als zwei Kacheln, es passte
   dort nur eine pro Zeile - breitgezogen und mit viel Leerraum. Der Prozentanteil deckelt die Mindestbreite genau
   dann, wenn sie nicht mehr zweimal hineinpasst, und lässt so immer zwei Kacheln nebeneinander zu. Auf größeren
   Bildschirmen gewinnt weiterhin der feste Wert.

   Die 9,25rem (148px) waren 11rem (176px) und sind am 22.09.2026 auf Wunsch gesunken: Auf dem Tablet des Nutzers
   standen quer 6 und hoch 4 Kacheln nebeneinander, jetzt sind es 8 und 5. Der Wert liegt zwischen zwei gemessenen
   Grenzen und hat nach beiden Seiten nur wenige Pixel Luft:

   - nach unten die Beschriftung. Die längste Kategorie des Bestands ist "Fortsetzung folgt"; in Verdana Bold bei
     0,9rem sind das rund 133px, dazu 12,8px Innenabstand der Kachel. Unter ~146px Spaltenbreite bricht sie um.
     (Gerechnet, nicht am Bildschirm abgelesen: Im Container fehlt Verdana, Textbreiten sind dort nicht
     originalgetreu - siehe CLAUDE.md.)
   - nach oben die Spaltenzahl im Hochformat: ab ~152px passen dort nur noch 4.

   Gilt für beide Übersichten; die Einträge einer Liste bekommen weiter unten ein eigenes, breiteres Raster. */
.content .categoryTiles,
.content .mediaListTiles {
	grid-template-columns: repeat(auto-fill, minmax(min(9.25rem, 47%), 1fr));
}

.content .tilesPage .tiles--grid {
	gap: 0.6rem;
}

/* Die Kachel ist eine Flex-Spalte, damit Meta-Zeile und Aktions-Buttons am unteren Rand sitzen und dadurch in einer
   Reihe immer auf gleicher Höhe stehen, auch wenn manche Titel mehrzeilig sind: */
.content .tilesPage .tile {
	display: flex;
	flex-direction: column;
	padding: 0.6rem 0.4rem 0.4rem 0.4rem;
}

.content .tilesPage .tile .tileIcon {
	font-size: 2.4rem;
}

.content .tilesPage .tile .tile-text {
	font-size: 0.9rem;
	margin-top: 0.3rem;
	overflow-wrap: anywhere;
}

.content .tilesPage .tile .tile-meta {
	margin-top: auto;
	padding-top: 0.2rem;
}

/* Der Link füllt die Kachel bis auf Meta-Zeile und Aktions-Buttons und ist selbst eine Flex-Spalte: */
.tilesPage .tileLink {
	color: inherit;
	display: flex;
	flex: 1;
	flex-direction: column;
	text-decoration: none;
}

/* Die "Neue Liste"/"Neue Kategorie"-Kachel als Button, sonst mit derselben Optik wie die übrigen Kacheln: */
.content .tilesPage .tile.createTileBtn {
	color: #aaa;
	cursor: pointer;
	font-family: inherit;
	justify-content: center;
}

/* Bearbeiten-Modus: die Aktions-Buttons und die "Neue ..."-Kachel sind nur darin sichtbar ---------- */

.tilesPage .tileActions,
.tilesPage .createTileBtn {
	display: none;
}

.tilesPage.editing .tileActions {
	display: flex;
	justify-content: center;
	margin: 0.2rem 0 0 0;
}

/* Die Knöpfe einer Übersichts-Kachel sind Berührungsziele und standen zu dicht: gemessen 22x24px ohne jede
   Lücke, also 22px von Mitte zu Mitte - mit dem Finger trifft man da den Nachbarn (gemeldet). Dabei war der Platz
   längst vorhanden: Die Aktionszeile ist 167px breit (Handy), die Knöpfe belegten davon nur 110px und standen
   mittig zusammengedrängt. (Es waren fünf, bis die beiden Pfeile am 22.09.2026 dem Greifer wichen.)
   Deshalb hier space-between statt center - das verteilt sie über die ganze Zeile - plus größere Trefferflächen.
   Bewusst ohne negative Seitenränder: Die Kachel hat auf diesen Seiten nur 6,4px Innenabstand (nicht das 1rem der
   allgemeinen Kachel-Regel, nachgemessen), ein Zurückholen davon zog die äußeren Knöpfe 4px über den Kachelrand
   hinaus und ließ dem Symbol 2px Luft. Die Zeilenbreite reicht auch so: 22px Mittenabstand werden zu 35px. */
.tilesPage.editing .categoryActions,
.tilesPage.editing .mediaListActions {
	justify-content: space-between;
	margin: 0.2rem 0 0;
}

/* Die Aktionszeile eines Eintrags hat weniger Knöpfe und sitzt auf den breiteren Kacheln der Detailseite. Dort
   genügt es, die Trefferflächen zu vergrößern und eine Lücke zu setzen: über die ganze Kachelbreite verteilt
   ständen zwei, drei Symbole verloren nebeneinander. */
.tilesPage.editing .categoryItemActions,
.tilesPage.editing .listItemActions {
	gap: 0.5rem;
}

.tilesPage.editing .tileActions button {
	padding: 0.3rem 0.35rem;
}

/* Die "Neue ..."-Kachel braucht denselben Selektor-Zuschnitt wie die Regel, die ihr weiter oben zusammen mit den
   übrigen Kacheln display:flex gibt (.content .tilesPage .tile) - mit weniger Klassen verliert das Verstecken gegen
   sie, und die Kachel stand dauerhaft da statt nur im Bearbeiten-Modus: */
.content .tilesPage .tile.createTileBtn {
	display: none;
}

.content .tilesPage.editing .tile.createTileBtn {
	display: flex;
}

/* Der Greifer zum Umsortieren (siehe dragSort.js). "touch-action: none" ist dabei nicht Kosmetik, sondern die
   Bedingung dafür, dass es auf einem Tablet überhaupt funktioniert: Ohne das wertet der Browser die Geste als
   Scrollen aus und schickt gar keine pointermove-Ereignisse mehr. */
.tilesPage .dragHandle {
	cursor: grab;
	touch-action: none;
}

.tilesPage .dragHandle:active {
	cursor: grabbing;
}

/* Die gezogene Kachel hebt sich ab und liegt über ihren Nachbarn - sie wandert ja durch sie hindurch. Ohne
   position/z-index schöbe sich die nächste Kachel im Raster darüber, sobald umgehängt wird. */
.tilesPage .dragSortActive {
	box-shadow: 0 8px 24px rgba(0,0,0,0.55);
	opacity: 0.9;
	position: relative;
	z-index: 5;
}

/* Einträge einer Kategorie ---------------------------------------------------------------------- */

/* Die Kacheln sind dieselben wie in der Film-/Serienübersicht (siehe inc/tmdbMeta.html), ihre Optik kommt daher aus
   dem TMDB-Abschnitt. Hier nur der Eintrag, dessen TMDB-Entität es nicht mehr gibt: */
.categoriesPage .tmdbTile.missing .tmdbPosterPlaceholder,
.categoriesPage .tmdbTile.missing .tmdbTileTitle {
	color: #d44;
}

/* In einer Kategorie tritt die Aktionszeile des Eintrags an die Stelle der Zeile mit dem "..."-Menü. Wo diese sitzt,
   ist je nach Kachel verschieden: bei Film und Filmreihe neben den TMDB-/Trailer-Links, bei einer Serie neben
   "Nächste Folge" (deren Link-Zeile hat kein Menü und bleibt deshalb stehen). */
.categoriesPage.editing .tmdbTile .tmdbTileLinks:has(.tmdbTileMoreActions),
.categoriesPage.editing .tmdbTile .tmdbTileActions {
	display: none;
}

/* Einträge einer Liste -------------------------------------------------------------------------- */

/* Breiter als die Kacheln der beiden Übersichten: Dort steht ein selbst vergebener, meist kurzer Name, hier der
   Titel einer Aufnahme bzw. der Name eines Ordners - und der bringt oft Sender, Datum oder Folgennummer mit. */
.content .listItemTiles {
	grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}

/* Der Titel bekommt den Platz zwischen Icon und Meta-Zeile und wird darin vertikal zentriert - anders als auf den
   beiden Übersichten, wo die Kachel niedrig ist und der Name direkt unter dem Symbol steht: */
.content .listsPage .tile.listItem .tile-text {
	align-items: center;
	display: flex;
	flex: 1;
	justify-content: center;
	margin-top: 0.2rem;
}

/* Die Meta-Zeile sitzt am unteren Ende der Kachel; Text und Play-Button (falls vorhanden) stehen als Gruppe
   zentriert nebeneinander: */
.content .listsPage .tile.listItem .tile-meta {
	align-items: center;
	display: flex;
	justify-content: center;
}

/* Als Flex-Item greift "margin-top" von .tileMetaIcon (siehe oben) hier tatsächlich, anders als vorher im Fließtext -
   "margin-right" ergibt weiterhin den Abstand zum Text daneben, wie vorher: */
.content .listsPage .tile.listItem .tile-meta .tileMetaIcon {
	margin-top: 0;
}

.content .listsPage .tile.listItem .tile-meta .listItemPlay {
	margin-left: 0.75rem;
}

.listsPage .listItem.missing .tileIcon,
.listsPage .listItem.missing .tile-meta {
	color: #d44;
}

.listsPage .listItemPlay {
	align-items: center;
	background-color: transparent;
	border: none;
	color: #fff;
	cursor: pointer;
	display: inline-flex;
	padding: 0;
}

.listsPage .listItemPlay i {
	font-size: 1.1rem;
}

/* Der rote Hinweis "nicht gefunden" - in der Kopfzeile der Detailseite wie auf der Kachel selbst. */
.listItemMissing {
	color: #d44;
}

/* Schmaler Bildschirm: auf dem Handy passt bei 15rem nur noch eine Kachel pro Reihe. */
@media (max-width: 640px) {
	.content .listItemTiles {
		grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
	}
}

/* Dialoge (Listen und Kategorien) ----------------------------------------------------------------------------- */

.dialogField {
	align-items: center;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.dialogLabel {
	display: inline-block;
	font-weight: bold;
	min-width: 5rem;
}

.dialogField .dialogInput {
	flex: 1;
	min-width: 12rem;
}

.default-dialog-row .defaultTextarea {
	font-family: monospace;
	font-size: 0.8rem;
	height: auto;
	line-height: 1.3;
	width: 100%;
}

/* Icon-Auswahl in den Bearbeiten-Dialogen von Listen und Kategorien (siehe inc/iconPicker.html); die Optik der
   Labels kommt von .hiddenRadio + label. */
.iconPicker {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	max-width: 22rem;
}

/* Feste Kantenlänge, damit die unterschiedlich breiten Icons trotzdem ein gleichmäßiges Raster ergeben: */
.iconPicker label {
	align-items: center;
	display: flex;
	font-size: 1.3rem;
	height: 2rem;
	justify-content: center;
	line-height: 1;
	padding: 0;
	width: 2rem;
}

/* Die Beschriftung fluchtet mit der ersten Icon-Reihe statt neben dem Block zentriert zu stehen: */
.dialogField:has(.iconPicker) {
	align-items: flex-start;
}

.selectListsCount {
	color: #999;
	font-size: 0.85em;
	margin-left: 0.4em;
}

/* Remote Control ------------------------------------------------------------------------------- */

.remoteTextForm {
	margin-top: 1rem;
}

.remoteTextForm #remoteTextInput {
	max-width: 60vw;
	width: 30rem;
}

.remoteTextForm #remoteTextBtn {
	margin-right: 0;
	min-width: auto;
	padding: 0 0.5em 0 0.5em;
}

.remoteOptions {
	margin: 0.5rem 0;
}

.remote {
	background: #111111;
	border-radius: 28px;
	box-shadow: 0 0 0 2px #1a1a1a, 0 0 0 4px #3a3a3a, 0 20px 60px rgba(0, 0, 0, 0.8), inset 0 1px 0 rgba(255, 255, 255, 0.05);
	margin-top: 1rem;
	padding: 0.5em 1em;
	width: 240px;
}

.remote .section {
	padding: 0.6em 0;
}

.remote button {
	border: none;
	cursor: pointer;
	font-family: inherit;
	font-weight: 700;
	font-size: 0.75rem;
	height: 2.5rem;
	letter-spacing: 0.05em;
	transition: filter 0.08s, transform 0.08s;
	user-select: none;
}

/* Die einzige Rückmeldung der Fernbedienungstasten - je Tastenfarbe gab es früher zusätzlich eine eigene
   Hover-Farbe, die aber nur den ohnehin vorhandenen Druckeffekt verdoppelte. */
.remote button:active {
	filter: brightness(0.75);
	transform: scale(0.94);
}

/* ── Grid helpers ── */
.remote .grid-3 {
	display: grid;
	gap: 8px;
	grid-template-columns: repeat(3, 1fr);
}

.remote .grid-4 {
	display: grid;
	gap: 8px;
	grid-template-columns: repeat(4, 1fr);
}

/* ── Dark square buttons (number pad) ── */
.remote .btn-dark {
	background: #3d3d3d;
	border-radius: 10px;
	box-shadow: 0 3px 0 #222, inset 0 1px 0 rgba(255, 255, 255, 0.08);
	color: #e0e0e0;
	width: 100%;
}

.remote .num-pad button {
	font-size: 1rem;
}

/* ── Grey square buttons (nav area) ── */
.remote .btn-grey {
	background: #8a8a8a;
	border-radius: 10px;
	box-shadow: 0 3px 0 #222, inset 0 1px 0 rgba(255, 255, 255, 0.08);
	color: #e0e0e0;
	width: 100%;
}

/* ── Red buttons ── */
.remote .btn-red {
	background: #cc2222;
	border-radius: 10px;
	box-shadow: 0 3px 0 #222, inset 0 1px 0 rgba(255, 255, 255, 0.08);
	color: #fff;
	width: 100%;
}

/* ── Color bar buttons ── */
.remote .btn-color {
	border-radius: 8px;
	box-shadow: 0 3px 0 #222, inset 0 1px 0 rgba(255, 255, 255, 0.08);
	height: 1.5rem;
	width: 100%;
}

.remote #btn-color-red {
	background: #cc2222;
}

.remote #btn-color-green {
	background: #22aa22;
}

.remote #btn-color-yellow {
	background: #ccaa00;
}

.remote #btn-color-blue {
	background: #2244cc;
}

.remote .btn-icon {
	font-size: 1.5rem;
}

.remote .btn-labeled-icon .btn-icon {
	font-size: 1.2rem;
}
.remote .btn-labeled-icon .btn-label {
	color: #aaa;
	font-size: 0.6rem;
}

/* ── Oval/pill buttons (media controls bottom) ── */
.remote .btn-oval {
	background: #3d3d3d;
	border-radius: 20px;
	box-shadow: 0 3px 0 #222, inset 0 1px 0 rgba(255, 255, 255, 0.08);
	color: #c0c0c0;
	font-size: 0.6rem;
	height: 2rem;
	width: 100%;
}

.remote #btn-rec {
	color: #cc2222;
}

.remote .btn-cursor .btn-icon,
.remote .btn-media .btn-icon {
	font-size: 1.2rem;
}

/* ── HELP / PWR top row ── */
.remote .top-row {
	display: flex;
	gap: 8px;
	justify-content: center;
}

.remote .top-row button {
	border-radius: 10px;
	font-size: 0.75rem;
	width: 5rem;
}

.remote #btn-help {
	background: #3d3d3d;
	box-shadow: 0 3px 0 #222, inset 0 1px 0 rgba(255, 255, 255, 0.08);
	color: #e0e0e0;
}

.remote #btn-pwr {
	background: #cc2222;
	box-shadow: 0 3px 0 #222, inset 0 1px 0 rgba(255, 255, 255, 0.08);
	color: #fff;
}

/* ---------------------------------------------------------------------------------------------- */

@media (max-width: 1280px) {

	/* Edit-Form -------------------------------------------------------------------------------- */

	.editForm,
	.editMovieForm,
	.editTimerForm,
	.editAutoTimerForm {
		bottom: 0;
		height: auto;
		left: 0;
		margin: 0;
		max-height: none;
		max-width: none;
		min-width: auto;
		overflow: auto;
		padding: 0.5em 1em 1em 1em;
		position: fixed;
		right: 0;
		top: 4rem;
		width: auto;
		z-index: 10;
	}
}

@media (max-width: 1024px) {
	.sidebar {
		display: none;
	}

	.main-content {
		padding-right: 0;
	}

	/* Hier steht die Schaltflächenreihe einzeilig unter dem Text. Führen beide Sprungknöpfe ins Leere, dürfen sie
	   ganz entfallen - ein Verrutschen der übrigen stört in einer eigenen Zeile niemanden. Einzeln tote Knöpfe
	   bleiben dagegen auch hier stehen, sonst rückte der andere an ihre Stelle.
	   Die Regel hängt bewusst an der Anordnung und nicht am Gerät: Wird die Kopfzeile später ebenfalls einzeilig,
	   gehört sie dorthin mit. */
	.nowPlayingButtons.nowPlayingNavDead .nowPlayingNav {
		display: none;
	}

	/* Hier steht die Reihe einzeilig, senkrecht ist also mehr Luft als im Raster - die Trefferfläche darf nach oben
	   und unten großzügiger ausfallen. Genau hier wird auch mit dem Finger bedient. */
	.nowPlayingButtons > button::after,
	.nowPlayingButtons .toggleMoreFlyout::after {
		inset: -8px -4px;
	}

	.content .dashboard {
		align-items: normal;
		flex-direction: column;
	}

	.content .db-info {
		max-width: none;
		width: 100%;
	}

	/* Actions ---------------------------------------------------------------------------------- */

	/* Hier entfällt die Abkürzungsleiste ganz, und das "..."-Menü daneben ist die einzige Bedienung der Zeile.
	   Es kann das sein, weil es seit dem 16.09.2026 ohnehin alle Aktionen enthält (siehe .actions .rowActions).

	   Bis dahin standen hier rund sechzig Zeilen, die Leiste und Menü zu einem einzigen senkrechten Popup
	   verschmolzen: Die Leiste wurde selbst zum Menü, ihre Knöpfe zu Menüeinträgen, das Menü zu deren unterem
	   Abschnitt, und ein zweiter Auslöser (.toggleActionFlyout) klappte das Ganze auf. Das hatte eine Folge, die
	   nichts mit der Breite zu tun hat: Die Trennlinie im Menü trennte nicht nach Bedeutung, sondern nach der
	   Naht zwischen beiden Bereichen - im selben Menü ließ sich also nicht gruppieren wie überall sonst. */
	.actions .actionFlyout {
		display: none;
	}

	/* MovieDirs -------------------------------------------------------------------------------- */

	.movieDirsTable .size,
	.movieDirsTable .length,
	.movieDirsTable .age,
	.movieDirsTable .gotoUrl {
		display: none;
	}

	.movieDirsTable .count,
	.movieDirsTable .unwatched,
	.movieDirsTable .modified {
		font-size: 0.9em;
		white-space: nowrap;
	}

	/* MovieList -------------------------------------------------------------------------------- */

	.movieListTable .type,
	.movieListTable .size {
		display: none;
	}

	/* Timer ------------------------------------------------------------------------------------ */

	.timerTable .time {
		font-size: 0.9em;
	}

	.timerTable .tags,
	.timerTable .autoTimer {
		display: none;
	}
}

@media (min-width: 50rem) {
	.editMovieForm,
	.editTimerForm,
	.editAutoTimerForm {
		flex: 1;
		min-width: 50rem;
		padding-bottom: 0.75em;
		padding-top: 0.75em;
	}
	.editMovieForm {
		padding-top: 2.75em;
	}

	.editMovieForm .form-group:not(.form-group--col1),
	.editTimerForm .form-group:not(.form-group--col1),
	.editAutoTimerForm .form-group:not(.form-group--col1) {
		display: flex;
		margin-bottom: 0.6em;
	}

	.editMovieForm .form-group:not(.form-group--col1) .fieldLabel,
	.editTimerForm .form-group:not(.form-group--col1) .fieldLabel {
		margin-bottom: 0;
		width: 18.5em;
	}

	.editAutoTimerForm .form-group:not(.form-group--col1) .fieldLabel {
		margin-bottom: 0;
		width: 20em;
	}

	.editMovieForm .form-group:not(.form-group--col1) .fieldLabel .fieldLabelIcon,
	.editTimerForm .form-group:not(.form-group--col1) .fieldLabel .fieldLabelIcon,
	.editAutoTimerForm .form-group:not(.form-group--col1) .fieldLabel .fieldLabelIcon {
		float: right;
		margin-right: 1em;
		margin-top: 0.5em;
	}
	.editMovieForm .form-group:not(.form-group--col1) .fieldLabel .fieldLabelIcon + .fieldLabelIcon,
	.editTimerForm .form-group:not(.form-group--col1) .fieldLabel .fieldLabelIcon + .fieldLabelIcon,
	.editAutoTimerForm .form-group:not(.form-group--col1) .fieldLabel .fieldLabelIcon + .fieldLabelIcon {
		margin-right: 0;
	}

	.editMovieForm .form-group:not(.form-group--col1) .form-field,
	.editTimerForm .form-group:not(.form-group--col1) .form-field,
	.editAutoTimerForm .form-group:not(.form-group--col1) .form-field {
		flex: 1;
	}
}

@media (max-width: 640px) {
	header {
		gap: 0.5rem;
		height: 3rem;
		max-width: 100vw;
	}

	.menuBtn {
		height: 3rem;
		width: 3rem;
	}

	.menuBtn .label {
		display: none;
	}

	.globalActions .toggleRemote {
		display: none;
	}
	/* inline-flex statt block, damit die Glyphe mittig bleibt (siehe .globalActions .iconBtn). */
	.globalActions .gotoRemote {
		display: inline-flex;
	}

	/* Auf dem Handy sind die Menüs der Kopfzeile das einzige, was von "Jetzt läuft" zu sehen ist - dort lohnt
	   mehr Luft als die 0.4em ringsum, die für ein Menü zwischen Tabellenzeilen gedacht sind. Links am meisten,
	   weil dort die Texte anfangen. ".actions" wie oben, um nicht mit ".actions .moreFlyout" gleichaufzuliegen.
	   max-width höher als die 80vw von oben: hochkant blieben davon auf einem 390px-Gerät nur 312px, und die
	   Texte wurden mit "..." gekürzt, obwohl rechts noch Platz war. Die restlichen 8vw halten den Abstand zum
	   Rand, den positionFlyout ohnehin erzwingt.
	   font-size etwas größer als die 1rem von oben: hier ist das Menü die einzige Darstellung von "Jetzt läuft",
	   nicht bloß eine Ausweichlösung. Es zieht die em-basierten Zeilen (Beschreibung, Sender) mit hoch. */
	.globalActions .actions .moreFlyout {
		font-size: 1.1rem;
		max-width: 92vw;
		padding: 0.6em 0.5em 0.6em 0.9em;
	}

	/* Titel und Schaltflächen rechnen in rem, folgen der Vergrößerung darüber also nicht von selbst. */
	.globalActions .nowPlayingTitle {
		font-size: 1.05rem;
	}

	.moreFlyout.nowPlayingFlyout .nowPlayingButtons > button,
	.moreFlyout.nowPlayingFlyout .nowPlayingButtons .toggleMoreFlyout {
		font-size: 1.5rem;
	}

	/* Die Zeilen des Tonspur-Menüs ebenso - sie rechnen in rem und blieben sonst als einzige klein.
	   Wichtig: die Größe gehört an beide Zeilenformen, nicht nur an den Text. Ihre Innenabstände rechnen in em,
	   und schon 0.15rem Unterschied zwischen der aktiven Zeile (<span>) und den Schaltflächen verschiebt die
	   Symbolspalte sichtbar gegeneinander. */
	.globalActions .audioTrackFlyout button,
	.globalActions .audioTrackFlyout .audioTrackName {
		font-size: 0.95rem;
	}

	.globalActions .audioTrackFlyout button span {
		font-size: inherit;
	}

	.flyout-menu {
		max-height: calc(var(--vh) * 100 - 3rem);
		top: 3rem;
	}

	.logo {
		font-size: 0.67rem; /* skaliert .testTag proportional zur verkleinerten Höhe mit, siehe dort */
		height: 2rem;
	}

	.globalActions {
		font-size: 0.6em;
		gap: 0;
	}

	main {
		display: block;
		margin-top: 3rem;
		padding: 0 0.5rem;
	}

	.content {
		max-width: 100vw;
		overflow: auto;
		padding: 0.75rem 0 0 0;
	}

	.defaultSelect {
		flex: 1 1 auto;
		min-width: 10rem;
	}

	.select-row {
		display: flex;
		width: calc(100vw - 1rem);
	}

	/* Feste Breite statt nur max-width: <dialog> ist von Haus aus fit-content, dadurch war jeder Dialog auf dem
	   Handy unterschiedlich breit (ein Dialog mit langem Dateipfad fast randfüllend, die Ordnerauswahl dagegen
	   deutlich schmaler). Einheitliche Breite mit 1rem Rand an beiden Seiten: */
	.default-dialog {
		margin: auto;
		max-width: calc(100vw);
		width: calc(100vw - 2rem);
	}

	/* Die Backdrop-Variante legt den Dialog als Flex-Item mittig ins Fenster; ohne dieses Zurücksetzen würde die
	   flex-basis (max-content, siehe .default-dialog-large) die Breite oben überstimmen: */
	.default-dialog-backdrop[open] .default-dialog-large {
		flex: 0 0 auto;
	}

	.content--remote {
		display: none;
	}

	.remoteTextForm {
		display: flex;
		gap: 0.5rem;
		margin-top: 0.5rem;
	}

	.remoteTextForm #remoteTextInput {
		flex: 1 1 auto;
		max-width: none;
		width: inherit;
	}
	
	.remoteTextForm #remoteTextBtn {
		margin: 0;
	}

	.remoteOptions {
		margin: 0.5rem 0;
	}

	.remoteOptions .defaultCheckboxLabel {
		width: 100%;
	}

	.remote {
		margin: 0.75rem auto 0 auto;
		padding: 0.25em 1em;
	}
	
	.remote button {
		height: 2.25rem;
	}

	.remoteFlyout {
		left: calc(50% - 120px);
		margin: 0;
		position: fixed;
		top: 3.75rem;
	}

	#remoteFlyout,
	#remoteFlyout.open {
		display: none;
	}

	/* Statuszeile bei Tabellenseiten ----------------------------------------------------------- */

	.infoBar {
		font-size: 0.9rem;
		gap: 0.5rem 1rem;
		margin: 0 0 1rem 0;
	}

	.infoBar .reloadBtn {
		display: none;
	}

	.countLabel {
		display: none;
	}
	.countIcon {
		display: inline;
	}
	/* Mit dem Wort davor muss auch sein Zusatz weichen - ohne das stünde in der schmalen Zeile "274 (191 komplett)"
	   ohne das Wort, auf das sich die Klammer bezieht (siehe tmdbmovies.html). */
	.countSub {
		display: none;
	}

	/* Ausnahme Streaming-Portal: Dort bleibt er stehen. Die Zeile trägt dort nur zwei Angaben statt fünf, der
	   Platz ist also da - und wer die Mediathek nur zum Ansehen benutzt, hat die Zeichen nicht so im Griff wie ein
	   Administrator, der sie täglich sieht. */
	body.portalMode .countSub {
		display: inline;
	}

	/* Und aus demselben Grund die führende Beschriftung statt ihres Ersatz-Zeichens - dieselbe Vertauschung wie bei
	   der Kategorien-Übersicht unten. Im Portal steht sonst nirgends auf der Seite, wo man ist: Das Seitenmenü fehlt,
	   eine Überschrift gibt es nicht, es bliebe allein die Filmrolle in der Zeile.
	   Beides zusammen wäre verschwendeter Platz, deshalb das Zeichen weg. */
	body.portalMode .countLabel {
		display: inline;
	}

	body.portalMode .countIcon {
		display: none;
	}

	/* Der seitliche Rand des Portals kommt hier wieder weg: Er ersetzt die fehlende Seitenleiste, damit der Inhalt am
	   breiten Bildschirm nicht an der Fensterkante klebt (siehe body.portalMode .main-content). Hochkant auf dem Handy
	   polstert <main> aber schon selbst, und die 1,2rem obendrauf ergaben 27px je Seite statt der 8px, die der
	   Administrator hat - bei 360px Breite ein Siebtel des Bildschirms für nichts. Oben und unten bleibt er.
	   Nur hier drin und damit nur hochkant: Im Querformat ist das Handy breiter als 640px, dort stört er nicht. */
	body.portalMode .main-content {
		padding-left: 0;
		padding-right: 0;
	}

	/* Ausnahme Kategorien-Übersicht: in deren Kopfzeile steht sonst nichts, dort ist auch auf dem Handy Platz für
	   die ausgeschriebene Beschriftung. Das Ersatz-Icon bleibt den gedrängten Kopfzeilen der übrigen Seiten
	   (Aufnahmen, Timer, ...) vorbehalten. */
	.categoriesPage .countLabel {
		display: inline;
	}

	.categoriesPage .countIcon {
		display: none;
	}

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

	table td {
		overflow-wrap: break-word;
		word-break: break-all;
	}

	/* MovieDirs -------------------------------------------------------------------------------- */

	.movieDirsTable .size,
	.movieDirsTable .length,
	.movieDirsTable .modified,
	.movieDirsTable .age,
	.movieDirsTable .gotoUrl {
		display: none;
	}

	/* MovieList -------------------------------------------------------------------------------- */

	.movieListTable .type,
	.movieListTable .size,
	.movieListTable .sender,
	.movieListTable .tags {
		display: none;
	}

	/* Timer ------------------------------------------------------------------------------------ */

	.timerTable .length,
	.timerTable .type,
	.timerTable .sender,
	.timerTable .tags,
	.timerTable .autoTimer {
		display: none;
	}

	/* AutoTimer -------------------------------------------------------------------------------- */

	.autoTimerTable .type,
	.autoTimerTable .filter,
	.autoTimerTable .sender,
	.autoTimerTable .tags,
	.autoTimerTable .timerCount {
		display: none;
	}

	.defaultAccordionItem {
		min-width: auto;
	}

	.textFiltersTable .textFilter input {
		min-width: auto;
	}

	/* EPG -------------------------------------------------------------------------------------- */

	.epgTable .length,
	.epgTable .timer {
		display: none;
	}
	
	/* Edit-Form -------------------------------------------------------------------------------- */

	.editForm,
	.editMovieForm,
	.editTimerForm,
	.editAutoTimerForm {
		top: 3rem;
	}
}

/* TMDB (Filme/Serien) ---------------------------------------------------------------------------- */

/* justify-content entfaellt bewusst: seit .countInfo display:contents traegt, waeren dessen einzelne Angaben
   Flex-Elemente der Leiste und wuerden ueber die volle Breite verteilt. Rechtsbuendig haelt sich die
   Aktionsgruppe ohnehin selbst (siehe .tmdbHeaderActions). */
.tmdbPage .infoBar {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	row-gap: 0.5rem;
}


.warningHint {
	color: #d44;
	margin: 0 0 1rem 0;
}

/* Ein Verweis in der Warnzeile hebt sich durch Helligkeit und Gewicht ab, nicht durch einen Unterstrich - den
   trägt hier kein Verweis (global: text-decoration none). Das Blau der übrigen Verweise (siehe .settingsHint a)
   risse die rote Zeile auseinander, deshalb der hellere Ton derselben Farbe. Ganz ohne Auszeichnung war
   "Einstellungen" gar nicht als Verweis zu erkennen: Verweise sind global weiß, also heller als die Warnzeile -
   das liest sich als bloße Hervorhebung. */
.warningHint a {
	color: #f88;
	font-weight: 600;
}

/* Die Klasse bedeutet "nicht rot": Rot (.warningHint) meldet eine Störung, das hier meldet einen Befund - "Nichts
   gefunden", "Die ersten 500 von 506", "36 Filme sind nicht in deiner Mediathek".

   Dass daraus bis zum 11.09.2026 auch "dunkler als Fließtext" wurde (#aaa), war ein Nebeneffekt und keine Absicht.
   Solche Sätze sagen etwas über die gezeigten Daten aus und sind damit genauso wichtig wie der erklärende Absatz
   darüber - es gab keinen Grund, sie schlechter lesbar zu machen. Was wirklich Beiwerk ist, bekommt eine eigene
   gedämpfte Klasse (siehe .settingsHintAside). */
.tmdbEmpty {
	color: var(--text);
	margin: 1rem 0;
}

/* Hinweis auf der Detailseite, dass es den Eintrag bei TMDB nicht mehr gibt (siehe inc/tmdbMeta.html#missingNotice).
   Deutlicher als der schlichte .warningHint darüber: Es geht um einen dauerhaften Zustand, der erklärt werden muss, und
   nicht um eine vorübergehende Meldung. Das Zeichen bleibt oben, damit es bei mehrzeiligem Text nicht mitrutscht. */
.tmdbMissingNotice {
	align-items: center;
	background: rgba(221,68,68,0.08);
	border: 1px solid rgba(221,68,68,0.45);
	border-radius: 6px;
	color: var(--text);
	display: flex;
	gap: 0.8rem;
	/* Großzügiger als der Standard: Der Kasten trägt mehrere Zeilen Fließtext, und in einer Meldung, die man nur
	   einmal liest und dann verstanden haben soll, hilft die Luft zwischen den Zeilen spürbar. */
	line-height: 1.55;
	margin: 0 0 1rem 0;
	padding: 0.7rem 0.9rem;
}

/* Die übliche Textfarbe auf dem rötlichen Grund: Ein abgetöntes Rot war darauf kaum zu lesen, reines Weiß dagegen
   grell. Die Warnfarbe trägt allein das Zeichen, das dafür groß genug ist, um die Meldung von weitem einzuordnen. */
.tmdbMissingNotice > i {
	color: #d44;
	flex-shrink: 0;
	font-size: 2.6rem;
}

/* Der Pfad im Hinweis "Der verknüpfte Ordner fehlt": als Pfad kenntlich, ohne dass die Meldung technisch wirkt -
   deshalb nur eine leicht abgesetzte Fläche statt einer echten Schreibmaschinenschrift in anderer Größe. */
.tmdbMissingNotice code {
	background: rgba(255, 255, 255, 0.07);
	border-radius: 4px;
	/* Der doppelte Eintrag ist kein Versehen, sondern der übliche Kniff gegen eine Browser-Eigenheit: Steht dort
	   allein das Schlüsselwort "monospace", rechnen Browser relative Schriftgrößen gegen ihre eigene Vorgabe für
	   Festbreitenschrift (13px) statt gegen den umgebenden Text. Ohne die zweite Angabe hinge die tatsächliche
	   Größe also an einer Browser-Einstellung statt an dieser Zeile.
	   0.9em ergibt die nachgemessenen 14,4px - etwas kleiner als der Fließtext daneben, weil eine
	   Festbreitenschrift bei gleicher Punktgröße breiter baut und sonst aus der Zeile herausspringt. */
	font-family: monospace, monospace;
	font-size: 0.9em;
	padding: 0.05em 0.35em;
	word-break: break-all;
}

/* Die Abhilfe steht mit im Kasten (siehe tmdbMeta.html#dirMissingNotice). Eigene Zeile statt inline im Fließtext:
   Der Knopf ist höher als eine Textzeile und drückte die Zeile, in der er stand, sichtbar auseinander.
   "display: flex" (nicht inline-flex) macht ihn dafür block-artig, "width: fit-content" hält ihn trotzdem so
   schmal wie seine Beschriftung, statt ihn über die ganze Kastenbreite zu ziehen. */
.tmdbMissingNotice .tmdbPillBtn {
	display: flex;
	margin-top: 0.6rem;
	width: fit-content;
}

/* Breadcrumb-Zeile: trägt rechts zusätzlich das "Weitere Aktionen"-Menü der Seite (siehe .tmdbHeaderActions),
   daher Flex statt schlichtem Textabsatz. margin-top sorgt für den Abstand zum Seitenkopf - ohne ihn beginnt der
   Breadcrumb unmittelbar unter der festen Kopfzeile: */
.tmdbBreadcrumb {
	align-items: center;
	color: #aaa;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0.75rem 0 1rem 0;
	min-height: 2rem;
	/* Bewusst kein padding-right: der "..."-Button soll rechts genauso weit vom Rand stehen wie der Zurück-Button
	   links, und beide bündig mit der Inhaltsspalte (Überschrift, Meta-Zeile, Kachelraster). Ein Zusatzabstand nur
	   rechts fiel auf schmalen Bildschirmen als Schieflage auf - dort bringt die Spalte schon beidseitig 8px mit,
	   ein weiteres 1rem ergab 24px rechts gegen 8px links. Die Kopfzeilen der Übersichtsseiten (ohne Breadcrumb)
	   enden ohnehin an derselben Kante. */
}

/* Aktionsgruppe im Seitenkopf - in der Breadcrumb-Zeile nur das "..."-Menü, auf den Übersichtsseiten zusätzlich
   der "Hinzufügen"-Button davor. margin-left:auto hält die Gruppe rechtsbündig, unabhängig davon wie lang der
   Text links daneben ist und ob sie in eine eigene Zeile umbricht: */
.tmdbHeaderActions {
	align-items: center;
	display: inline-flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-left: auto;
}

/* Zurück-Button ganz links: nur das Pfeil-Icon, rund und mit Rahmen, damit der Pfeil klar als Bedienelement
   auftritt statt als Textdekoration am ersten Pfad-Eintrag zu kleben. Er führt eine Ebene nach oben, also auf
   denselben Ort wie der letzte Eintrag des Pfades daneben: */
.tmdbCrumbBack {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	display: inline-flex;
	flex: none;
	height: 2rem;
	justify-content: center;
	width: 2rem;
}

.tmdbCrumbBack:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Der Pfad selbst als <ol> (semantisch eine geordnete Abfolge), ohne die Standard-Einrückung einer Liste: */
.tmdbCrumbTrail {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	list-style: none;
	margin: 0;
	padding: 0;
}

.tmdbCrumbTrail li {
	align-items: center;
	display: inline-flex;
}

/* Trenner als gedrehtes Rahmeneck statt als Icon-Glyphe: so sieht jeder Trenner gleich aus und ist unabhängig
   von der Icon-Schrift - deren Chevron säße auf der Textgrundlinie und damit sichtbar zu tief: */
.tmdbCrumbTrail li + li::before {
	border-right: 2px solid #667;
	border-top: 2px solid #667;
	content: "";
	display: inline-block;
	height: 0.35rem;
	margin: 0 0.6rem;
	/* translateY hebt den Trenner auf die optische Mitte der Versalien: zentriert man ihn auf die Zeilenmitte,
	   endet seine Spitze genau auf der Grundlinie und er wirkt dadurch zu tief: */
	transform: translateY(-1px) rotate(45deg);
	width: 0.35rem;
}

.tmdbCrumbTrail a {
	color: #9ac;
	text-decoration: none;
}

.tmdbCrumbTrail a:active {
	color: #fff;
}

/* Poster-Grid, analog .tiles--grid der Listen-Seite, aber mit Platz für ein hochformatiges Poster: */
.tmdbGrid {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
	margin-top: 1rem;
}

.tmdbTile {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	color: #ddd;
	display: flex;
	flex-direction: column;
	position: relative;
}

/* Bewusst kein overflow:hidden auf .tmdbTile (mehr dazu s.u.) - das würde das .moreFlyout-Dropdown der Kachel
   abschneiden, sobald es über den Kachelrand hinausragt. Stattdessen runden Poster/Platzhalter ihre oberen Ecken
   selbst ab (border-radius passend zu .tmdbTile), der Rest der Kachel braucht kein Clipping. */

.tmdbTile:active {
	box-shadow: 0 6px 18px rgba(0,0,0,0.45);
}

.tmdbPosterLink {
	color: inherit;
	display: block;
	text-decoration: none;
}

.tmdbPoster {
	aspect-ratio: 2 / 3;
	background: var(--page-bg);
	border-radius: 8px 8px 0 0;
	display: block;
	object-fit: cover;
	width: 100%;
}

.tmdbPosterPlaceholder {
	align-items: center;
	aspect-ratio: 2 / 3;
	background: var(--page-bg);
	border-radius: 8px 8px 0 0;
	color: var(--text-faint);
	display: flex;
	font-size: 2.6rem;
	justify-content: center;
	width: 100%;
}

.tmdbTileTitle {
	font-size: 0.85rem;
	font-weight: bold;
	margin: 0.5rem 0.5rem 0.2rem 0.5rem;
	overflow-wrap: anywhere;
}

.tmdbTileMeta {
	color: #aaa;
	font-size: 0.78rem;
	margin: 0 0.5rem 0.5rem 0.5rem;
	margin-top: auto;
}

.tmdbBadges {
	display: flex;
	gap: 0.3rem;
	position: absolute;
	right: 0.4rem;
	top: 0.4rem;
}

/* Warnzeichen mittig im Poster, wenn es den Eintrag bei TMDB nicht mehr gibt (siehe inc/tmdbMeta.html#missingMark).
   Der Rahmen deckt genau den Posterbereich ab - gleiche Breite und gleiches Seitenverhältnis wie .tmdbPoster, oben
   angesetzt -, damit das Zeichen im Bild sitzt und nicht in der Mitte der (je nach Inhalt unterschiedlich hohen)
   Kachel. Vollständig durchlässig für den Zeiger: Das Zeichen sitzt genau dort, wo man die Kachel antippt - finge es
   den Klick ab, käme man von der Postermitte aus nicht mehr auf die Detailseite. Die Erklärung trägt daher der
   Poster-Link als title (siehe inc/tmdbMeta.html#missingTitle). */
.tmdbMissingMark {
	align-items: center;
	aspect-ratio: 2 / 3;
	display: flex;
	justify-content: center;
	left: 0;
	pointer-events: none;
	position: absolute;
	right: 0;
	top: 0;
	z-index: 1;
}

/* Dunkle Scheibe unter dem Zeichen, damit es auch auf einem hellen Poster lesbar bleibt (wie bei .tmdbBadge): */
.tmdbMissingMark > i {
	align-items: center;
	background: rgba(17,17,51,0.85);
	border-radius: 50%;
	color: #d44;
	display: flex;
	font-size: 2.4rem;
	height: 3.4rem;
	justify-content: center;
	width: 3.4rem;
}

/* Archiv-Badge (verknüpft/gesammelt) sitzt immer links oben, unabhängig vom Gesehen-Status (der rechts oben bleibt,
   siehe .tmdbBadges) - eigener Container, da beide gleichzeitig sichtbar sein können: */
.tmdbBadgesLeft {
	display: flex;
	gap: 0.3rem;
	left: 0.4rem;
	position: absolute;
	top: 0.4rem;
}

.tmdbBadge {
	align-items: center;
	background: rgba(17,17,51,0.85);
	border-radius: 50%;
	display: flex;
	height: 1.6rem;
	justify-content: center;
	position: relative; /* Bezug für .tmdbBadgeCount */
	width: 1.6rem;
}

/* Anzahl der verknüpften Aufnahmen, wenn es zu einem Film mehrere Fassungen gibt (siehe tmdbmovies.html) - klein in
   der Ecke des Archiv-Icons, damit dieses erkennbar bleibt: */
.tmdbBadgeCount {
	background: #6af;
	border-radius: 50%;
	bottom: -0.15rem;
	color: var(--page-bg);
	font-size: 0.6rem;
	font-weight: bold;
	line-height: 0.85rem;
	min-width: 0.85rem;
	position: absolute;
	right: -0.15rem;
	text-align: center;
}

.tmdbBadge.watched {
	color: #6c6;
}

.tmdbBadge.collected {
	color: #6af;
}

/* Teilweise gesammelt (noch nicht alle ausgestrahlten Episoden als Aufnahme vorhanden) - grau statt blau, siehe
   tmdbseries.html/tmdbseasons.html: */
.tmdbBadge.collected.partial {
	color: #889;
}

/* Teilweise gesehen (noch nicht alle erschienenen Filme/ausgestrahlten Episoden gesehen) - grau statt grün,
   analog zu .tmdbBadge.collected.partial: */
.tmdbBadge.watched.partial {
	color: #889;
}

/* Eine eigene Notiz liegt vor (siehe inc/tmdbMeta.html, NoteDao) - im selben Gelb wie der Notizblock der
   Detailseite (.tmdbNote): */
.tmdbBadge.note {
	color: #dc8;
}

/* Kennzeichen einer Filmreihe in der Filmübersicht, damit sie dort auf einen Blick von einem einzelnen Film
   unterscheidbar ist (siehe tmdbmovies.html): */
.tmdbBadge.collectionMark {
	color: #cae;
}

/* Die Kachel am Ende der Staffel-Übersicht, die zu den nicht aufgehenden Aufnahmen führt (siehe tmdbseasons.html).
   Bewusst unauffälliger als die Staffeln daneben: sie zeigt keinen Inhalt der Serie, sondern nur einen Hinweis. */
.tmdbTile.tmdbTileMuted {
	background: transparent;
	border-style: dashed;
}

/* Das Fragezeichen füllt die Posterfläche fast aus - es steht hier anstelle eines Bildes, nicht als kleines Symbol
   daneben. Die Obergrenze richtet sich nach der schmalsten Kachel (siehe .tmdbGrid), damit es nicht überläuft. */
.tmdbTile.tmdbTileMuted .tmdbPosterPlaceholder {
	background: transparent;
	font-size: 8rem;
}

.tmdbTile.tmdbTileMuted .tmdbTileTitle {
	text-align: center;
}

/* Die Zahlen sollen bündig untereinander stehen, der Block als Ganzes aber mittig unter dem Fragezeichen: deshalb
   die Breite auf den Inhalt schrumpfen und diesen Block zentrieren, statt den Text selbst zu zentrieren. */
.tmdbTile.tmdbTileMuted .tmdbTileMeta {
	margin-left: auto;
	margin-right: auto;
	width: fit-content;
}

.tmdbTile.tmdbTileMuted .tmdbTileMeta span {
	display: block;
}

/* Ein Film einer Filmreihe, der (noch) nicht in der eigenen Sammlung ist - gedämpft, damit die Lücken der Reihe
   sofort erkennbar sind (siehe tmdbcollection.html): */
.tmdbTile.notAdded {
	opacity: 0.55;
}

/* Wie beim Tooltip bewusst :hover statt :active: Auf Touch-Geräten bleibt die Kachel nach dem Antippen hell
   stehen, und erst dann ist "Übernehmen" gut genug zu erkennen, um es zu treffen. Mit :active wäre sie nur
   hell, solange der Finger liegt - man müsste blind auf einen gedämpften Knopf zielen. */
.tmdbTile.notAdded:hover {
	opacity: 1;
}

/* Etwas kleiner und enger gesetzt als die übrigen Kachel-Links: "Übernehmen" ist die längste Beschriftung, die in
   einer Kachelzeile vorkommt, und stünde sonst als einzige nicht mehr neben dem TMDB-Link (siehe .tmdbTileLinks). */
.tmdbAddPartBtn {
	align-items: center;
	background: transparent;
	border: none;
	color: #9ac;
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.75rem;
	gap: 0.125rem;
	margin-left: auto;
	padding: 0;
}

.tmdbAddPartBtn:active:not([disabled]) {
	color: #fff;
}

.tmdbProgress {
	background: var(--page-bg);
	border-radius: 3px;
	height: 0.35rem;
	margin: 0 0.5rem 0.5rem 0.5rem;
	overflow: hidden;
}

/* "Gesehen"-Balken, in Grün passend zum Gesehen-Icon (.tmdbBadge.watched): */
.tmdbProgressFill {
	background: #6c6;
	height: 100%;
}

/* Umhüllung, die nur den Tooltip eines Fortschrittsbalkens trägt (siehe tmdbmovies.html): .tmdbProgress selbst braucht
   overflow:hidden, damit der Füllbalken den runden Ecken folgt - das würde die Tooltip-Blase abschneiden. Der
   Innenabstand vergrößert zugleich die Hover-Fläche des nur 0.35rem hohen Balkens; dafür rückt dessen Abstand hierher,
   sodass die Kachel gleich hoch bleibt. */
.tmdbProgressTip {
	padding: 0.15rem 0;
}

.tmdbProgressTip .tmdbProgress {
	margin-bottom: 0.2rem;
}

/* Balken über dem "gesehen"-Balken: zeigt den Anteil ausgestrahlter Episoden, zu denen eine Aufnahme
   existiert ("gesammelt"), in Blau passend zum Archiv-Icon (.tmdbBadge.collected) - immer sichtbar (auch bei 0%),
   damit alle Kacheln auf einer Höhe bleiben (siehe tmdbseries.html/tmdbseasons.html): */
.tmdbProgressFillCollected {
	background: #6af;
}

.tmdbTileActions {
	align-items: center;
	display: flex;
	gap: 0.4rem;
	justify-content: space-between;
	padding: 0 0.4rem 0.5rem 0.4rem;
}

.tmdbTileActions button {
	align-items: center;
	background: transparent;
	border: none;
	color: #ddd;
	cursor: pointer;
	display: inline-flex;
	font-size: 1.1rem;
	padding: 0.2rem;
}

.tmdbTileActions button:active {
	color: #fff;
}

.tmdbNextEpisodeLabel {
	font-size: 0.75rem;
	margin-left: 0.3rem;
}

/* "Weitere Aktionen"-Menü auf Film-/Serien-Kacheln (bei Filmen in .tmdbTileLinks statt hier, siehe dort), immer an den
   rechten Rand der Zeile gedrückt - funktioniert unabhängig vom umgebenden justify-content: */
.tmdbTileMoreActions {
	margin-left: auto;
}

/* .tmdbPillBtn ist der Alias für "sieht aus wie eine Schaltfläche mit Beschriftung, ist aber keine .defaultBtn"
   (etwa im Such-Dialog). Die Optik selbst kommt aus .defaultBtn, siehe dort. */
.tmdbPillBtn {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.9rem;
	gap: 0.35rem;
	height: var(--control-height);
	justify-content: center;
	padding: 0 0.9rem;
}

.tmdbPillBtn:active:not([disabled]) {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

.tmdbPillBtn i {
	font-size: 1.1rem;
}

/* Im Seitenkopf sitzen die Schaltflächen in einer Flex-Zeile, die den Abstand über gap regelt - der eigene
   Außenabstand von .defaultBtn würde sie gegen den "..."-Button daneben um 2px versetzen: */
.tmdbHeaderActions .defaultBtn {
	margin: 0;
}

/* Das "..."-Menü der Seitenköpfe: rund und so breit wie hoch, wie die Zurück-/Blätter-Buttons. Der Selektor muss
   .actions mitnehmen, weil das umgebende <span class="actions"> ".actions button { background: transparent;
   border: none }" mitbringt und eine einzelne Klassenregel das sonst nicht überstimmt. */
.actions .tmdbBurgerBtn,
.tmdbBurgerBtn {
	align-items: center;
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-size: 1.1rem;
	height: var(--control-height);
	justify-content: center;
	margin: 0;
	padding: 0;
	width: var(--control-height);
}

.actions .tmdbBurgerBtn:active,
.tmdbBurgerBtn:active {
	background-color: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Suche (Dialoge zum Hinzufügen) ------------------------------------------------------------------ */

.tmdbSearchRow {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	margin-bottom: 0.75rem;
}

/* Eingabefeld und Suchen-Button exakt gleich hoch. Die Schaltfläche bringt ihre Höhe inzwischen selbst mit
   (siehe .defaultBtn), das Feld daneben muss nur mitziehen - align-items/align-self: stretch hilft hier nicht,
   ein <button> streckt sich als Flex-Item nicht mit (nachgemessen). */
.tmdbSearchRow input {
	height: var(--control-height);
}

/* min-width: 0 ist zwingend: ein <input> hat als Flex-Item die Vorgabe min-width:auto, also min-content - das
   entspricht der Default-Feldbreite von rund 20 Zeichen. Ohne die Regel schrumpft das Feld trotz flex:1 nicht
   weiter, und auf schmalen Displays schiebt es stattdessen den "Suchen"-Button aus dem Dialog heraus: */
.tmdbSearchRow input {
	flex: 1;
	min-width: 0;
}

/* Der Suchen-Button zeigt hier nur die Lupe. margin: 0 hebt den Standardabstand der Schaltflächen auf - er zählt
   bei align-items:center zur Boxhöhe und würde den Button gegenüber dem Eingabefeld um 2px nach oben versetzen.
   Ein Nur-Icon-Button ist rund, wie überall in der Anwendung: */
.tmdbSearchRow .defaultBtn {
	border-radius: 50%;
	margin: 0;
	padding: 0;
	width: var(--control-height);
}

/*
 * grid-auto-rows/align-content sind nötig, seit der Dialog die volle Fensterhöhe nutzt (siehe .default-dialog-tall):
 * dadurch hat der Grid eine feste Höhe, und mit den Standardwerten (auto-Zeilen + align-content:stretch) richtet sich
 * die Zeilenhöhe nach dem Container statt nach dem Inhalt - die Kacheln wurden dann gestaucht (quadratisches Poster,
 * unten abgeschnitten). max-content bindet die Zeilenhöhe an den Inhalt, start füllt von oben statt zu dehnen.
 */
.tmdbSearchResults {
	align-content: start;
	display: grid;
	gap: 0.75rem;
	grid-auto-rows: max-content;
	grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
	max-height: 60vh;
	overflow-y: auto;
}

.tmdbSearchResult {
	background: var(--surface);
	border-radius: 8px;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	position: relative;
}

.tmdbSearchResultAdded,
.tmdbSearchResultCollection {
	align-items: center;
	background: rgba(17,17,51,0.85);
	border-radius: 50%;
	color: #6c6;
	display: flex;
	height: 1.6rem;
	justify-content: center;
	position: absolute;
	right: 0.4rem;
	top: 0.4rem;
	width: 1.6rem;
}

/* Kennzeichen einer Filmreihe unter den Suchtreffern - links oben, damit es neben dem "bereits in der Sammlung"-Haken
   rechts Platz hat, und lila wie überall im Bereich (siehe .tmdbBadge.collectionMark): */
.tmdbSearchResultCollection {
	color: #cae;
	left: 0.4rem;
	right: auto;
}

/* flex:none, damit das Poster in einer knappen Kachel nie gestaucht wird und sein 2:3-Format behält. Seit das Poster
   in einer Schaltfläche steckt (siehe .tmdbPosterBtn), ist diese das Flex-Kind und braucht es ebenfalls: */
.tmdbSearchResult .tmdbPosterBtn,
.tmdbSearchResult .tmdbPoster,
.tmdbSearchResult .tmdbPosterPlaceholder {
	aspect-ratio: 2 / 3;
	flex: none;
}

.tmdbSearchResultTitle {
	flex: 1;
	font-size: 0.8rem;
	margin: 0.4rem 0.4rem 0.2rem 0.4rem;
	overflow-wrap: anywhere;
}

.tmdbSearchResultBtn {
	margin: 0 0.4rem 0.4rem 0.4rem;
}

/* Zusatzangabe unter dem Titel einer Filmreihen-Trefferkarte ("3/5 in der Sammlung"): */
.tmdbSearchResultMeta {
	color: #aaa;
	font-size: 0.75rem;
	margin: 0 0.4rem 0.3rem 0.4rem;
}

/* Kopfzeile der aufgeklappten Filmreihe im Such-Dialog: Zurück-Button, Name, "Alle übernehmen" rechts. */
.tmdbSearchCollectionBar {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
	margin: 0 0 0.75rem 0;
}

.tmdbSearchCollectionTitle {
	align-items: center;
	color: var(--control-text);
	display: inline-flex;
	font-weight: bold;
	gap: 0.35rem;
	overflow-wrap: anywhere;
}

#tmdbSearchAddAll {
	margin-left: auto;
}

/* Ohne :disabled-Variante: Der "hinzugefügt"-Knopf war früher gesperrt, führt jetzt aber auf die Detailseite in der
   Mediathek (siehe markAsAdded in tmdbCommon.js) und ist damit nie mehr deaktiviert. */
.tmdbSearchResultBtn.added {
	background-color: #1e5631;
	border-color: #1e5631;
	color: #dfffe0;
}

/* Der Knopf sieht wie eine reine Zustandsanzeige aus, ist aber ein Sprungziel. Ohne eigene Hover-Farbe bliebe er
   beim Überfahren völlig stumm - den Mauszeiger bringt .defaultBtn ohnehin mit. */
.tmdbSearchResultBtn.added:hover {
	background-color: #27703f;
	border-color: #27703f;
}

.tmdbSearchResultBtn.added i {
	color: #7ee787;
}

.tmdbSearchResult .tmdbRating {
	font-size: 0.78rem;
	margin: 0 0.4rem 0.3rem 0.4rem;
}

/* Ordner-Scan: Review-Dialog für uneindeutige Treffer ---------------------------------------------- */

/* Kopfzeile des Scan-Ergebnisses: Texte links, "Fertig" rechts daneben statt in einer Fußzeile darunter. Das spart
   die Höhe der Fußzeile für die Trefferliste und hält die Schaltfläche erreichbar, ohne ans Listenende zu scrollen.
   Oben ausgerichtet, damit sie bei mehrzeiligem Text nicht mittig mitwandert. */
.tmdbScanReviewBar {
	align-items: flex-start;
	display: flex;
	gap: 1rem;
	margin-bottom: 0.75rem;
}

.tmdbScanReviewTexts {
	flex: 1;
	min-width: 0;
}

.tmdbScanReviewBar .defaultBtn {
	flex: none;
	margin: 0;
}

.tmdbScanReviewSummary {
	color: #ccc;
	font-weight: bold;
	margin: 0 0 0.25rem 0;
}

/* Den Abstand zur Liste gibt die Leiste vor (siehe .tmdbScanReviewBar), sonst zählte er doppelt. */
.tmdbScanReviewHint {
	color: #aaa;
	font-size: 0.85rem;
	margin: 0;
}

.tmdbScanReviewList {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	max-height: 60vh;
	overflow-y: auto;
}

.tmdbScanReviewItem {
	border-top: 1px solid var(--line-subtle);
	padding-top: 0.75rem;
}

.tmdbScanReviewItemTitle {
	align-items: center;
	display: flex;
	font-weight: bold;
	gap: 0.4rem;
}

.tmdbScanReviewItemInfoBtn {
	background: transparent;
	border: none;
	color: inherit;
	cursor: pointer;
	font-size: 1rem;
	padding: 0;
}

.tmdbScanReviewItemInfoBtn:active {
	color: #fff;
}

.tmdbScanReviewItemDesc {
	color: #ccc;
	font-size: 0.82rem;
	margin-top: 0.15rem;
}

.tmdbScanReviewItemLength {
	color: #aaa;
	font-size: 0.78rem;
	margin-top: 0.15rem;
}

.tmdbScanReviewItemPath {
	color: #889;
	font-size: 0.78rem;
	margin-bottom: 0.5rem;
	margin-top: 0.15rem;
	overflow-wrap: anywhere;
}

.tmdbScanReviewCandidates {
	grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
}

.tmdbScanReviewManualBtn {
	margin-top: 0.5rem;
}

/* Das Poster einer Trefferkarte ist die Schaltfläche fürs Detail-Popup (siehe posterButton in tmdbCommon.js) - die
   Fläche selbst ist der Knopf, deshalb ohne eigene Optik. */
.tmdbPosterBtn {
	background: none;
	border: none;
	cursor: pointer;
	display: block;
	padding: 0;
	width: 100%;
}

/* Bewusst nur das Bild: der Platzhalter daneben zentriert sein Symbol per display:flex (siehe .tmdbPosterPlaceholder,
   bringt auch width:100% schon mit) - ein display:block von hier aus nähme ihm die Zentrierung. */
.tmdbPosterBtn .tmdbPoster {
	display: block;
	width: 100%;
}

.tmdbScanReviewItem.done {
	align-items: center;
	color: #6c6;
	display: flex;
	gap: 0.4rem;
}

/* Detail-Popup hinter dem Poster einer Trefferkarte (siehe showTmdbDetailPopup in tmdbCommon.js) ---

   Breit angelegt, damit Poster und Text nebeneinander Platz haben - aber bewusst nur so hoch wie sein Inhalt statt
   wie .default-dialog-tall stets fensterhoch: bei einem kurzen Eintrag stünde darunter sonst viel Leerraum. Erst bei
   langem Inhalt (Filmreihe mit vielen Filmen) wächst er bis kurz vor den Fensterrand, dann scrollt .tmdbDetailBody.
   Die eigene max-width hebt die schmale Vorgabe von .default-dialog auf (dort min(40rem, 100%)). */
.tmdbDetailDialog {
	display: flex;
	flex-direction: column;
	max-height: calc(100% - 2rem);
	max-width: calc(100% - 2rem);
	width: 64rem;
}

.tmdbDetailDialog .default-dialog-content {
	display: flex;
	flex-direction: column;
	min-height: 0;
	overflow: hidden;
}

/* Poster links, Angaben rechts; gescrollt wird der ganze Block, weil bei einer Filmreihe die Filmliste unter der
   Inhaltsangabe deutlich länger werden kann als das Poster hoch ist. */
.tmdbDetailBody {
	display: flex;
	flex: 1;
	gap: 1.2rem;
	min-height: 0;
	overflow-y: auto;
}

/* align-self, damit das Poster seine Höhe aus dem Bild bezieht statt (als Flex-Kind) auf die Höhe der Textspalte
   gestreckt zu werden - bei einer Filmreihe mit vielen Filmen wäre es sonst arg in die Länge gezogen. sticky hält es
   beim Scrollen dieser langen Liste im Blick. */
.tmdbDetailPoster {
	align-self: flex-start;
	border-radius: 8px;
	flex: none;
	position: sticky;
	top: 0;
	width: 15rem;
}

/* min-width:0, damit lange Wörter der Inhaltsangabe die Spalte nicht aufziehen statt umzubrechen: */
.tmdbDetailInfo {
	min-width: 0;
}

/* Gleichmäßiger Abstand zwischen allen Blöcken der Textspalte (Meta-Zeile, Genres, Tagline, Regie, Inhaltsangabe,
   Filmliste). Die Bausteine bringen von den Detailseiten teils gar keinen eigenen Abstand mit (die Meta-Zeile) und
   teils nur einen knappen - dort verteilen sie sich über die ganze Seitenbreite, hier stehen sie eng untereinander
   und klebten sonst aneinander. Der Abstand wird deshalb einheitlich hier gesetzt: oben statt unten, damit unter dem
   letzten Block kein Rest bleibt.
   Bewusst mit zwei Klassen, um die Vorgaben der Bausteine zu überstimmen - .tmdbOverview & Co. stehen weiter unten in
   dieser Datei und gewännen bei gleicher Spezifität. */
.tmdbDetailBody .tmdbDetailInfo > * {
	margin-bottom: 0;
	margin-top: 0.9rem;
}

.tmdbDetailBody .tmdbDetailInfo > :first-child {
	margin-top: 0;
}

.tmdbDetailMeta {
	gap: 0.5rem;
}

/* Trennpunkt zwischen den Angaben der Meta-Zeile - als eigenes Element, damit er beim Umbruch nicht am Zeilenanfang
   landet und mit dem gap der Zeile mitgeht: */
.tmdbDetailSep {
	color: #789;
}

.tmdbDetailCredit {
	color: #bbb;
}

/* Die Filme einer Filmreihe: sie treten an die Stelle der Angaben, die TMDB auf Reihen-Ebene nicht kennt. */
.tmdbDetailParts {
	list-style: none;
	padding: 0;
}

.tmdbDetailParts li {
	border-top: 1px solid var(--line-subtle);
	padding: 0.35rem 0;
}

.tmdbDetailPartYear {
	color: #9ab;
}

/* Auf schmalen Bildschirmen (Handy) übereinander, sonst bliebe für den Text neben dem Poster zu wenig übrig: */
@media (max-width: 640px) {
	.tmdbDetailBody {
		flex-direction: column;
	}

	/* Übereinander ist ein mitscrollendes Poster richtig - festgeheftet verdeckte es sonst den Text darunter: */
	.tmdbDetailPoster {
		align-self: center;
		position: static;
		width: min(60%, 12rem);
	}
}

/* Verknüpfen-Dialog (Suche über bestehende Aufnahmen bzw. Verzeichnisse) -------------------------- */

.tmdbLinkResults {
	max-height: 50vh;
	overflow-y: auto;
}

.tmdbLinkResult {
	border-bottom: 1px solid var(--line-subtle);
	cursor: pointer;
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	padding: 0.5rem 0.2rem;
}

.tmdbLinkResult:active {
	background: var(--surface);
}

/* Deutlich abgesetzte Auswahl: der frühere Hintergrund lag nur einen Blauwert neben dem des Dialogs und war
   praktisch nicht zu erkennen. Die Auswahl trägt deshalb dieselbe Füllung wie ein aktives Segment; die
   Zusatzzeilen werden mit aufgehellt, da ihr Grau auf dem helleren Untergrund abfiele: */
.tmdbLinkResult.active {
	background: var(--control-bg-hover);
	color: var(--control-text-hover);
}

.tmdbLinkResult.active .tmdbLinkResultDesc,
.tmdbLinkResult.active .tmdbLinkResultPath {
	color: #dde;
}

.tmdbLinkResultDesc {
	color: #99a;
	display: block;
	font-size: 0.78rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.tmdbLinkResultPath {
	color: #778;
	display: block;
	font-size: 0.72rem;
	overflow-wrap: anywhere;
}

/* Verknüpfen-Dialog: "Ausgewählt"-Info + Radiobuttons stehen untereinander statt nebeneinander zu kleben ----- */

.tmdbLinkWinnerGroup {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.tmdbLinkSelectedInfo {
	margin: 0;
}

.tmdbLinkWinnerOption {
	align-items: center;
	display: flex;
	gap: 0.4rem;
}

/* Staffel/Episoden-Detailseiten ------------------------------------------------------------------- */

.tmdbOverview {
	color: #ccc;
	line-height: 1.6;
	margin: 0 0 1rem 0;
	max-width: 90rem;
}

/*
 * Inhaltsangabe und eigene Notiz (siehe inc/tmdbMeta.html#overviewWithNote): Ist daneben genug Platz, steht die Notiz
 * als Zettel rechts neben dem Text und bekommt dort ihre gelbe Kopfzeile; sonst steht sie schlicht darunter.
 *
 * Gemessen wird der vorhandene Platz, nicht die Fensterbreite (@container statt @media): Wie breit die Inhaltsangabe
 * ist, hängt nicht am Fenster, sondern an der Seite - auf der Filmdetailseite steht sie neben dem Poster, auf der
 * Serien- und Filmreihenseite über die volle Breite.
 *
 * Bewusst eine Container-Abfrage statt eines Umbruchs per flex-wrap: Der Umbruchpunkt von flex-wrap hängt auch an der
 * Textlänge der Notiz und ist damit nicht abfragbar - die Kopfzeile erschiene dann in einem schmalen Bereich, obwohl
 * der Kasten längst unter der Inhaltsangabe steht.
 */
/* Hält das umflossene Poster der Serie auf dem Handy innerhalb der Zeile, wenn der Text kürzer ist als das Poster
   hoch. Ohne eigenes Poster bleibt die Zeile ein gewöhnlicher Block: Sonst stünde sie als Ganzes neben dem Poster ab
   der Titelzeile (Staffel, Filmreihe), und langer Text liefe unter diesem in einer schmalen Spalte weiter. */
.tmdbOverviewRow.hasPoster {
	display: flow-root;
}

/* Gemessen wird .tmdbOverviewBody, nicht die ganze Zeile: Steht rechts ein Poster, ist das die Breite ohne dieses.
   Erst ab 641px ein Container - aus demselben Grund wie oben (ein Container ist ein eigener Formatierungskontext und
   würde nicht umflossen), und auf dem Handy wird er ohnehin nie die 46rem breit, ab denen der Zettel daneben steht. */
@media (min-width: 641px) {
	.tmdbOverviewBody {
		container: tmdbOverview / inline-size;
	}
}

/*
 * Das Poster der Serie auf dem Handy (siehe inc/tmdbMeta.html#overviewWithNote): klein am rechten Rand,
 * damit die Staffelkacheln bzw. Folgen der Blickfang der Seite bleiben - bewusst nicht wie das 13rem breite Filmposter.
 *
 * Text und Notiz umfließen das Poster - deshalb ist .tmdbOverviewBody auf dem Handy kein Container (siehe oben).
 */

.tmdbOverviewPoster {
	aspect-ratio: 2 / 3;
	background: var(--page-bg);
	border-radius: 6px;
	float: right;
	margin: 0.2rem 0 1rem 1.2rem;
	object-fit: cover;
	width: 5.5rem;
}

/* Außer auf dem Handy steht das Poster schon ab der Titelzeile (siehe inc/tmdbMeta.html#headerPoster) und das in der
   Zeile der Inhaltsangabe entfällt. Die Schwelle ist die übliche Handy-Grenze dieser Datei (640px): Auf dem Tablet
   hochkant hinterließ das Poster neben der Inhaltsangabe dieselbe Lücke wie breit. .tmdbOverviewBody steht dann als
   Container (eigener Formatierungskontext) neben dem Poster und misst die Breite ohne dieses.

   Staffel- und Filmreihenseite zeigen es auch auf dem Handy ab dem Titel (Entscheidung des Nutzers, 26.09.2026):
   Beide haben oft keine oder nur eine kurze Inhaltsangabe, das Poster stünde dort meist allein in einer Zeile. Neben ihm stehen
   nur Titel und drei Kennzahlen. Die Serienseite bleibt beim Umfließen - ihre Kennzahlen, Genres und Knöpfe sind
   länger, und ihre Inhaltsangabe fehlt selten.

   Kacheln und Folgen beginnen in jedem Fall unter dem Poster: Als Raster bzw. Liste stünden sie sonst verschmälert
   daneben. */
.tmdbHeaderPoster {
	aspect-ratio: 2 / 3;
	background: var(--page-bg);
	border-radius: 6px;
	display: none;
	float: right;
	margin: 0 0 1rem 1.2rem;
	object-fit: cover;
	width: 5.5rem;
}

#tmdbEpisodesPage .tmdbHeaderPoster,
#tmdbCollectionPage .tmdbHeaderPoster {
	display: block;
}

.tmdbHeaderPoster ~ .tmdbGrid,
.tmdbHeaderPoster ~ .tmdbEpisodeList {
	clear: right;
}

@media (min-width: 641px) {
	.tmdbHeaderPoster {
		display: block;
		margin-left: 1.4rem;
		width: 7rem;
	}

	.tmdbOverviewRow.hasPoster > .tmdbOverviewPoster {
		display: none;
	}
}

/* Block statt Flex-Spalte: Eine Flex-Box ist ein eigener Formatierungskontext und würde das Poster nicht umfließen.
   Die Notiz bleibt trotzdem so breit wie ihr Inhalt (width: fit-content an .tmdbNote). */
.tmdbOverviewRowInner {
	display: block;
}

/* 46rem = Inhaltsangabe (mind. ~23rem) + Abstand + Notiz (höchstens 22rem): darunter bliebe für den Text zu wenig. */
@container tmdbOverview (min-width: 46rem) {
	.tmdbOverviewRowInner {
		align-items: flex-start;
		display: flex;
		flex-direction: row;
		gap: 0 1.4rem;
	}

	/* Feste Basis statt "auto": Mit auto wäre die Basis die Breite des Textes in einer einzigen Zeile, die Zeile also
	   weit überfüllt - beide Spalten würden dann anteilig geschrumpft und die Notiz landete auf Wortbreite. */
	.tmdbOverviewRowInner .tmdbOverview {
		flex: 1 1 24rem;
		min-width: 0;
	}

	/* Schmaler als der Kasten für sich allein (50rem): Neben dem Fließtext soll er ein Zettel bleiben und nicht die
	   halbe Zeile einnehmen. width: fit-content aus .tmdbNote gilt weiter - kurze Notizen bleiben kurz. */
	.tmdbOverviewRowInner .tmdbNote {
		/* Nicht schrumpfen: Der Zettel behält die Breite seines Inhalts, Platz gibt die Textspalte ab. */
		flex: 0 0 auto;
		max-width: min(22rem, 100%);
	}

	/* Zettel-Optik: Kopfzeile über dem Text statt Zeichen daneben. Der linke Balken entfällt dabei - die
	   Kennzeichnung trägt jetzt die Kopfzeile, beides zusammen wäre doppelt gemoppelt. */
	.tmdbOverviewRowInner .tmdbNote {
		border-left-width: 1px;
		display: block;
		/* Damit die Kopfzeile die abgerundeten Ecken des Kastens nicht überzeichnet: */
		overflow: hidden;
		padding: 0;
	}

	/* Alle Regeln hier laufen über .tmdbNote, um die Grundregeln zu überstimmen: Eine Container-Abfrage erhöht die
	   Spezifität nicht, und die Grundregeln stehen weiter unten in dieser Datei - bei Gleichstand gewännen sie. */
	.tmdbOverviewRowInner .tmdbNote > .tmdbNoteHeader {
		align-items: center;
		background: #dc8;
		/* Dunkel auf Gelb - das sonst gelbe Zeichen wäre auf der eigenen Farbe unsichtbar: */
		color: var(--surface-dialog);
		display: flex;
		/* Ausdrücklich auf Notiztextgröße: Ohne die Angabe erbte die Aufschrift die 1,5rem der Grundregel, die dort
		   nur das allein stehende Zeichen groß macht. */
		font-size: 0.9rem;
		font-weight: 700;
		gap: 0.4rem;
		/* Etwas weiter gesperrt als zuvor: Versalien stehen sonst zu gedrängt. */
		letter-spacing: 0.06em;
		/* Ohne die geerbte Zeilenhöhe von 1,55: Sie bläht den Kasten der Aufschrift auf, was das senkrechte
		   Ausrichten gegen das Zeichen daneben verfälscht. */
		line-height: 1;
		margin: 0;
		/* Oben etwas mehr, unten entsprechend weniger: Das rückt Aufschrift und Zeichen gemeinsam um rund 1,5px nach
		   unten, wo sie optisch mittig sitzen, und lässt die Höhe der Zeile unverändert. Versalien brauchen das, weil
		   sie den Raum der Unterlängen nicht ausfüllen und dadurch zu hoch wirken. */
		padding: 0.4rem 0.7rem 0.2rem;
		text-transform: uppercase;
	}

	/* Nur eine Winzigkeit größer als die Schrift daneben: Zeichen wirken bei gleicher Größe optisch kleiner als
	   Buchstaben. Deutlich größer wäre falsch - die Kopfzeile soll den Kasten anschreiben, nicht ihn beherrschen. */
	/* Das Zeichen steht rechts außen, die Aufschrift links - wie die Schaltflächen in den Dialog-Kopfzeilen.
	   order statt umgestellter Auszeichnung, damit der schmale Zustand unverändert mit dem Zeichen beginnt. */
	.tmdbOverviewRowInner .tmdbNote > .tmdbNoteHeader > .tmdbNoteEditBtn {
		font-size: 1.1rem;
		margin-left: auto;
		margin-top: 0;
		order: 1;
	}

	/* Die Kette bis .tmdbNote ist nötig, um die Ausblendung des Wortes im Grundzustand zu überstimmen - eine
	   Container-Abfrage erhöht die Spezifität nicht. */
	.tmdbOverviewRowInner .tmdbNote > .tmdbNoteHeader > span {
		display: inline;
	}

	.tmdbOverviewRowInner .tmdbNote > .tmdbNoteText {
		display: block;
		padding: 0.6rem 0.8rem;
	}
}

/* Die eigene Notiz einer Detailseite (siehe inc/tmdbMeta.html#note). Abgesetzt von der Inhaltsangabe darüber, damit
   erkennbar bleibt, dass der Text nicht von TMDB stammt; pre-wrap erhält die eingegebenen Zeilenumbrüche. */
.tmdbNote {
	/* Getönte Fläche mit Rahmen wie beim .tmdbMissingNotice, nur in Gelb: Ein bloßer Randstrich reichte nicht - die
	   Notiz stand direkt unter der Inhaltsangabe und sah aus wie ein weiterer Absatz davon. */
	background: rgba(221,204,136,0.10);
	border: 1px solid rgba(221,204,136,0.45);
	/* Kräftiger an der Seite, das gibt dem Kasten die Anmutung eines angehefteten Zettels: */
	border-left-width: 4px;
	border-radius: 6px;
	color: var(--text);
	display: flex;
	gap: 0.8rem;
	line-height: 1.55;
	margin: 0 0 1rem 0;
	padding: 0.7rem 0.9rem;
	/* Nur so breit wie ihr Inhalt: Eine Notiz ist meist ein Satz, über die volle Spaltenbreite gezogen bestand der
	   Kasten überwiegend aus Leerraum. Längerer Text bricht an der Maximalbreite um. */
	max-width: min(50rem, 100%);
	width: fit-content;
}

/* Steht die Notiz unter der Inhaltsangabe, schrumpft die Kopfzeile auf ihr Zeichen zusammen: Ein Balken mit der
   Aufschrift "Notiz" wäre über einem einzeiligen Satz mehr Rahmen als Inhalt (die Zettel-Optik daneben steht im
   @container-Block weiter oben). */
.tmdbNote > .tmdbNoteHeader {
	color: #dc8;
	flex-shrink: 0;
	font-size: 1.5rem;
	line-height: 1;
	/* Auf die erste Textzeile ausgerichtet, nicht auf die Mitte eines mehrzeiligen Blocks: */
	margin-top: 0.1rem;
}

.tmdbNote > .tmdbNoteHeader > span {
	display: none;
}

/* Das Zeichen ist zugleich die Schaltfläche zum Bearbeiten. Flächenlos wie in der Seiten-Kopfzeile (.iconBtn), und
   Farbe wie Größe geerbt, damit es in beiden Zuständen genauso aussieht wie zuvor das reine Zeichen. */
.tmdbNoteEditBtn {
	color: inherit;
	font-size: inherit;
	line-height: 1;
	padding: 0;
}

/* Die eingegebenen Zeilenumbrüche bleiben erhalten - am Text selbst, nicht am Kasten, damit die Auszeichnung nicht
   auch für den Abstand zwischen Zeichen und Text gilt: */
.tmdbNoteText {
	white-space: pre-wrap;
}

/* Film-Detailseite -------------------------------------------------------------------------------- */

/* Der eigene Abstand nach oben sorgt dafür, dass der Poster-Block immer gleich weit vom Vorhergehenden absteht -
   egal ob darüber der Titel, der Originaltitel oder die Tagline endet. Diese bringen unterschiedlich große untere
   Abstände mit (die Überschrift rund 20px, die Tagline nur 8), und da benachbarte Abstände verschmelzen statt sich
   zu addieren, gewinnt immer der größere von beiden. Auf der Serien-Detailseite übernimmt das die .infoBar. */
.tmdbMovieDetailHero {
	align-items: flex-start;
	display: flex;
	flex-wrap: wrap;
	gap: 1.2rem;
	margin-top: 1.25rem;
}

/* Anders als in der Kachel steht das Poster hier fest neben dem Text, statt die volle Breite zu füllen. Die Umhüllung
   trägt die Breite und ist zugleich der Bezugspunkt für die Kennzeichen (.tmdbBadges/.tmdbBadgesLeft sind absolut
   positioniert): */
.tmdbMovieDetailPoster {
	flex: none;
	position: relative;
	width: 13rem;
}

.tmdbMovieDetailHero .tmdbPoster,
.tmdbMovieDetailHero .tmdbPosterPlaceholder {
	border-radius: 8px;
	width: 100%;
}

.tmdbMovieDetailInfo {
	flex: 1 1 20rem;
}

/* Ohne diese Korrektur klafft hier eine Lücke zum Posterrand, weil .infoBar sonst überall einen eigenen
   Abstand nach oben zum vorangehenden Element mitbringt - hier ist es aber das erste Element der Spalte: */
.tmdbMovieDetailInfo .infoBar {
	margin-top: 0;
}

/* Je verknüpfter Aufnahme eine Schaltfläche mit ihrer Bezeichnung ("21:9, o. Nachspann"). Bewusst kompakt als Chips
   nebeneinander statt als Karten untereinander: mehrere Fassungen desselben Films sind der Sonderfall und sollen die
   Seite nicht dominieren. */
.tmdbRecordingChips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
}

.tmdbRecordingChip {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 999px;
	color: var(--control-text);
	display: inline-flex;
	font-family: inherit;
	gap: 0.2rem;
	padding: 0.15rem 0.3rem 0.15rem 0.8rem;
}

.tmdbRecordingChip:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
}

.tmdbRecordingChip .playMovie,
.tmdbRecordingChip .tmdbRecordingMissing {
	align-items: center;
	background: transparent;
	border: none;
	color: inherit;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.82rem;
	gap: 0.35rem;
	padding: 0.3rem 0;
}

.tmdbRecordingChip .playMovie {
	cursor: pointer;
}

/* Trennlinie zwischen dem Abspielen-Teil und dem "..."-Menü, wie bei einer zweigeteilten Schaltfläche üblich. In der
   Rahmenfarbe des Chips, damit kein zweiter Blauton entsteht.
   Die beiden Abstände sind bewusst ungleich notiert, damit die Linie optisch mittig steht: rechts kommt zum Polster
   noch das Innenpolster des "..."-Buttons (0,1rem, siehe .actions.actionsSmall button) und die Luft hinzu, die das
   Punkte-Symbol in seiner em-Box lässt (bei 1,2rem gut 3px) - links dagegen nur der Chip-Abstand (gap 0,2rem), denn
   der Text steht bündig an seiner Kante. Nachgemessen ergibt das rund 7px auf jeder Seite. */
.tmdbRecordingChip .actions {
	border-left: 1px solid var(--control-border);
	margin-left: 0.25rem;
	padding-left: 0.15rem;
}

/* Der mittlere Teil des dreigeteilten Chips: die Aufnahme-Infos als reines Symbol zwischen "Abspielen" und dem
   "..."-Menü (siehe tmdbmoviedetail.html). Trennlinie und Abstände wie beim Menü daneben, damit beide Fugen
   gleich aussehen; die Symbolgröße ist die des Punkte-Symbols, sonst stünde in der Mitte ein kleineres Zeichen
   zwischen zwei größeren. */
.tmdbRecordingChip .tmdbRecordingChipInfo {
	align-items: center;
	background: transparent;
	border: none;
	border-left: 1px solid var(--control-border);
	color: inherit;
	cursor: pointer;
	display: inline-flex;
	/* line-height und das knappe senkrechte Polster halten den Knopf auf der Höhe seiner Nachbarn: Das Symbol ist
	   mit 1,2rem größer als die Chip-Schrift, und mit dem Polster der beiden Nachbarn wäre der Knopf 29 statt 24px
	   hoch geworden - genug, um den ganzen Chip aufzudehnen und ihn neben einem Chip ohne Info-Knopf (Aufnahme
	   fehlt) sichtbar höher stehen zu lassen. Nachgemessen. */
	line-height: 1;
	margin-left: 0.25rem;
	padding: 0.15rem 0.15rem 0.15rem 0.3rem;
}

.tmdbRecordingChip .tmdbRecordingChipInfo i {
	font-size: 1.2rem;
}

.tmdbRecordingChip .tmdbRecordingChipInfo:active {
	color: #fff;
}

.tmdbRecordingChip:active .actions,
.tmdbRecordingChip:active .tmdbRecordingChipInfo {
	border-left-color: var(--control-border-hover);
}

.tmdbRecordingChip .playMovie:active {
	color: #fff;
}

/* Verwaiste Verknüpfung: die Datei ist nicht mehr da, lösen lässt sie sich über das Menü des Chips trotzdem. */
.tmdbRecordingMissing {
	color: #c88;
}

.tmdbRecordingChip.addChip {
	background: transparent;
	border-style: dashed;
	cursor: pointer;
	font-size: 0.82rem;
	gap: 0.35rem;
	padding: 0.45rem 0.9rem;
}

.tmdbRecordingChip.addChip:disabled {
	cursor: default;
	opacity: 0.5;
}

/* Die technischen Daten der Aufnahmen (siehe inc/tmdbMeta.html#techPills) - eine Zeile je Aufnahme unterhalb der
   Chips.
   Ein Raster statt einzelner Flex-Zeilen, damit die Pillen aller Fassungen bündig untereinander beginnen: Die
   Bezeichnungen sind unterschiedlich lang ("21:9, o. Nachspann" gegen "16:9, Vollbild"), und je Zeile für sich
   ausgerichtet fingen die Pillen jeder Zeile woanders an. Die erste Spalte wächst mit der längsten Bezeichnung. */
/* Oben ausgerichtet statt mittig: Auf schmalen Bildschirmen bricht die Pillenreihe auf mehrere Zeilen um, und die
   Bezeichnung stünde dann mittig neben dem ganzen Block statt neben ihrer ersten Zeile. Dass sie bei einzeiligen
   Reihen trotzdem exakt auf Pillenhöhe sitzt, besorgt die line-height der Bezeichnung. */
.tmdbTechRows {
	align-items: start;
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 0.35rem 0.6rem;
}

/* Ist keine der Aufnahmen analysiert, bleibt das Raster leer - dann soll es auch keinen Abstand aufspannen. */
.tmdbTechRows:has(.tmdbTechPill) {
	margin-top: 1.1rem;
}

/* Die Zeile selbst ist nur eine Klammer: ihre beiden Kinder sollen unmittelbar im Raster oben liegen, damit sie
   sich an dessen Spalten ausrichten. */
.tmdbTechRow {
	display: contents;
}

/* Nur bei mehreren Fassungen/Teilen vorhanden: sagt, zu welcher Aufnahme die Pillen daneben gehören.
   Die line-height entspricht der Pillenhöhe, damit die Bezeichnung mit der ersten Pillenzeile fluchtet - siehe
   align-items:start am Raster. */
.tmdbTechRowLabel {
	color: #8fa3c0;
	font-size: 0.75rem;
	line-height: var(--control-height-small);
}

.tmdbTechPills {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}

/* Die Formensprache der Anwendung statt der alten eckigen Tag-Pille: rund wie jedes andere beschriftete Element
   (--control-radius) und auf der Höhe der kompakten Bedienelemente, damit die Reihe zu den Chips darüber passt.
   Gefüllt wird nur angedeutet - es sind Angaben, keine Schaltflächen, sie sollen die Aufnahme-Chips nicht
   überstrahlen. Die feine Linie stammt aus derselben Familie wie die Kachelrahmen (--line-subtle). */
.tmdbTechPill {
	align-items: center;
	background: rgba(102, 153, 221, 0.09);
	border: 1px solid var(--line-subtle);
	border-radius: var(--control-radius);
	color: #c4d2e6;
	display: inline-flex;
	font-size: 0.8rem;
	gap: 0.35rem;
	height: var(--control-height-small);
	padding: 0 0.7rem;
	white-space: nowrap;
}

/* Die Symbole tragen die Bedeutung ("was für eine Angabe ist das?"), der Text den Wert - deshalb dürfen sie
   etwas kräftiger sein als die Schrift daneben, ohne sie zu übertönen. */
.tmdbTechPill i {
	color: #8fb4e8;
	font-size: 1rem;
}

/* HDR ist die einzige Angabe, die eine Aufnahme wirklich heraushebt - der Rest ist Beschreibung. */
.tmdbTechPill.hdr {
	background: rgba(240, 190, 90, 0.14);
	border-color: rgba(240, 190, 90, 0.45);
	color: #f0d68a;
}

.tmdbTechPill.hdr i {
	color: #f0c860;
}

/* Ton- und Untertitel-Pille klappen weitere Spuren auf und sind damit echte Bedienelemente: Sie bekommen die
   volle Fläche und den kräftigen Rahmen der Bedienelemente, damit man ihnen ansieht, dass sich etwas tut.
   Der Selektor muss ".actions" enthalten, sonst nähme ihnen die allgemeine Regel ".actions button"
   (transparent, randlos) die Fläche wieder weg - dieselbe Begründung wie bei .sortPill.
   Aus demselben Grund steht hier das Innenpolster nochmals: ".actions button" setzt 0.25rem und ist mit seinen
   zwei Bestandteilen spezifischer als ".tmdbTechPill". Ohne diese Zeile fiele die anklickbare Pille schmaler
   aus als ihre Nachbarn, und ihr Symbol stünde nicht mehr unter dem der Zeile darüber. */
.actions .tmdbTechPillBtn {
	background: var(--control-bg);
	/* Vollständig notiert statt nur border-color: ".actions button" setzt "border: none" und ist spezifischer als
	   ".tmdbTechPill" - eine bloße Farbangabe liefe daher ins Leere. Der Rahmen fehlte dann nicht nur optisch, die
	   Pille wäre auch 1px schmaler als ihre Nachbarn und ihr Symbol stünde einen Punkt versetzt. */
	border: 1px solid var(--control-border);
	color: var(--control-text);
	cursor: pointer;
	font-family: inherit;
	padding: 0 0.7rem;
}

.actions .tmdbTechPillBtn:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Ebenfalls gegen ".actions button i" (1.2rem): Anklickbar oder nicht ändert nichts an der Bedeutung des
   Symbols, es soll in beiden Fällen gleich groß sein. */
.actions .tmdbTechPillBtn i {
	font-size: 1rem;
}

/* Der Pfeil steht für "hier ist mehr" und tritt deshalb hinter der Angabe selbst zurück. */
.actions .tmdbTechPillBtn .tmdbTechPillCaret {
	font-size: 0.8rem;
	opacity: 0.7;
}

/* Das Flyout listet reinen Text statt Schaltflächen - die Menü-Regeln von ".actions .moreFlyout button, ... a"
   greifen hier also nicht, Abstände und Größe stehen deshalb hier.
   Die Höhenbegrenzung ist nicht theoretisch: Eine MKV des Bestands führt 27 Untertitelspuren, deren Liste
   nachgemessen 571px hoch wurde und damit unten aus dem Fenster ragte (auf dem Handy entsprechend mehr). Ab dieser
   Grenze wird im Flyout gescrollt, statt dass die letzten Einträge unerreichbar sind. */
.tmdbTechFlyout {
	max-height: min(60vh, 22rem);
	max-width: 20rem;
	overflow-y: auto;
	padding: 0.5em 0.7em;
}

.tmdbTechFlyoutItem {
	font-size: 0.85rem;
	padding: 0.15em 0;
	white-space: nowrap;
}

/* Nur beim Ton: dort steht die Hauptspur bereits in der Pille, ohne Überschrift wirkte die Liste sonst wie die
   vollständige Aufzählung. Bei den Untertiteln steht ohnehin alles darin, da wäre sie nur Ballast. */
.tmdbTechFlyoutTitle {
	color: #8fa3c0;
	font-size: 0.72rem;
	letter-spacing: 0.02em;
	padding-bottom: 0.25em;
	text-transform: uppercase;
}

/* Staffel/Episoden-Detailseiten (Fortsetzung) ------------------------------------------------------ */

.tmdbEpisodeList {
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	margin-top: 1rem;
}

/* Bewusst kein overflow:hidden hier (analog .tmdbTile, siehe dort) - das würde das .moreFlyout-Dropdown der Karte
   abschneiden, sobald es über den Kartenrand hinausragt. Stattdessen rundet .tmdbEpisodeStillWrap seine Ecken selbst ab. */
.tmdbEpisodeCard {
	align-items: flex-start;
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	color: #ddd;
	display: flex;
}

.tmdbEpisodeCard:active {
	box-shadow: 0 6px 18px rgba(0,0,0,0.45);
}

/* Per Anker angesprungene Karte (siehe movielist.html) optisch hervorheben: */
.tmdbEpisodeCard:target {
	border-color: #6af;
}

.tmdbEpisodeStillWrap {
	background: var(--page-bg);
	border-radius: 8px 0 0 8px;
	flex: 0 0 18rem;
	height: 10.125rem;
	overflow: hidden;
	position: relative;
	width: 18rem;
}

/* Das Bild füllt die Umhüllung, und der Verweis dazwischen (siehe inc/tmdbEpisodeCard.html) muss die Höhe
   durchreichen - sonst bezöge sich das height:100% des Bildes auf einen in sich zusammengefallenen Kasten: */
.tmdbEpisodeStillLink {
	display: block;
	height: 100%;
}

.tmdbEpisodeStill,
.tmdbEpisodeStillPlaceholder {
	height: 100%;
	width: 100%;
}

.tmdbEpisodeStill {
	display: block;
	object-fit: cover;
}

.tmdbZoomable {
	cursor: zoom-in;
}

.tmdbEpisodeStillPlaceholder {
	align-items: center;
	color: var(--text-faint);
	display: flex;
	font-size: 2rem;
	justify-content: center;
}

/* Folgen-Detailseite: das Bild steht wie das Poster der Filmdetailseite fest links neben den Angaben (deshalb auch
   deren .tmdbMovieDetailHero/.tmdbMovieDetailInfo, siehe .tmdbPersonPhoto), aber im 16:9-Seitenverhältnis des
   Folgenbilds statt im Poster-Format - height:100% aus .tmdbEpisodeStill/-Placeholder griffe hier ins Leere, da
   anders als bei der Kachel keine feste Höhe vorgegeben ist. */
.tmdbEpisodeDetailStill {
	flex: none;
	position: relative;
	width: 20rem;
}

.tmdbEpisodeDetailStill .tmdbEpisodeStill,
.tmdbEpisodeDetailStill .tmdbEpisodeStillPlaceholder {
	aspect-ratio: 16 / 9;
	border-radius: 8px;
	height: auto;
}

.tmdbEpisodeInfo {
	display: flex;
	flex: 1;
	flex-direction: column;
	gap: 0.4rem;
	min-width: 0;
	padding: 0.6rem 0.8rem;
}

.tmdbEpisodeInfoTop {
	align-items: baseline;
	display: flex;
	gap: 0.5rem;
}

.tmdbEpisodeLabel {
	color: #9ac;
	flex: 0 0 auto;
	font-size: 0.85rem;
	font-weight: bold;
}

/* In der Detail-Überschrift wächst die Nummer mit der übrigen Schrift mit, statt wie in der Folgenkachel klein
   danebenzustehen: */
.tmdbDetailTitle .tmdbEpisodeLabel {
	font-size: inherit;
}

.tmdbEpisodeTitle {
	flex: 1;
	font-weight: bold;
	overflow-wrap: anywhere;
}

.tmdbEpisodeInfoTop .tmdbToggleWatchedBtn,
.tmdbEpisodeInfoTop .tmdbEpisodeDetailsBtn,
.tmdbEpisodeInfoTop .actions {
	flex: 0 0 auto;
	text-decoration: none;
}

/* Nur das erste der drei schiebt die Gruppe nach rechts - :first-of-type griffe hier nicht, die drei sind
   button, a und span. */
.tmdbEpisodeInfoTop .tmdbToggleWatchedBtn {
	margin-left: auto;
}

.tmdbEpisodeInfoTop .tmdbToggleWatchedBtn + .tmdbEpisodeDetailsBtn,
.tmdbEpisodeInfoTop .tmdbEpisodeDetailsBtn:first-child {
	margin-left: 0;
}

.tmdbEpisodeInfoTop .tmdbEpisodeDetailsBtn:not(.tmdbToggleWatchedBtn + *) {
	margin-left: auto;
}

/* Serienweite Folgensuche (siehe tmdbEpisodeSearch.js) ------------------------------------------
 *
 * Eigene, kompaktere Kachel statt .tmdbEpisodeCard: hier zählen viele Treffer auf einen Blick, nicht die
 * Detailangaben einer einzelnen Folge. Der Serienname fehlt bewusst - gesucht wird immer innerhalb einer Serie.
 */
.tmdbEpisodeSearchRow {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	margin-bottom: 0.75rem;
}

.tmdbEpisodeSearchRow .dialogInput {
	flex: 1;
	min-width: 0;
}

.tmdbEpisodeSearchResults {
	align-content: start;
	display: grid;
	gap: 0.6rem;
	grid-auto-rows: max-content;
	grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
	min-height: 0;
	overflow-y: auto;
}

.tmdbEpisodeSearchHit {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: 8px;
	color: #ddd;
	display: flex;
	overflow: hidden;
	text-decoration: none;
}

.tmdbEpisodeSearchHit:active {
	border-color: #9ac;
}

.tmdbEpisodeSearchStillWrap {
	background: var(--page-bg);
	flex: 0 0 7.5rem;
	height: 4.22rem;
	position: relative;
	width: 7.5rem;
}

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

.tmdbEpisodeSearchInfo {
	display: flex;
	flex: 1;
	flex-direction: column;
	gap: 0.25rem;
	min-width: 0;
	padding: 0.4rem 0.6rem;
}

.tmdbEpisodeSearchTitle {
	display: flex;
	font-weight: bold;
	gap: 0.4rem;
}

.tmdbEpisodeSearchName {
	min-width: 0;
	overflow-wrap: anywhere;
}

.tmdbEpisodeSearchSnippet {
	color: #aaa;
	font-size: 0.8rem;
	margin: 0;
	overflow-wrap: anywhere;
}

/* Der Treffer wird über <strong> hervorgehoben (siehe highlight() in tmdbEpisodeSearch.js) - hier zusätzlich
   farblich, damit er im gedämpften Ausschnittstext auch wirklich ins Auge springt: */
.tmdbEpisodeSearchSnippet strong,
.tmdbEpisodeSearchTitle strong {
	color: #fff;
}

.tmdbEpisodeSearchTags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem;
}

/* Tag-Pille der verknüpften Aufnahmen - gemeinsam genutzt von der Folgenkachel, der Filmdetailseite (beide über
   inc/tmdbMeta.html#tagPills) und den Trefferkacheln der Folgensuche. */
/* Beim Durchscrollen der Folgenliste sollen die Tags sofort ins Auge fallen, dürfen aber nicht wie eine Schaltfläche
   aussehen. Deshalb bewusst anders als die Pillen darunter (siehe .tmdbEpisodeActions .playMovie): eckig statt rund,
   hell gefüllt statt umrandet, und in neutralem Grau statt im Buttonblau. Das Tag-Symbol macht vollends klar, dass
   hier eine Angabe steht und nichts zu drücken ist. */
.tmdbTagPill {
	align-items: center;
	background: #39435c;
	border-radius: 3px;
	color: #d3dcea;
	display: inline-flex;
	/* Fett und eine Spur größer als die Nachbarangaben: die Tags sollen sich beim Durchscrollen der Folgenliste
	   sofort erfassen lassen. */
	font-size: 0.78rem;
	font-weight: 600;
	gap: 0.2rem;
	/* Oben/unten bewusst mehr Luft als der Text bräuchte - die Pille soll als Fläche wirken, nicht wie eng
	   umschlossene Schrift. */
	padding: 0.15rem 0.4rem;
	white-space: nowrap;
}

/* Nur in der Suche: hebt das Tag hervor, wegen dem die Folge im Ergebnis steht - genau die Umkehrung der
   Grundfarben. */
.tmdbTagPill.matched {
	background: #d3dcea;
	color: #39435c;
}

/* Dieselbe Pille, aber als Schaltfläche: Sie öffnet die serienweite Folgensuche mit genau diesem Tag (siehe
   tmdbEpisodeSearch.js). Der Knopf bringt Browservorgaben mit, die die Pille sonst verunstalten - Rahmen, eigene
   Schrift, Innenabstand -, deshalb hier zurückgesetzt statt die Grundregel oben anzupassen. */
button.tmdbTagPill {
	border: 0;
	cursor: pointer;
	font-family: inherit;
	line-height: inherit;
}

button.tmdbTagPill:hover {
	background: #4a5670;
}

.tmdbEpisodeInfoTop .tmdbToggleWatchedBtn:active {
	color: #fff;
}

.tmdbEpisodeMeta {
	align-items: center;
	color: #aaa;
	display: flex;
	flex-wrap: wrap;
	font-size: 0.78rem;
	gap: 0.6rem;
}

.tmdbEpisodeOverview {
	color: #ccc;
	font-size: 0.82rem;
	line-height: 1.4;
	margin: 0;
}

.tmdbEpisodeActions {
	align-items: center;
	display: flex;
	/* Lieber die Zeile umbrechen als die Beschriftung in der Pille: Auf dem Handy schrumpften die Stream-Knöpfe
	   sonst so weit, dass "Streamen (ext. Player)" zweizeilig in der Pille stand. */
	flex-wrap: wrap;
	gap: 0.8rem;
	margin-top: auto;
}

.tmdbEpisodeActions .playMovie {
	align-items: center;
	background: transparent;
	border: none;
	color: #9ac;
	cursor: pointer;
	display: inline-flex;
	font-size: 0.78rem;
	gap: 0.25rem;
	padding: 0;
}

.tmdbEpisodeActions .playMovie:active {
	color: #fff;
}

/* Auf den Detailseiten stehen die technischen Daten frei unter den Chips und brauchen deshalb reichlich Luft
   (1.1rem). In der Kachel liegen sie im Spaltenfluss von .tmdbEpisodeInfo, der bereits 0.4rem Abstand mitbringt -
   der volle Wert ergäbe zusammen 1.5rem und risse die Kachel unnötig auseinander. */
.tmdbEpisodeCard .tmdbTechRows:has(.tmdbTechPill) {
	margin-top: 0.25rem;
}

/* Handy hochkant: Standbild und Text nebeneinander lohnen sich nicht mehr - das 16:9-Bild ist dann nur noch
   halb so hoch wie die Karte (darunter bliebe toter Leerraum) und lässt der Beschreibung weniger als die halbe
   Breite. Stattdessen gestapelt: Bild in voller Breite oben, Text darunter. */
@media (max-width: 640px) {
	.tmdbEpisodeCard {
		flex-direction: column;
	}

	.tmdbEpisodeStillWrap {
		aspect-ratio: 16 / 9;
		border-radius: 8px 8px 0 0;
		flex: 0 0 auto;
		height: auto;
		width: 100%;
	}
}

.tmdbFutureHint {
	font-size: 0.8rem;
	margin-left: 0.5rem;
	color: #aaa;
}

.tmdbUnmatchedTitle {
	margin-top: 2rem;
}

/* Derselbe Zeilenabstand wie bei den Inhaltsangaben (.tmdbOverview): Das sind mehrzeilige Fließtexte, und mit dem
   vorgabemäßig engen Abstand liest sich das über drei Zeilen mühsam. Gilt für beide Seiten, die diese Klasse
   benutzen - es ist dieselbe Sorte Text. */
/* Die Anleitung über einer Tabelle - der eigentliche Text der Seite und nicht ihr Kleingedrucktes, deshalb in
   normaler Textfarbe wie auf der Hilfeseite. Grau auf Dunkelblau las sich schlecht, und gerade hier steht, wie die
   Seite zu bedienen ist. Für Nebensächliches gibt es .tmdbEmpty. */
.tmdbUnmatchedHint {
	color: var(--text);
	line-height: 1.6;
}

.tmdbUnmatchedList {
	color: #ccc;
}

/* Ein Serien-Abschnitt auf der Seite der nicht aufgehenden Aufnahmen (siehe tmdbunmatched.html). In der
   Gesamtansicht stehen mehrere davon untereinander, deshalb eine sichtbare Trennung. */
.tmdbUnmatchedSeries + .tmdbUnmatchedSeries {
	border-top: 1px solid var(--line-subtle);
	margin-top: 2rem;
}

.tmdbUnmatchedSeriesTitle {
	margin-bottom: 0.3rem;
}

.tmdbUnmatchedActions {
	margin-top: 1rem;
}

/* Gesehen-Status-Abgleich (siehe tmdbwatchedsync.html): links die Mediathek, rechts die Aufnahme, dazwischen die
   Richtung. Die beiden Seiten bekommen gleich viel Platz, damit der Pfeil in der Mitte steht und die Spalte, in die
   geschrieben wird, sich nicht durch ihre Breite hervortut. */
.syncToolbar {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-bottom: 1rem;
}

/* Eine Beschriftung, kein Hinweis - deshalb normale Textfarbe, wie die Beschriftungen der Eingabefelder
   (.settingsForm label). Sie gehört zur Bedienung daneben und ist nicht Beiwerk. */
.syncToolbarLabel {
	color: var(--text);
}

/* Das Kästchen der Zusatzoption steht neben der segmentierten Auswahl und braucht deren Höhe: Die Formensprache
   der App gibt allen Bedienelementen einer Zeile --control-height (siehe :root). Ohne die Regel kommt es auf 26 statt
   32 px, weil .defaultCheckboxLabel seine Höhe sonst aus Schriftgröße und Innenabstand bezieht - gemessen, nicht
   geschätzt. Die Klasse selbst bleibt unangetastet: In den Filter-Flyouts stehen diese Pillen untereinander, dort
   wäre eine feste Höhe zu luftig. */
.syncToolbar .defaultCheckboxLabel {
	height: var(--control-height);
}

.syncTable {
	border-collapse: collapse;
	table-layout: fixed;
	width: 100%;
}

.syncTable th {
	color: #aaa;
	font-weight: normal;
	text-align: left;
}

.syncTable th,
.syncTable td {
	padding: 0.35rem 0.6rem 0.35rem 0;
	vertical-align: top;
}

.syncTable .syncArrowCell {
	text-align: center;
	white-space: nowrap;
	width: 5.5rem;
}

.syncSideFile {
	overflow-wrap: anywhere;
}

/* Der Pfeil ist das eigentliche Bedienelement der Zeile und deshalb kräftiger als das Kreuz daneben. */
.syncArrow,
.syncSkip {
	background: transparent;
	border: none;
	cursor: pointer;
	font-size: 1.1rem;
	padding: 0 0.2rem;
}

.syncArrow {
	color: var(--control-border-hover);
}

.syncSkip {
	color: #777;
}

.syncSkip:hover {
	color: #aaa;
}

/* Eine übersprungene Zeile bleibt lesbar, tritt aber zurück - sie ist Teil des Befunds, nur nicht der Handlung. */
.syncRow.syncSkipped td {
	opacity: 0.35;
}

/* Welche Seite gewinnt, sieht man sonst nur am Pfeil in der Mitte - bei 500 Zeilen zu wenig, um eine umgedrehte
   Zeile beim Durchgehen wiederzufinden (11.09.2026 gemeldet). Die unterlegene Seite wird deshalb gedämpft, in
   derselben Sprache wie eine übersprungene Zeile ("zählt nicht"), und die gewinnende zusätzlich fett gesetzt: eine
   Abschwächung allein ließe sich mit "übersprungen" verwechseln.

   Bei "gesehen gewinnt" auf den Serienseiten bleibt beides aus - dort gewinnt keine Seite ganz, sondern je Folge
   eine andere. */
.syncRow td.syncSideLoses {
	opacity: 0.5;
}

.syncRow td.syncSideWins {
	font-weight: 600;
}

.syncRow.syncSkipped .syncArrow {
	color: #777;
}

/* Wie überall: Grün steht für den Gesehen-Status der Mediathek. Hier tragen es beide Seiten, denn in dieser Tabelle
   geht es gerade darum, die eine mit der anderen zu vergleichen. */
.syncWatched {
	color: #6c6;
}

.syncActions {
	align-items: center;
	display: flex;
	gap: 1rem;
	margin-top: 1rem;
}

.syncSummary {
	color: #aaa;
}

/* Serien-Abgleich: In der Mitte steht kein einzelner Pfeil, sondern bis zu zwei mit ihren Zahlen - eine Serie kann
   Folgen in beide Richtungen haben (siehe tmdbSeriesWatchedSync.js). Deshalb hier mehr Platz. */
.syncSeriesTable .syncArrowCell {
	width: 9rem;
}

.syncArrowPart {
	align-items: center;
	display: inline-flex;
	gap: 0.15rem;
	margin: 0 0.25rem;
}

.syncExpand {
	background: transparent;
	border: none;
	color: #aaa;
	cursor: pointer;
	padding: 0 0.3rem 0 0;
}

.syncCount {
	color: #aaa;
	font-size: 0.85rem;
	margin-left: 0.4rem;
}

/* Die Folgen einer Serie: nur Anzeige, entschieden wird auf Serienebene. */
.syncEpisodeList {
	color: #ccc;
	list-style: none;
	margin: 0.2rem 0 0.6rem 1.6rem;
	padding: 0;
}

.syncEpisodeList li {
	align-items: center;
	display: flex;
	gap: 0.4rem;
	padding: 0.1rem 0;
}

.syncEpisodeLabel {
	color: var(--control-text);
	min-width: 3.5rem;
}

/* Die Einträge, die Trakt nicht kennt: eine Aufzählung unter der Tabelle. Dieselbe Farbe wie der Hinweis darüber -
   es ist eine Liste von Titeln, die man lesen können muss (siehe .tmdbEmpty). */
/* Mit Aufzählungszeichen: Eingerückt allein sah es aus wie fortgesetzter Fließtext, nicht wie eine Liste - und genau
   das ist es (11.09.2026 gemeldet). Die Zeilen bleiben deshalb list-item statt flex; die Angabe hinter dem Titel ist
   ohnehin inline und braucht keinen Flex-Container. */
.syncUnknownList {
	color: var(--text);
	list-style: disc;
	margin: 0 0 1rem 0;
	padding-left: 1.6rem;
}

.syncUnknownList li {
	padding: 0.1rem 0;
}

.syncUnknownList li .syncCount,
.syncUnknownList li .tmdbVersionsYear {
	margin-left: 0.4rem;
}

.syncEpisodeText {
	color: #aaa;
	font-size: 0.85rem;
}

.syncEpisodes.syncSkipped {
	opacity: 0.35;
}

@media (max-width: 640px) {
	.syncTable .syncArrowCell {
		width: 4rem;
	}

	.syncSeriesTable .syncArrowCell {
		width: 7rem;
	}
}

/* Filme mit mehreren Fassungen (siehe tmdbversions.html). Ein Block je Film, darin eine Tabelle - anders als bei den
   nicht aufgehenden Serien-Aufnahmen wird hier verglichen, und dafür müssen Länge und Größe untereinander stehen. */
.tmdbVersionsMovie + .tmdbVersionsMovie {
	border-top: 1px solid var(--line-subtle);
	margin-top: 1.5rem;
	padding-top: 1.5rem;
}

.tmdbVersionsYear {
	color: #aaa;
	font-weight: normal;
	margin-left: 0.4rem;
}

.tmdbVersionsTable {
	border-collapse: collapse;
	width: 100%;
}

.tmdbVersionsTable th {
	color: #aaa;
	font-weight: normal;
	text-align: left;
}

.tmdbVersionsTable th,
.tmdbVersionsTable td {
	padding: 0.3rem 0.6rem 0.3rem 0;
	vertical-align: top;
}

/* Die maßgebliche Fassung: Sie allein bestimmt den Gesehen-Status des Films, das muss man sehen, ohne zu zählen. */
.tmdbVersionsTable .tmdbVersionsFirst td {
	color: #eee;
}

/* Derselbe Stern in der Tabelle und im Hinweistext darüber - nur so ist der Bezug ohne Erklärung da. Er steht
   hinter der Bezeichnung, weil er ihr vorangestellt die eine Zeile gegen alle anderen einrückte. */
.tmdbVersionsStar {
	color: var(--control-border);
}

/* Der Abstand nur in der Tabelle: Im Hinweistext steht der Stern in Klammern, dort sähe er wie ein Tippfehler aus. */
.tmdbVersionsTable .tmdbVersionsStar {
	margin-left: 0.3rem;
}

/* Zahlen rechtsbündig, damit zwei Längen bzw. Größen stellengerecht untereinander stehen - genau daran erkennt man
   eine versehentliche Doppel-Aufnahme. */
.tmdbVersionsNum {
	text-align: right !important;
	white-space: nowrap;
}

.tmdbVersionsFlag {
	text-align: center !important;
	white-space: nowrap;
}

/* Das grüne Auge steht app-weit für den Gesehen-Status der Mediathek (.tmdbBadge.watched), nicht für den einer Aufnahme -
   die Aufnahmeliste färbt ihren nirgends. Grün bekommt deshalb allein die maßgebliche Fassung: Bei ihr sind beide
   dasselbe, und die Farbe sagt genau das. Die übrigen Fassungen behalten die Textfarbe ihrer Zeile. */
.tmdbVersionsFirst .tmdbVersionsWatched {
	color: #6c6;
}

/* Der Dateiname bekommt den freien Platz, die Zahlenspalten daneben bleiben schmal. Die Bezeichnung der Fassung
   braucht dabei eine Mindestbreite: Ohne sie drückt die 100%-Spalte sie so schmal, dass "21:9, o. Nachspann" mitten
   im Wort umbricht. */
.tmdbVersionsPath {
	overflow-wrap: anywhere;
	width: 100%;
}

/* Die Bezeichnung der Fassung bleibt am Schreibtisch einzeilig: Sie ist die Spalte, an der man die Zeilen
   auseinanderhält, und umgebrochen ("21:9, o. / Nachspann") liest sie sich schlechter als ein etwas engerer
   Dateiname daneben - der bricht ohnehin an jeder Stelle. Die Mindestbreite hält kurze Bezeichnungen ("SD") auf
   einer ruhigen Spaltenbreite. */
.tmdbVersionsTable td:first-child,
.tmdbVersionsTable th:first-child {
	min-width: 9rem;
	white-space: nowrap;
}

@media (max-width: 640px) {
	/* Nebeneinander ist auf dem Handy kein Platz für fünf Spalten - der Dateiname bräche mitten im Wort. Er rückt
	   deshalb in eine eigene Zeile darüber, während Bezeichnung, Länge, Größe und Gesehen-Status untereinander stehen
	   bleiben: Genau deren Vergleich ist der Zweck der Seite, den darf die Umstellung nicht kosten. */
	.tmdbVersionsTable thead {
		display: none;
	}

	.tmdbVersionsTable tr {
		display: grid;
		grid-template-columns: 1fr auto auto auto;
		padding: 0.4rem 0;
	}

	.tmdbVersionsTable tr + tr {
		border-top: 1px solid var(--line-subtle);
	}

	/* Schmal ist für Einzeiligkeit kein Platz - hier muss die Bezeichnung umbrechen dürfen. */
	.tmdbVersionsTable td:first-child {
		min-width: 0;
		white-space: normal;
	}

	.tmdbVersionsPath {
		grid-column: 1 / -1;
		order: -1;
	}
}

/* ------------------------------------------------------------------------------------------------
   Folgen mit mehreren Aufnahmen (/tmdb/episodeversions/)

   Dieselben Spalten wie bei den Fassungen eines Films, aber eine Tabelle für den ganzen Bestand: Je Folge ein tbody
   mit einer Zwischenzeile davor, die Serie, Nummer und Folgentitel trägt. Hier kommen deshalb nur die Regeln für
   diese Zwischenzeile dazu.
   ------------------------------------------------------------------------------------------------ */

/* Bewusst ein td und kein th: Ein th brächte den Hintergrund des Tabellenkopfs mit (siehe die globale th-Regel) und
   die Zwischenzeile sähe aus wie ein zweiter Spaltenkopf. Die erste Spalte ist sonst einzeilig und schmal-begrenzt
   (.tmdbVersionsTable td:first-child) - beides muss hier zurückgenommen werden, sonst ragt ein langer Folgentitel
   aus der Tabelle heraus. */
.tmdbEpisodeVersionsTable .tmdbEpisodeVersionsGroup td {
	color: #eee;
	min-width: 0;
	padding-bottom: 0.1rem;
	padding-top: 0.8rem;
	white-space: normal;
}

/* Die Trennlinie trägt die Zwischenzeile, nicht jede Zeile: Zwischen den Aufnahmen einer Folge soll gerade keine
   stehen - sie gehören zusammen und werden miteinander verglichen. Beim ersten tbody entfällt sie, dort steht schon
   der Tabellenkopf darüber. */
.tmdbEpisodeVersionsTable tbody + tbody .tmdbEpisodeVersionsGroup td {
	border-top: 1px solid var(--line-subtle);
}

/* Die Serie führt die Zeile an und ist der Anker beim Überfliegen - deshalb fett, während die Folgennummer daneben
   ein gewöhnlicher Link bleibt. */
.tmdbEpisodeVersionsSeries {
	font-weight: bold;
	margin-right: 0.4rem;
}

/* Der Folgentitel erläutert die Nummer und ist die Beigabe, nicht der Anker - gedämpft wie überall in dieser Rolle. */
.tmdbEpisodeVersionsName {
	color: #aaa;
	margin-left: 0.4rem;
}

/* Der Info-Knopf in der Fassungs-Spalte: nur das Symbol, ohne Fläche - die Spalte ist eine Beschriftung und kein
   Bedienfeld, ein Knopf mit Rahmen zöge dort alle Aufmerksamkeit auf sich. line-height und der fehlende Innenabstand
   halten ihn auf der Zeilenhöhe: Das Symbol ist größer als die Tabellenschrift und dehnte die Zeile sonst auf
   (dieselbe Falle wie beim Chip der Filmdetailseite, siehe .tmdbRecordingChipInfo). */
.tmdbEpisodeVersionsInfo {
	background: transparent;
	border: none;
	color: inherit;
	cursor: pointer;
	display: inline-flex;
	line-height: 1;
	margin-left: 0.35rem;
	padding: 0;
	vertical-align: text-bottom;
}

.tmdbEpisodeVersionsInfo i {
	font-size: 1.1rem;
}

.tmdbEpisodeVersionsInfo:active {
	color: #fff;
}

/* Das grüne Auge steht app-weit für den Gesehen-Status der Mediathek (.tmdbBadge.watched) - hier also für den der
   Folge. Die Spalte rechts zeigt den der einzelnen Dateien und bleibt deshalb farblos, genau wie in der
   Aufnahmeliste. */
.tmdbEpisodeVersionsWatched {
	color: #6c6;
	margin-left: 0.4rem;
}

.tmdbEpisodeVersionsUnwatched {
	color: #aaa;
	margin-left: 0.4rem;
}

/* Der Hinweis auf die vermutete Doppel-Aufnahme, im selben gedämpften Warnton wie .tmdbRecordingMissing ("fehlt"):
   Auch das hier ist eine Feststellung an der Aufnahme, nur eine vermutete - deshalb derselbe Ton und nicht das Rot,
   das app-weit dem Fehler vorbehalten ist. */
.tmdbEpisodeVersionsSuspect {
	color: #c88;
	font-size: 0.85rem;
	margin-left: 0.5rem;
	white-space: nowrap;
}

.tmdbEpisodeVersionsSuspect i,
.tmdbEpisodeVersionsSuspectIcon {
	color: #c88;
	margin-right: 0.25rem;
}

@media (max-width: 640px) {
	/* Schmal wird jede Zeile zum Raster (siehe .tmdbVersionsTable oben) - die Zwischenzeile hat aber nur eine Zelle
	   und stünde sonst allein in der ersten Spalte. */
	.tmdbEpisodeVersionsTable .tmdbEpisodeVersionsGroup td {
		grid-column: 1 / -1;
	}

	/* Die Trennlinie zwischen zwei Zeilen kommt schmal aus der allgemeinen Regel (tr + tr) - innerhalb einer Folge
	   ist sie hier so wenig gewollt wie breit. */
	.tmdbEpisodeVersionsTable tbody tr + tr {
		border-top: none;
	}
}

@media (max-width: 640px) {
	.tmdbGrid {
		grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
	}

	/* Mit den schmaleren Kacheln muss auch das Fragezeichen kleiner werden, sonst läuft es seitlich heraus. */
	.tmdbTile.tmdbTileMuted .tmdbPosterPlaceholder {
		font-size: 6.5rem;
	}

	/* In einer nur ~8rem breiten Kachel reicht der Platz für "TMDB" und "Trailer" im Klartext nicht mehr - hier
	   bleiben die Icons allein stehen, ihre Bedeutung nennt weiterhin der title-Tooltip. Nur in den Kacheln: die
	   Pills der Detailseiten haben die ganze Seitenbreite und behalten ihre Beschriftung. */
	.tmdbTileLinks .tmdbExternalLink span {
		display: none;
	}

	/* Ausnahme Portal: Dort steht in der Zeile nur noch der Trailer-Link, der TMDB-Link daneben ist ausgeblendet
	   (siehe body.portalMode .tmdbTileLinks). Der Platz, den das freimacht, ist genau der, der hier fehlte - und ein
	   einzelnes Zeichen ohne Beschriftung ist für jemanden, der die Mediathek nur zum Ansehen benutzt, schlechter zu
	   deuten als für einen Administrator. Gezielt der YouTube-Link, nicht .tmdbExternalLink allgemein: Sonst bekäme
	   ein künftiger Link dort seine Beschriftung zurück, ohne dass jemand darüber nachgedacht hat. */
	body.portalMode .tmdbTileLinks .tmdbYoutubeLink span {
		display: inline;
	}
}

/* Verknüpfungs-Badges/-Buttons auf MovieDirsPage/MovieListPage --------------------------------- */

.actions .actionFlyout a.tmdbGotoSeries,
.actions .actionFlyout a.tmdbGotoMovie {
	align-items: center;
	color: var(--group-mediathek-bright);
	display: inline-flex;
	padding: 0.25rem 0.25rem;
}

.actions.actionsSmall .actionFlyout a.tmdbGotoSeries {
	padding: 0.1rem 0.1rem;
}

.actions .actionFlyout a.tmdbGotoSeries i,
.actions .actionFlyout a.tmdbGotoMovie i {
	font-size: 1.2rem;
}

/* Auf schmalen Bildschirmen ist das .actionFlyout ein senkrechtes Menü (siehe dort), in dem diese beiden Links
   ganz normale Einträge sind: Innenabstand und Beschriftungsfarbe wie bei den Buttons daneben statt der kompakten
   Badge-Darstellung aus der Icon-Reihe. Der Block steht hier unten und nicht oben in der Media Query, weil die drei
   Regeln darüber sonst gleichauf lägen und als spätere im Dokument gewönnen.
   Die Maße müssen dieselben rem-Werte sein wie bei den Menüeinträgen oben - warum nicht em, steht dort. */
@media (max-width: 1024px) {

	.actions .actionFlyout > a.tmdbGotoSeries,
	.actions .actionFlyout > a.tmdbGotoMovie,
	.actions.actionsSmall .actionFlyout > a.tmdbGotoSeries {
		color: white;
		padding: 0.35rem 0.625rem;
	}

	/* Das Icon bleibt grün, auch wenn die Beschriftung weiß ist wie überall im Menü: Es ist das einzige Zeichen
	   dafür, dass hier bereits eine TMDB-Verknüpfung besteht (der Eintrag heißt sonst nur "Zum TMDB-Film"). Auf
	   breiten Bildschirmen sagt das dasselbe grüne Symbol in der Icon-Reihe, siehe die Regel weiter oben. */
	.actions .actionFlyout > a.tmdbGotoSeries i,
	.actions .actionFlyout > a.tmdbGotoMovie i {
		color: var(--group-mediathek-bright);
	}
}

/* Bewertung und externe Links (TMDB/YouTube) ---------------------------------------------------- */

.tmdbRating {
	color: #fc6;
	margin-left: 0.4rem;
	white-space: nowrap;
}

/* Als Flyout-Auslöser auf den Detailseiten ist die Bewertung eine Schaltfläche (siehe das Makro ratingFlyout). Der
   Reset in ".actions button" ist spezifischer als ".tmdbRating" und färbte sie sonst weiß; Schriftart und Innenabstand
   kämen ebenfalls von dort. Gleiches Muster wie bei ".actions .tmdbTechPillBtn". */
.actions .tmdbRating {
	color: #fc6;
	cursor: pointer;
	font-family: inherit;
	font-size: inherit;
	padding: 0;
}

/* Gegen ".actions button i" (1.2rem): Ob anklickbar oder nicht ändert nichts an der Größe des Sterns. */
.actions .tmdbRating i {
	font-size: 1rem;
}

/* Nimmt die Regel eine Zeile darüber vom Pfeil wieder zurück, damit er so klein bleibt wie an den übrigen Pillen
   (siehe .tmdbFlyoutCaret). */
.actions .tmdbRating .tmdbFlyoutCaret {
	font-size: 0.7em;
}

/* Die Zeilen des Bewertungs-Flyouts stehen in drei Spalten (Quelle, Wert, Einordnung), damit Sterne und Zahlen
   untereinander stehen: "IMDb" ist schmaler als "TMDB", nebeneinandergeschrieben liefen die Werte sonst versetzt.
   max-content nimmt die Breite der längsten Quelle, sodass eine weitere Zeile (etwa Trakt) ohne Anpassung mitgeht.

   Der lange Selektor ist nötig: ".actions .moreFlyout.open" setzt display:flex und gap und ist spezifischer als eine
   einzelne Klasse - die Zellen stünden sonst als schmale Spalte untereinander. */
.actions .moreFlyout.tmdbRatingFlyout.open {
	align-items: baseline;
	column-gap: 0.45em;
	display: grid;
	grid-template-columns: max-content max-content max-content;
	row-gap: 0.15em;
}

/* Die Überschrift ist keine Zeile des Rasters, sondern steht über allen drei Spalten. */
.tmdbRatingFlyout .tmdbTechFlyoutTitle {
	grid-column: 1 / -1;
}

/* Wie .tmdbTechFlyoutItem, dessen Platz die drei Zellen einnehmen - bewusst je Klasse und nicht über den Nachfahren
   "span", da das auch die kleiner gesetzte Überschrift träfe. */
.tmdbRatingFlyoutSource,
.tmdbRatingFlyoutValue,
.tmdbRatingFlyoutExtra {
	font-size: 0.85rem;
	white-space: nowrap;
}

/* Stern und Wert tragen dieselbe Farbe wie die Pille darüber - beides zusammen oder gar nicht, ein andersfarbiger
   Stern neben einem Wert in Textfarbe sähe nach Versehen aus. Quelle und Einordnung bleiben in der Textfarbe und
   treten damit hinter die Zahl zurück, auf die es ankommt. */
.tmdbRatingFlyoutValue {
	color: #fc6;
}

.tmdbRatingFlyoutValue i {
	margin-right: 0.15rem;
}

/* Die Zahl der Stimmen hinter der Bewertung: in der gedämpften Textfarbe der übrigen Nebenangaben und kleiner
   gesetzt, denn sie ordnet die Bewertung nur ein und soll ihr nicht die Aufmerksamkeit nehmen. */
.tmdbVoteCount {
	color: var(--text-muted);
	font-size: 0.85em;
	margin-left: 0.25rem;
}

/* Kompakte Kennzahl mit Icon in den Meta-Zeilen der Detailseiten (siehe inc/tmdbMeta.html#stat). Die Farben
   entsprechen den Kennzeichen auf den Postern, damit Icon und Badge dieselbe Bedeutung tragen. */
.tmdbStat {
	margin-left: 0.6rem;
	white-space: nowrap;
}

.tmdbStat i {
	margin-right: 0.2rem;
}

/* Dieselben Farben stehen den Kopfzeilen der Übersichtsseiten zur Verfügung, wo die Kennzahl ausgeschrieben und
   nicht als .tmdbStat aufgebaut ist (siehe tmdbmovies.html/tmdbseries.html): */
.tmdbStat.collected i,
.tmdbIconCollected {
	color: #6af;
}

.tmdbStat.watched i,
.tmdbIconWatched {
	color: #6c6;
}

/* Die jeweils zweite Zahl der Zusammenfassungszeile ("292 + 95 gesammelt", siehe tmdbseries.html): angefangen, aber
   nicht fertig - dasselbe Symbol in demselben Grau, in dem die Kachel ihr Kennzeichen dann zeigt
   (.tmdbBadge.collected.partial). Die Farbe ist der ganze Unterschied zur Zahl davor, hier wie dort. */
.tmdbIconPartial {
	color: #889;
}

/* Lila wie das Filmreihen-Kennzeichen auf dem Poster (.tmdbBadge.collectionMark) - das Stapel-Icon steht überall
   im Bereich für "Filmreihe/Sammlung": */
.tmdbStat.inCollection i,
.tmdbIconCollection {
	color: #cae;
}

/* Überschrift der Detailseiten mit den Blätter-Pfeilen dahinter (Staffel bzw. Film einer Reihe): */
.tmdbDetailTitle {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
}

.tmdbTitleNav {
	display: inline-flex;
	gap: 0.2rem;
}

.tmdbTitleNav a,
.tmdbTitleNav .disabled {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	display: inline-flex;
	font-size: 1.1rem;
	height: 2rem;
	justify-content: center;
	width: 2rem;
}

.tmdbTitleNav a:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Am Anfang bzw. Ende bleibt der Pfeil stehen statt zu verschwinden - sonst springt der jeweils andere an seine
   Stelle und man klickt beim Durchblättern daneben: */
.tmdbTitleNav .disabled {
	border-color: #2a3a5a;
	color: var(--text-faint);
}

.tmdbRating i {
	margin-right: 0.15rem;
}

/* TMDB-Link, Trailer-Link und "..."-Menü teilen sich hier gut 8rem - eine Kachel ist nur ~9,5rem breit, und wie
   breit sie wirklich wird, bestimmt das Grid je nach Fensterbreite (auto-fill mit 1fr, siehe .tmdbGrid). Mit zu
   großen Abständen wurde das Menü aus der Kachel herausgeschoben - in der rechten Spalte aus dem Fenster heraus,
   was die Seite waagerecht scrollbar machte.

   Den sichtbaren Abstand erzeugt deshalb space-between aus dem freien Rest - das hält die Lücken untereinander
   gleich, statt (wie zuvor per margin-left:auto am Menü) den gesamten Rest in die letzte Lücke zu legen und dadurch
   ungleichmäßig zu wirken. Der column-gap ist dabei nur die Untergrenze, ab der umbrochen wird, und deshalb 0: schon
   ein Millimeter Mindestabstand kostet in der engsten Kachel genau die Zeile.

   flex-wrap bleibt als Sicherheitsnetz für den Fall, dass es doch einmal nicht reicht (größere Schrift). */
.tmdbTileLinks {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem 0;
	justify-content: space-between;
	margin: 0 0.5rem 0.5rem 0.5rem;
}

/* margin-left:auto würde den gesamten freien Platz an sich ziehen und space-between damit aushebeln: */
.tmdbTileLinks .tmdbTileMoreActions,
.tmdbTileLinks .tmdbAddPartBtn {
	margin-left: 0;
}

/* Der knappe gap zwischen Icon und Beschriftung ist Teil der Platzrechnung der Kachel-Linkzeile (siehe
   .tmdbTileLinks); die Pills der Detailseiten setzen sich davon bewusst ab und bringen ihren eigenen mit. */
.tmdbExternalLink {
	align-items: center;
	color: #9ac;
	display: inline-flex;
	font-size: 0.78rem;
	gap: 0.125rem;
	text-decoration: none;
}

.tmdbExternalLink:active {
	color: #fff;
}

.tmdbYoutubeLink {
	color: #e55;
}

.tmdbYoutubeLink:active {
	color: #f88;
}

/* Die Pille für die eigenen Videoclips einer Serie ("... 0x00 - Trailer"). Immer ein <button>, da sie die Aufnahme
   auf der Dreambox startet statt einem Link zu folgen - deshalb der Reset auf die Optik der <a>-Pillen daneben.
   Farblich bewusst wie die übrigen Bedienelemente und nicht wie die rote YouTube-Pille: sie führt nicht nach außen. */
button.tmdbExternalLink {
	background: transparent;
	border: none;
	cursor: pointer;
	font-family: inherit;
	padding: 0;
}

/* Etwas mehr Luft als bei den Nachbarpillen: das schmale Play-Dreieck rückt sonst an die Beschriftung heran,
   während die breiten, quadratischen Icons daneben (YouTube-Logo, Pfeil im Kasten) von selbst Abstand halten. */
.tmdbLocalVideoLink {
	gap: 0.25rem;
}

/* Die Meta-Zeile der Detailseiten (Angaben, Bewertung, am Ende die Pills). Bewusst Flexbox statt Textfluss: auf
   schmalen Bildschirmen rutschen die Pills in eine eigene Zeile, und im Textfluss sähe das an beiden Enden falsch
   aus - ein Umbruch erzeugt dort keinen Abstand nach oben, während das margin-left der Pills als Einzug von links
   stehen bliebe. Als Flex-Zeile übernimmt das der row-gap, und der Abstand zwischen den Angaben kommt aus dem
   column-gap, der beim Umbruch von selbst verschwindet. */
.tmdbMetaLine {
	align-items: center;
	column-gap: 0.6rem;
	display: flex;
	flex-wrap: wrap;
	row-gap: 0.5rem;
}

/* In der Flex-Zeile trennt der column-gap; die eigenen Abstände der Bausteine kämen sonst obendrauf und wirkten
   nach einem Umbruch wieder als Einzug: */
.tmdbMetaLine .tmdbStat,
.tmdbMetaLine .tmdbRating,
.tmdbMetaLine .tmdbDetailLinks {
	margin-left: 0;
}

/* Der Originaltitel direkt unter der Überschrift: kleiner und grauer als diese, damit er sie ergänzt statt mit ihr
   zu konkurrieren. Der negative obere Abstand holt ihn dicht an den Titel heran - er gehört zu ihm, während die
   Tagline darunter eine eigene Aussage ist. */
.tmdbOriginalTitle {
	color: var(--text-muted);
	font-size: 0.85rem;
	margin: -0.6rem 0 0.5rem 0;
}

/* Gleiches Element im Detail-Popup-Kopf (siehe base.html): dort sitzt der Titel nicht unter einer großen Überschrift,
   sondern in der schmalen Dialog-Kopfzeile - daher kleiner und ohne den negativen Abstand der Detailseiten-Variante. */
.tmdbDetailPopupTitleBlock .tmdbOriginalTitle {
	font-size: 0.75rem;
	margin: 0.1rem 0 0 0;
}

/* Kurzer Werbespruch der Detailseiten (Film/Serie), zwischen Titel und Meta-Zeile. Bewusst nicht var(--text-faint):
   das ist die Farbe für abgeschaltete Bedienelemente und für einen kursiven Satz auf dem dunklen Hintergrund zu
   schwach - hier soll er gedämpft, aber lesbar sein. */
.tmdbTagline {
	color: #9ab;
	font-style: italic;
	margin: 0 0 0.5rem 0;
}

/* Genres/Produktionsländer, zwischen Meta-Zeile und Inhaltsangabe - dieselbe gedämpfte Farbe wie .tmdbOverview,
   aber kleiner, da reine Zusatzinfo statt Fließtext. Die Serienzeile (Status, nächste Folge, Sender, Erfinder)
   steht direkt darunter und sieht bewusst genauso aus - beides sind Angaben zum Titel, keine Bedienelemente. */
.tmdbGenreLine,
.tmdbSeriesLine {
	color: #ccc;
	font-size: 0.85rem;
	margin: 0 0 0.6rem 0;
}

/* Am Ende der Genre-Zeile stehen die Kategorie-Pillen (siehe inc/tmdbMeta.html#categoryPills). Damit sie in der
   Textzeile mittig sitzen statt auf deren Grundlinie zu hängen, ist die Zeile ein Flex-Container; der Umbruch trennt
   dann Text und Pillen sauber, statt eine Pille in die nächste Zeile zu ziehen. Der senkrechte Abstand ist kleiner
   als der waagerechte: untereinander stehen die Pillen ohnehin schon durch ihre Flächen auseinander. */
.tmdbGenreLine {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.25rem 0.45rem;
}

/* Zwischen beiden Zeilen soll kein doppelter Abstand stehen: */
.tmdbGenreLine + .tmdbSeriesLine {
	margin-top: -0.35rem;
}

/* Kategorie-Pille: Aufbau der Technik-Pillen (siehe .tmdbTechPill) - angedeutete statt gefüllter Fläche, denn eine
   Kategorie ist in erster Linie eine Angabe und keine Schaltfläche, auch wenn sie zusätzlich verlinkt. Etwas kleiner
   als dort (weniger Innenabstand auf allen vier Seiten): eine Kategorie ist eine einzelne, meist kurze Zuordnung wie
   ein Aufnahme-Tag, kein womöglich mehrstelliger technischer Wert.

   Der Rahmen trägt die helle statt der gedeckten Gruppenfarbe, aus zwei Gründen: Erstens wäre er in der gedeckten
   Fassung neben der ohnehin schwachen Fläche kaum noch zu sehen - genau das Gegenteil von "etwas weniger
   unscheinbar", das hier gewollt ist. Zweitens trägt die aufklappbare Technik-Pille (Ton/Untertitel, siehe
   ".actions .tmdbTechPillBtn") ebenfalls den kräftigeren Rahmen der Bedienelemente, wenn sie tatsächlich etwas tut -
   hier bedeutet der helle Rahmen also durchgängig "das hier führt irgendwohin", nicht nur zufällig dieselbe Farbe wie
   das Symbol. */
a.tmdbCategoryPill {
	align-items: center;
	background: rgba(116, 189, 147, 0.10);
	border: 1px solid var(--group-mediathek-bright);
	border-radius: var(--control-radius);
	color: #cfe6d9;
	display: inline-flex;
	font-size: 0.8rem;
	gap: 0.3rem;
	height: 1.4rem;
	padding: 0 0.55rem;
	white-space: nowrap;
}

a.tmdbCategoryPill i {
	color: var(--group-mediathek-bright);
	font-size: 1rem;
}

a.tmdbCategoryPill:hover {
	background: rgba(116, 189, 147, 0.22);
	color: #fff;
}

/* Videos ---------------------------------------------------------------------------------------- */

/* YouTube-Titel werden beliebig lang ("Michael Emerson Joins Elsbeth ("The Good Wife" / ...) CBS Trailer"). Ohne
   Begrenzung wüchse das Flyout mit ihnen und schöbe sich - da es am Auslöser rechts ausgerichtet ist - über die
   Navigationsleiste hinaus: */
.tmdbVideoFlyout {
	max-width: 22rem;
}

/* Im Flyout der Video-Pillen steht die Typ- bzw. Bezeichnungszeile über der Beschreibung; ohne diese Ausrichtung
   säße das Icon neben der zweizeiligen Beschriftung mittig statt an der ersten Zeile. Gilt für beide Pillen: die
   YouTube-Videos sind <a>, die eigenen Aufnahmen <button> (sie starten auf der Dreambox). */
.tmdbVideoFlyout a,
.tmdbVideoFlyout button {
	align-items: flex-start;
}

/* Das Icon darf hier größer ausfallen als in den einzeiligen Menüs: die Beschriftung daneben ist zweizeilig,
   und ein Icon in Standardgröße wirkte daneben verloren. */
.tmdbVideoFlyout a i,
.tmdbVideoFlyout button i {
	font-size: 1.7rem;
}

/* min-width: 0 erlaubt dem Textblock, schmaler als sein Inhalt zu werden - ohne das greift das ellipsis darunter
   nicht, weil ein Flex-Kind standardmäßig nicht unter seine Inhaltsbreite schrumpft: */
.tmdbVideoFlyoutText {
	display: flex;
	flex-direction: column;
	line-height: 1.3;
	min-width: 0;
}

/* Der Typ ist die Gruppierung und trägt deshalb das Gewicht, der Videoname steht als Erläuterung darunter: */
.tmdbVideoFlyout .tmdbVideoType {
	font-weight: bold;
}

/* Sprache und Auflösung hinter dem Typ - gedämpft und ohne dessen Fettung, sie sind nur Beiwerk zur Typangabe: */
.tmdbVideoDetails {
	color: var(--text-muted);
	font-size: 0.8rem;
	font-weight: normal;
	margin-left: 0.3rem;
}

/* Kennzeichnet eine Pille als Flyout-Auslöser (siehe inc/tmdbMeta.html#flyoutCaret). Kleiner als die Beschriftung
   und gedämpft: es ist ein Hinweis auf das Verhalten, kein eigener Inhalt. */
.tmdbFlyoutCaret {
	font-size: 0.7em;
	margin-left: 0.1rem;
	opacity: 0.7;
}

.tmdbVideoFlyout .tmdbVideoName {
	color: var(--text-muted);
	font-size: 0.8rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Der eigene Videobereich der Filmdetailseite (siehe inc/tmdbMeta.html#videoSection). */
.tmdbVideoSection {
	margin-top: 1.5rem;
}

.tmdbVideoSection h3 {
	margin: 0 0 0.6rem 0;
}

/* In jeder Breite eine quer wischbare Reihe, nicht nur am Handy: Zu einem Film können zwei Dutzend Videos gehören
   ("Glass": 24). Umbrechend füllten die allein mehrere Bildschirmhöhen, und was darunter steht - Regie, verknüpfte
   Inhalte, Vorschläge - wäre nur noch über langes Scrollen erreichbar. Eine Zeile hoch bleibt der Bereich das, was
   er ist: ein Angebot am Rand.
   Die angeschnittene nächste Karte am rechten Rand zeigt an, dass es weitergeht. */
.tmdbVideoRow {
	display: flex;
	flex-wrap: nowrap;
	gap: 0.8rem;
	overflow-x: auto;
	padding-bottom: 0.5rem;
	scroll-snap-type: x proximity;
}

.tmdbVideoCard {
	scroll-snap-align: start;
}

.tmdbVideoCard {
	color: inherit;
	flex: none;
	text-decoration: none;
	width: 15rem;
}

/* Eine eigene Aufnahme ist ein <button> (sie startet auf der Dreambox), die YouTube-Videos daneben sind <a> - beide
   sollen gleich aussehen. align-self verhindert dabei, dass die Reihe den Button auf die Höhe der höchsten Karte
   streckt: ein Button zentriert seinen Inhalt vertikal, wodurch Vorschaufläche und Beschriftung tiefer säßen als
   nebenan. */
button.tmdbVideoCard {
	align-self: start;
	background: transparent;
	border: none;
	cursor: pointer;
	font-family: inherit;
	font-size: inherit;
	padding: 0;
	text-align: left;
}


/* Bezugspunkt für das Play-Symbol, das absolut darüber liegt: */
.tmdbVideoThumb {
	background: #0d1424;
	border-radius: 8px;
	display: block;
	overflow: hidden;
	position: relative;
}

/* Von einer eigenen Aufnahme gibt es kein Vorschaubild - die Fläche bleibt leer und trägt nur das Play-Symbol, das
   auch auf den YouTube-Karten daneben liegt. Der 16:9-Ausschnitt kommt hier von der Kachel selbst statt vom Bild.
   Sie braucht dabei einen eigenen, helleren Hintergrund als .tmdbVideoThumb: dessen #0d1424 ist der Seitenfarbe so
   nah, dass die leere Fläche unsichtbar wäre und das Play-Symbol frei zu schweben schiene. */
.tmdbVideoThumbLocal {
	aspect-ratio: 16 / 9;
	background: var(--surface);
	width: 100%;
}

/* 16:9 wie das mqdefault-Vorschaubild - fest gesetzt, damit die Reihe beim Nachladen der Bilder nicht springt: */
.tmdbVideoThumb img {
	aspect-ratio: 16 / 9;
	display: block;
	object-fit: cover;
	width: 100%;
}

.tmdbVideoPlay {
	align-items: center;
	background: rgba(0, 0, 0, 0.55);
	border-radius: 50%;
	color: #fff;
	display: flex;
	font-size: 1.4rem;
	height: 3rem;
	justify-content: center;
	left: 50%;
	position: absolute;
	top: 50%;
	transform: translate(-50%, -50%);
	width: 3rem;
}

.tmdbVideoCard:active .tmdbVideoPlay {
	background: #e55;
}

/* Auf einer eigenen Aufnahme ist das Play-Symbol das einzige Element der leeren Fläche - der abgedunkelte Kreis der
   YouTube-Karten ergäbe hier keinen Sinn, er hebt sich dort ja von einem Bild ab. Stattdessen die Optik der runden
   Icon-Schaltflächen des Bereichs (siehe .tmdbIconBtn): Das sagt zugleich, dass hier etwas im Haus startet und nicht
   im Browser aufgeht. */
.tmdbVideoThumbLocal .tmdbVideoPlay {
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	color: var(--control-text);
}

.tmdbVideoCard:active .tmdbVideoThumbLocal .tmdbVideoPlay {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Auf den YouTube-Karten steht das Logo an der Stelle des Abspiel-Dreiecks (siehe inc/tmdbMeta.html#videoSection).
   Ohne den dunklen Kreis der Abspiel-Schaltfläche: das Logo hat mit seiner eigenen Fläche schon eine Form, im Kreis
   säße Rund in Rund. Bewusst nicht in der Markenfarbe, sondern hell und halbdurchsichtig wie ein Wasserzeichen -
   es unterscheidet die Karte von einer eigenen Aufnahme, soll aber neben dem Vorschaubild nicht um Aufmerksamkeit
   ringen. Der Schatten hält es auch auf hellen Bildern lesbar. */
.tmdbVideoPlayYoutube {
	background: none;
	color: rgba(255, 255, 255, 0.8);
	font-size: 3rem;
	height: auto;
	text-shadow: 0 1px 6px rgba(0, 0, 0, 0.6);
	width: auto;
}

.tmdbVideoCard:active .tmdbVideoPlayYoutube {
	background: none;
	color: #fff;
}

.tmdbVideoCard .tmdbVideoType {
	display: block;
	font-weight: bold;
	margin-top: 0.4rem;
}

/* Lange Videonamen auf zwei Zeilen begrenzen, damit die Kacheln der Reihe gleich hoch bleiben: */
.tmdbVideoCard .tmdbVideoName {
	color: var(--text-muted);
	display: -webkit-box;
	font-size: 0.8rem;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	overflow: hidden;
}

/* Regie & Besetzung ----------------------------------------------------------------------------- */

/* Aufbau und Verhalten wie beim Videobereich darüber (siehe .tmdbVideoSection): am Desktop umbrechend, auf dem
   Handy eine quer wischbare Reihe. Die Karten sind allerdings halb so breit - ein Profilbild steht hochkant, wo
   ein Video-Vorschaubild quer liegt, und so passen doppelt so viele Personen in eine Zeile. */
.tmdbCreditSection {
	margin-top: 1.5rem;
}

.tmdbCreditSection h3 {
	margin: 0 0 0.6rem 0;
}

.tmdbCreditRow {
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
}

.tmdbCreditCard {
	color: inherit;
	flex: none;
	text-decoration: none;
	width: 7.5rem;
}

.tmdbCreditPhoto {
	background: #0d1424;
	border-radius: 8px;
	display: block;
	overflow: hidden;
}

/* 2:3 wie ein Poster - fest gesetzt, damit die Reihe beim Nachladen der Bilder nicht springt und Karten mit und
   ohne Foto gleich hoch bleiben: */
.tmdbCreditPhoto img,
.tmdbCreditPlaceholder {
	aspect-ratio: 2 / 3;
	display: block;
	object-fit: cover;
	width: 100%;
}

.tmdbCreditPlaceholder {
	align-items: center;
	color: var(--text-faint);
	display: flex;
	font-size: 2.5rem;
	justify-content: center;
}

.tmdbCreditName {
	display: block;
	font-weight: bold;
	margin-top: 0.4rem;
}

/* Lange Rollennamen auf zwei Zeilen begrenzen, damit die Karten gleich hoch bleiben (wie bei den Videonamen): */
.tmdbCreditRole {
	color: var(--text-muted);
	display: -webkit-box;
	font-size: 0.8rem;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	overflow: hidden;
}

@media (max-width: 640px) {
	.tmdbCreditRow {
		flex-wrap: nowrap;
		overflow-x: auto;
		padding-bottom: 0.5rem;
		scroll-snap-type: x proximity;
	}

	.tmdbCreditCard {
		scroll-snap-align: start;
	}
}

/* Titelkarten (ähnliche Titel, Filmografie) --------------------------------------------------------------------------- */

/* Aufbau wie die Video- und Besetzungs-Reihe darüber (siehe .tmdbVideoRow): am Desktop umbrechend, auf dem Handy
   quer wischbar. Die Karten sind so breit wie die der Besetzung - beide zeigen ein Bild im Hochformat. */
.tmdbTitleCardSection {
	margin-top: 1.5rem;
}

.tmdbTitleCardSection h3 {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	margin: 0 0 0.6rem 0;
}

/* Die verlinkte Überschrift soll wie eine Überschrift aussehen, nicht wie ein Link - der Weg zur vollen Ansicht
   ist ein Angebot, keine Ansage. Sie erbt deshalb Farbe und Schrift und zeigt sich erst beim Überfahren. */
.tmdbTitleCardHeadingLink {
	align-items: center;
	color: inherit;
	display: flex;
	gap: 0.5rem;
	text-decoration: none;
}

.tmdbTitleCardHeadingLink:hover {
	text-decoration: underline;
}

/* Sagt nur "Filme" oder "Serien" und steht damit deutlich unter dem Namen der Reihe davor: kleiner und
   zurückgenommen, wie die Meta-Angaben unter den Karten (siehe .tmdbTitleCardMeta). */
.tmdbTitleCardGroupIcon {
	color: var(--text-muted);
	font-size: 0.8em;
}

.tmdbTitleCardRow {
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
}

/* Die Karte ist ein Behälter, der Verweis eine durchsichtige Fläche darüber (siehe .tmdbTitleCardLink) - eine
   Ausnahme ist die "Verknüpfen"-Karte am Ende von "Siehe auch", die selbst eine Schaltfläche ist. Deshalb werden
   hier die Vorgaben für Schaltflächen zurückgenommen, damit auch sie wie die übrigen Karten aussieht.

   position:relative ist der Bezugspunkt für die Verweis-Fläche und für die Kennzeichen darüber. Bewusst kein
   overflow:hidden: Das schnitte die Tooltip-Blase der Kennzeichen ab (siehe .tmdbTitleCardMarks) - die Ecken
   rundet das Poster selbst ab. */
.tmdbTitleCard {
	background: none;
	border: none;
	color: inherit;
	cursor: pointer;
	display: block;
	flex: none;
	font: inherit;
	padding: 0;
	position: relative;
	text-align: left;
	text-decoration: none;
	width: 7.5rem;
}

/* Die Fläche, die die ganze Karte anklickbar macht: eine eigene Schicht über der Karte statt einer Hülle um sie
   herum. Als Hülle fing der Verweis auch den Tipp auf ein Kennzeichen ab - dessen Tooltip war damit nicht zu
   lesen, weil im selben Zug die Detailseite aufging. Bei den großen Kacheln ist es seit jeher getrennt: Dort
   umschließt der Link nur das Poster, die Kennzeichen stehen daneben (siehe .tmdbPosterLink).

   Übernommene Titel tragen hier ein <a>, noch nicht übernommene eine Schaltfläche (sie öffnen das Detail-Popup,
   siehe tmdbTitleCards.js) - daher auch hier die Rücknahme der Schaltflächen-Vorgaben. */
.tmdbTitleCardLink {
	background: none;
	border: none;
	cursor: pointer;
	inset: 0;
	padding: 0;
	position: absolute;
}

/* Die Schicht mit den Kennzeichen. Sie deckt genau die Posterfläche ab - gleiche Breite wie die Karte, gleiches
   Seitenverhältnis wie das Poster, oben angesetzt (Muster von .tmdbMissingMark) -, denn die Kennzeichen sitzen in
   den Ecken des Posters und dürfen nicht in den Kartenteil darunter rutschen (Titel und Meta-Zeile).

   Sie liegen deshalb nicht mehr im Poster selbst: Dieses rundet seine Ecken per overflow:hidden ab und schnitt
   damit auch die Tooltip-Blase ab. Ein z-index half dagegen nicht - Abschneiden durch overflow ist keine Frage
   der Stapelfolge (siehe positionTooltip in chrome.js).

   Durchlässig für den Zeiger, damit die freie Fläche zwischen den Kennzeichen weiterhin die Karte öffnet; nur die
   Kennzeichen selbst fangen ihn ab und zeigen ihren Tooltip. */
.tmdbTitleCardMarks {
	aspect-ratio: 2 / 3;
	left: 0;
	pointer-events: none;
	position: absolute;
	right: 0;
	top: 0;
	z-index: 1;
}

.tmdbTitleCardMarks > * {
	pointer-events: auto;
}

/* Rundet die Ecken selbst ab, weil die Karte darüber kein overflow:hidden tragen darf (s.o.): */
.tmdbTitleCardPoster {
	background: #0d1424;
	border-radius: 8px;
	display: block;
	overflow: hidden;
}

.tmdbTitleCardPoster img {
	aspect-ratio: 2 / 3;
	display: block;
	object-fit: cover;
	width: 100%;
}

/* Nur die Bildmaße übernehmen, nicht display:block wie beim <img> darüber: Das Platzhaltersymbol zentriert sich
   per display:flex (siehe .tmdbPosterPlaceholder) - mit block stand es zuvor oben links statt mittig. */
.tmdbTitleCardPoster .tmdbPosterPlaceholder {
	aspect-ratio: 2 / 3;
	width: 100%;
}

/* Lange Titel auf zwei Zeilen begrenzen, damit die Karten gleich hoch bleiben (wie bei den Videonamen).

   Dieselbe Schriftgröße wie auf den großen Kacheln der Übersichten (siehe .tmdbTileTitle): Wenn sie dort reicht,
   reicht sie hier erst recht - diese Karten sind schmaler, und der zuvor größere Titel verbrauchte gerade auf
   ihnen den knappen Platz. Bewusst nicht auf .tmdbCreditName übertragen: Die Karten von "Regie & Besetzung"
   bleiben, wie sie sind. */
.tmdbTitleCardName {
	display: -webkit-box;
	font-size: 0.85rem;
	font-weight: bold;
	margin-top: 0.4rem;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	overflow: hidden;
}

.tmdbTitleCardMeta {
	color: var(--text-muted);
	display: block;
	font-size: 0.8rem;
}

/* Die Rolle in diesem Titel - nur auf der Personenseite vorhanden, dort der Grund, warum er überhaupt erscheint.
   Auf zwei Zeilen begrenzt, damit die Karten gleich hoch bleiben.

   Bewusst nicht var(--text-faint): Das ist die Farbe abgeschalteter Bedienelemente und für Text schon auf einer
   normalen Karte zu schwach - auf einer gedämpften (siehe .tmdbTitleCard.notAdded) käme deren Deckkraft noch
   obendrauf und ließe ihn ganz verschwinden. */
.tmdbTitleCardRole {
	color: var(--text-muted);
	display: -webkit-box;
	font-size: 0.8rem;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	overflow: hidden;
}

/* Noch nicht übernommene Vorschläge gedämpft, mit derselben Regel wie die fehlenden Filme einer Filmreihe (siehe
   .tmdbTile.notAdded) - inklusive des Aufhellens beim Überfahren bzw. Antippen. */
.tmdbTitleCard.notAdded {
	opacity: 0.55;
}

.tmdbTitleCard.notAdded:hover {
	opacity: 1;
}

/* "Siehe auch" (siehe inc/tmdbMeta.html#relatedSection) ------------------------------------------------------

   Die Karte trägt keine eigenen Regeln mehr: Behälter, Verweis-Fläche und Kennzeichen-Schicht gelten inzwischen
   für alle Titelkarten (siehe .tmdbTitleCard). Die Schaltfläche zum Lösen liegt in derselben Schicht wie die
   Kennzeichen - ein <button> darf nicht in einem <a> stehen, und im Poster selbst darf sie nicht sitzen. */

/* Symbol und Text der Überschrift auseinanderhalten - der Text schließt sonst unmittelbar an die Kette an. Nur
   hier, weil die übrigen Kartenreihen keine Überschrift mit Symbol tragen. */
.tmdbRelatedHeading {
	align-items: center;
	display: flex;
	gap: 0.45rem;
}

/* Sagt, ob der Verweis auf einen Film, eine Filmreihe oder eine Serie zeigt - in dieser Reihe stehen alle drei
   gemischt. Unten links, weil oben je nach Eintrag schon "gesammelt" und "gesehen" stehen und unten rechts das
   Lösen-Zeichen sitzt. Gedämpftes Grau statt einer eigenen Farbe: Die Angabe ordnet nur ein, sie meldet nichts. */
.tmdbBadge.tmdbTypeMark {
	bottom: 0.4rem;
	color: #aab;
	left: 0.4rem;
	position: absolute;
}

/* Unten rechts im Poster, gegenüber den Kennzeichen oben. Dauerhaft sichtbar und nicht erst beim Überfahren:
   Am Tablet - dem hauptsächlichen Gerät - gibt es kein Überfahren, die Schaltfläche wäre dort nicht auffindbar.
   Zurückhaltend genug, um das Poster nicht zu stören, und beim Überfahren deutlich.

   Sie liegt in der Kennzeichen-Schicht über der Verweis-Fläche (siehe .tmdbTitleCardMarks), sonst läge diese
   darüber und finge den Klick ab. */
.tmdbRelatedRemoveBtn {
	align-items: center;
	background: rgba(17,17,51,0.85);
	border: none;
	border-radius: 50%;
	bottom: 0.4rem;
	color: #bbc;
	cursor: pointer;
	display: flex;
	font-size: 0.8rem;
	height: 1.6rem;
	justify-content: center;
	padding: 0;
	position: absolute;
	right: 0.4rem;
	width: 1.6rem;
}

.tmdbRelatedRemoveBtn:hover {
	background: rgba(51,17,17,0.95);
	color: #f88;
}

/* Die Karte zum Hinzufügen ist als einzige der Reihe eine Schaltfläche, und die zentriert ihren Inhalt senkrecht.
   Da sie nur das Poster-Feld trägt (ohne Titel und Meta-Zeile), säße dieses sonst mittig neben den Postern der
   übrigen Karten statt auf gleicher Höhe. Als Spalte mit Ausrichtung nach oben beginnt ihr Inhalt wieder oben.

   Gilt nur für die Karte in der Reihe - derselbe Klassenname sitzt auch am Menüpunkt "Inhalte verknüpfen...",
   der ein gewöhnlicher Eintrag im "..."-Menü ist und dessen Aussehen behalten muss. */
.tmdbTitleCardRow .tmdbRelatedAddBtn {
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
}

/* Kein Poster, sondern ein gestrichelter Rahmen im Posterformat, damit die Reihe gleich hoch bleibt (Muster wie
   .tmdbTile.tmdbTileMuted). */
.tmdbRelatedAddPoster {
	align-items: center;
	aspect-ratio: 2 / 3;
	background: transparent;
	border: 2px dashed var(--line-subtle);
	border-radius: 8px;
	color: var(--text-muted);
	display: flex;
	font-size: 1.8rem;
	justify-content: center;
	width: 100%;
}

.tmdbRelatedAddBtn:hover .tmdbRelatedAddPoster {
	border-color: var(--text-muted);
	color: var(--text);
}

/* Trefferzeile im Verknüpfen-Dialog: Kontrollkästchen und Art-Zeichen links, Titel und Untertitel rechts daneben.
   Die Grundzeile ist eine Spalte (siehe .tmdbLinkResult), hier wird daraus eine Zeile mit eigener Textspalte.

   Die Zeile ist ein <label> zu einem unsichtbaren Kästchen (siehe .defaultCheckbox), damit ein Klick irgendwo in
   der Zeile umschaltet - nicht nur auf ein kleines Kästchen. */
.tmdbRelatedResult {
	align-items: center;
	flex-direction: row;
	gap: 0.6rem;
}

/* Das Kästchen wird vom Label gezeichnet, mit denselben Maßen und Farben wie .defaultCheckboxLabel::before -
   bewusst nachgebildet statt jene Regel mitzubenutzen: Die trägt eine Pillen-Optik (Rahmen, Polsterung,
   inline-flex), die einer Zeile über die volle Dialogbreite nicht steht. */
.tmdbRelatedResult::before {
	background-color: var(--page-bg);
	border: 1px solid var(--control-border);
	border-radius: 4px;
	content: "";
	display: inline-flex;
	flex-shrink: 0;
	height: 1em;
	justify-content: center;
	line-height: 1em;
	width: 1em;
}

.defaultCheckbox:checked + .tmdbRelatedResult::before {
	background-color: var(--control-border);
	color: #fff;
	content: "✓";
	font-weight: bold;
}

/* Angehakte Zeile wie eine ausgewählte hervorheben (dieselben Farben wie .tmdbLinkResult.active): */
.defaultCheckbox:checked + .tmdbRelatedResult {
	background: var(--control-bg-hover);
	color: var(--control-text-hover);
}

.defaultCheckbox:checked + .tmdbRelatedResult .tmdbLinkResultDesc,
.defaultCheckbox:checked + .tmdbRelatedResult .tmdbRelatedResultIcon {
	color: #dde;
}

/* Die getroffene Auswahl über den Schaltflächen - sie zeigt auch das, was nach einer neuen Suche nicht mehr in der
   Trefferliste steht, und ist der einzige Weg, es dort wieder herauszunehmen. */
.tmdbRelatedPicked {
	border-top: 1px solid var(--line-subtle);
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin-top: 0.6rem;
	padding-top: 0.6rem;
}

.tmdbRelatedPick {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	display: inline-flex;
	font-size: 0.85rem;
	gap: 0.35rem;
	max-width: 100%;
	padding: 0.2rem 0.3rem 0.2rem 0.5rem;
}

/* Lange Titel abschneiden statt die Pille über die Dialogbreite wachsen zu lassen: */
.tmdbRelatedPick > span {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.tmdbRelatedPick > button {
	background: none;
	border: none;
	color: var(--text-muted);
	cursor: pointer;
	display: flex;
	font-size: 0.9em;
	padding: 0.1rem;
}

.tmdbRelatedPick > button:hover {
	color: #f88;
}

/* "Auch untereinander verknüpfen" samt Ansage, wie viele Verknüpfungen daraus werden. Wie bei .tmdbRelatedPicked
   muss das display:none für das hidden-Attribut ausdrücklich gesetzt werden, sonst gewinnt das display:flex. */
.tmdbRelatedCrossRow {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 0.6rem;
}

.tmdbRelatedCrossHint {
	color: var(--text-muted);
	font-size: 0.8rem;
}

.tmdbRelatedResultText {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	min-width: 0;
}

/* Dieselbe zurückgenommene Farbe wie die Zeile darunter: Das Zeichen ordnet den Treffer ein, es ist nicht der
   Treffer selbst. Feste Breite, damit die Titel aller Zeilen bündig beginnen, auch wenn die Zeichen unterschiedlich
   breit sind. */
.tmdbRelatedResultIcon {
	color: #99a;
	flex: none;
	font-size: 1.25rem;
	text-align: center;
	width: 1.5rem;
}

/* Auf der ausgewählten Zeile mit aufhellen, sonst fiele das Grau auf dem helleren Untergrund ab (wie
   .tmdbLinkResult.active .tmdbLinkResultDesc). */
.tmdbLinkResult.active .tmdbRelatedResultIcon {
	color: #dde;
}

/* Erklärt im Verknüpfen-Dialog die beiden Eigenheiten, die man sonst erst durch Ausprobieren merkt: dass nur
   Vorhandenes verknüpfbar ist und dass die Verknüpfung beidseitig gilt (siehe inc/tmdbRelatedDialog.html). */
.tmdbRelatedHint {
	color: var(--text-muted);
	font-size: 0.8rem;
	margin: 0.4rem 0 0 0;
}

/* Eine Kartenreihe, die in jeder Breite eine Zeile hoch bleibt (siehe inc/tmdbMeta.html#titleCardSection, Parameter
   singleRow) - dieselbe Mechanik wie bei den Videos und aus demselben Grund: TMDBs Vorschläge stehen am Seitenende
   und sollen nicht umbrechend mehrere Bildschirmhöhen füllen. Die angeschnittene nächste Karte am rechten Rand
   zeigt an, dass es weitergeht. */
.tmdbTitleCardSectionSingle .tmdbTitleCardRow {
	flex-wrap: nowrap;
	overflow-x: auto;
	padding-bottom: 0.5rem;
	scroll-snap-type: x proximity;
}

.tmdbTitleCardSectionSingle .tmdbTitleCard {
	scroll-snap-align: start;
}

/* Auf der Startseite gilt das Wischen in jeder Breite, nicht nur am Handy: Dort stehen mehrere Reihen
   untereinander ("Neu gesammelt: Filme", "Neu in der Mediathek" usw.), und jede soll genau eine Zeile hoch sein -
   sonst schöbe eine einzelne umbrechende Reihe die folgenden aus dem Bild. Auf den Detailseiten bleibt es beim
   Umbruch, dort steht nur eine Reihe am Seitenende (siehe index.html, .homeCardRows).

   Die Regeln stehen bewusst hier statt in der 640px-Query darunter: So gewinnen sie dort nicht per Reihenfolge,
   sondern gelten schlicht immer - die Query bleibt für alle übrigen Reihen zuständig. */
.homeCardRows .tmdbTitleCardRow {
	flex-wrap: nowrap;
	overflow-x: auto;
	padding-bottom: 0.5rem;
	scroll-snap-type: x proximity;
}

.homeCardRows .tmdbTitleCard {
	scroll-snap-align: start;
}

/* Jede Reihe der Startseite bekommt denselben Karteireiter wie die Bereichsmarke darüber, nur in Grau: Fläche
   allein hinter der Überschrift, Unterkante als Linie weiter nach rechts. Die Linie endet an der Breite der
   Reihe - bei den nebeneinanderstehenden Kategorien zeichnet sie damit zugleich deren Spalte nach.

   Bewusst nur hier: Auf den Detailseiten ("Ähnliche Filme") und der Personenseite steht dasselbe Makro, dort
   bleibt es bei der schlichten Überschrift.

   Etwas kleiner als eine gewöhnliche Überschrift (Vorgabe des Browsers ist rund 1,17rem): Der Reiter benennt hier
   nur eine Reihe innerhalb eines Bereichs und steht damit eine Stufe unter dessen Marke - zwischen deren 0,85rem
   und der vollen Überschriftengröße. */
.homeCardRows .tmdbTitleCardSection h3 {
	border-bottom: 2px solid var(--home-row-label-color);
	display: block;
	font-size: 1rem;
	margin-bottom: 0.8rem;
}

.homeCardRows .tmdbTitleCardHeadingInner {
	align-items: center;
	background: var(--home-row-label-color);
	border-radius: 6px 6px 0 0;
	color: #fff;
	display: inline-flex;
	gap: 0.5rem;
	padding: 0.15rem 0.8rem;
}

/* Auf dem Reiter nie unterstreichen (die Vorgabe von .tmdbTitleCardHeadingLink): Eine Unterstreichung mitten
   auf der Fläche sähe nach Textlink aus und liefe zudem der Reiterkante darunter zuwider. Dass es anklickbar
   ist, zeigt stattdessen die aufgehellte Fläche - dieselbe Rückmeldung wie bei den Kacheln. */
.homeCardRows .tmdbTitleCardHeadingInner:hover {
	text-decoration: none;
}

.homeCardRows a.tmdbTitleCardHeadingInner:hover {
	filter: brightness(1.2);
}

/* Auf der farbigen Fläche taugt das Grau der Meta-Angaben nicht mehr - das Gruppensymbol tritt hier über eine
   abgeschwächte Weißstufe zurück, damit es gedämpft bleibt, ohne im Reiter zu verschwinden. */
.homeCardRows .tmdbTitleCardHeadingInner .tmdbTitleCardGroupIcon {
	color: rgba(255, 255, 255, 0.65);
}

/* Marke über den beiden Bereichen der Startseite ("Kategorien", "Neues", "Aktivitäten"): Sie benennt den Unterschied
   zwischen selbst zusammengestellten und automatisch gefüllten Reihen, der aus den Reihentiteln allein nicht
   hervorgeht.

   Beschriftet wie die senkrechten Balken der Gruppenkacheln darüber (siehe .tile-group-label), nur waagerecht.
   Die Fläche liegt bewusst nur hinter dem Text - als Karteireiter, dessen Unterkante sich als Linie über die
   ganze Breite fortsetzt. Eine durchgehend farbige Zeile wäre für eine bloße Bereichsmarke zu schwer. */
.homeRowsLabel {
	border-bottom: 2px solid var(--home-label-color);
	margin: 1.2rem 0 0 0;
}

.homeRowsLabel > span {
	background: var(--home-label-color);
	border-radius: 6px 6px 0 0;
	color: #fff;
	display: inline-block;
	font-size: 0.85rem;
	font-weight: bold;
	letter-spacing: 0.2em;
	padding: 0.2rem 0.9rem;
	text-transform: uppercase;
}

/* Die erste Reihe eines Bereichs bringt ihren eigenen Abstand mit (.tmdbTitleCardSection hat margin-top), der
   hier überschrieben wird: Unter der Marke steht bewusst mehr Luft als über ihr - die durchgezogene Linie hält
   den Bezug zum Bereich darunter ohnehin, während oben der Abstand zum vorigen Bereich genügt. */
.homeRowsLabel + * .tmdbTitleCardSection,
.homeRowsLabel + .tmdbTitleCardSection {
	margin-top: 1rem;
}

/* Kategorien sind oft kurz (zwei, drei Titel) und verschwendeten als eigene Zeile viel Platz. Sie stehen deshalb
   nebeneinander, sobald zwei nebeneinander passen.

   Ein Umbruch per flex-wrap reichte dafür nicht: Er kann nur der Reihe nach umbrechen, eine lange Kategorie in der
   Mitte zerriss also die kurzen um sie herum. Das Raster mit "dense" darf dagegen zurückgreifen und holt eine
   spätere kurze Reihe in eine Lücke, die eine lange vor ihr gelassen hat - die Reihenfolge der Kategorien bleibt
   damit die Vorgabe, ohne dass Löcher entstehen.

   Die Spalte ist eine Karte breit, der Abstand genau der zwischen zwei Karten (siehe .tmdbTitleCard und
   .tmdbTitleCardRow): Nur so deckt sich eine Spannweite von n Spalten ungefähr mit n Karten.

   minmax(..., 1fr) statt einer starren Breite, damit die Spalten den Rest unter sich aufteilen, der am rechten
   Rand nicht mehr für eine weitere reicht. Mit starren 7,5rem blieb er ungenutzt liegen, und eine Reihe über die
   volle Breite endete dadurch sichtbar früher als die Reihen darunter, die kein Raster verwenden. */
.homeCategoryRows {
	display: grid;
	gap: 0 0.8rem;
	grid-auto-flow: row dense;
	grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
}

/* Die Spannweite kommt als --span aus dem Template (eine Spalte je Karte, siehe HomeCategory#getColumnSpan). */
.homeCategoryCell {
	grid-column: span var(--span, 2);
	min-width: 0;
}

/* Lange Reihen nehmen die ganze Zeile, statt über viele Spalten zu spannen: Eine Spannweite größer als die
   Spaltenzahl ließe das Raster zusätzliche Spalten anlegen und die Seite seitlich überlaufen. "1 / -1" kann
   dagegen nie zu breit werden. */
.homeCategoryCell--full {
	grid-column: 1 / -1;
}

/* Ohne das schrumpfte eine Reihe nicht unter ihre Inhaltsbreite und liefe über den Rand, statt zu wischen. */
.homeCategoryCell .tmdbTitleCardSection {
	min-width: 0;
}

/* Der Platzhalter, solange der Mediathek-Block noch unterwegs ist (siehe homeRows.js): nur freigehaltene Höhe,
   keine sichtbare Fläche.

   Er trug zuerst --control-bg mit sanftem Puls und kam damit als hellblauer Kasten heraus - das ist die hellste
   Stufe der Staffelung (Seite 10% - Fläche 15% - Bedienelement 21%, siehe :root) und für Schaltflächen und
   Felder gedacht, nicht für eine Stelle, an der gerade gar nichts ist. Die halbe Sekunde, die er zu sehen ist,
   rechtfertigt keine Fläche, die heller ist als alles andere auf der Seite.

   Die Höhe bleibt, und zwar genau eine Kartenreihe - nicht alle sechs: Wie viele es werden, weiß erst die
   Antwort, und eine zu hoch geratene Fläche ließe die Bildlaufleiste erst lang und dann kurz werden. Sie hat
   außerdem eine zweite Aufgabe: Der IntersectionObserver hängt am umgebenden Block, und ein Element ohne jede
   Höhe ist ein Ziel ohne Fläche - das funktioniert, ist aber eine unnötig heikle Stelle. */
.homeRowsPlaceholder {
	height: 15rem;
}

@media (max-width: 640px) {
	.tmdbTitleCardRow {
		flex-wrap: nowrap;
		overflow-x: auto;
		padding-bottom: 0.5rem;
		scroll-snap-type: x proximity;
	}

	.tmdbTitleCard {
		scroll-snap-align: start;
	}

	/* Am Handy reicht die Breite für kein Nebeneinander: Jede Kategorie bekommt ihre Zeile, wie vor dem Raster.
	   Nötig auch deshalb, weil bei nur einer Rasterspalte eine Spannweite von zwei eine zusätzliche anlegte. */
	.homeCategoryCell {
		grid-column: 1 / -1;
	}
}

/* Der Übernehmen-Knopf im Detail-Popup, mit Abstand zum Text darüber: */
.tmdbDetailActions {
	margin-top: 0.8rem;
}

/* Personenseite --------------------------------------------------------------------------------- */

/* Das Foto steht wie das Poster der Filmdetailseite fest links neben den Angaben - deshalb nutzt die Seite auch
   deren .tmdbMovieDetailHero/.tmdbMovieDetailInfo, und hier ist nur die Breite zu setzen: */
.tmdbPersonPhoto {
	flex: none;
	width: 13rem;
}

.tmdbPersonPhoto img,
.tmdbPersonPhoto .tmdbPosterPlaceholder {
	aspect-ratio: 2 / 3;
	border-radius: 8px;
	object-fit: cover;
	width: 100%;
}

/* Biografien sind lang - begrenzte Zeilenlänge hält sie lesbar, statt sie über die volle Fensterbreite zu ziehen: */
.tmdbPersonBio {
	max-width: 70rem;
}



/* TMDB-/Trailer-Links auf den Detailseiten (Serie, Staffel, Filmreihe, Film) - größer als in den Kacheln und als
   Pills. Sie stehen am Ende der Meta-Zeile, daher inline-flex statt flex: als Block würden sie die Zeile sprengen. */
.tmdbDetailLinks {
	display: inline-flex;
	flex-wrap: wrap;
	gap: 0.6rem;
	margin-left: 0.6rem;
	vertical-align: middle;
}

.tmdbDetailLinks .tmdbExternalLink {
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 999px;
	color: var(--control-text);
	font-size: 0.9rem;
	gap: 0.35rem;
	padding: 0.4rem 0.9rem;
}

.tmdbDetailLinks .tmdbExternalLink:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Die Trailer-Pille behält ihren roten Akzent (siehe .tmdbYoutubeLink), sonst wären beide Pillen nicht mehr
   auseinanderzuhalten - die Spezifität von .tmdbDetailLinks .tmdbExternalLink überschreibt ihn sonst: */
.tmdbDetailLinks .tmdbYoutubeLink {
	background: #4a1c28;
	border-color: #b04a5a;
	color: #ffcfd6;
}

.tmdbDetailLinks .tmdbYoutubeLink:active {
	background: #7a2c3e;
	border-color: #e07a8a;
	color: #fff;
}

/* Der "Links"-Auslöser ist ein <button> (für das .moreFlyout-Menü, siehe chrome.js) statt eines <a> wie TMDB/Trailer -
   ".actions button i" (siehe oben) würde dessen Icon sonst mit höherer Spezifität auf 1.2rem festnageln und es
   größer wirken lassen als die Nachbar-Icons: */
.tmdbDetailLinks .tmdbExternalLink i {
	font-size: inherit;
}

/* Einheitliche Optik im TMDB-/Kategorien-Bereich ------------------------------------------------- */

/* Die Formensprache dieses Bereichs kennt zwei Bausteine: die Pille mit Beschriftung und den runden Button mit
   nur einem Icon (siehe .tmdbCrumbBack, .tmdbTitleNav, .tmdbBurgerBtn, .tmdbDetailLinks). Farben überall
   gleich: #1b2b52 auf #4a70b0, beim Drücken #2a4383 auf #7aa0e0.

   Runder Icon-Button als wiederverwendbare Klasse, für Stellen ohne eigene Regel: */
.tmdbIconBtn {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	cursor: pointer;
	display: inline-flex;
	font-size: 1.1rem;
	height: 2rem;
	justify-content: center;
	padding: 0;
	width: 2rem;
}

.tmdbIconBtn:active,
.tmdbIconBtn.active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Der Herunterladen-Knopf des Portals (siehe inc/tools.html#download_button) steht neben den beiden START-Knöpfen
   und muss deren Höhe teilen - die geben die Folgenkarte und die Aufnahmekarte mit 1,75rem vor, nicht .tmdbIconBtn
   mit seinen 2rem. Quadratisch, weil ein 32x28 großer Knopf mit halbem Radius keine Scheibe mehr ist, sondern eine
   Ellipse. Das Polster muss mit, sonst gewönne es aus der Kartenregel und schöbe die Breite wieder auseinander. */
/* Auf den Detailseiten passt die Grundgröße von .tmdbIconBtn (2rem) neben die Pillen daneben. In den beiden
   Karten - Aufnahmekarte und Folgenkarte - sind die Nachbarn dagegen eine Nummer kleiner (1,75rem), und die Höhe
   setzt dort schon die jeweilige Kartenregel; mitwandern muss nur die Breite, sonst bliebe aus der Scheibe eine
   Ellipse. Das Polster gehört mit dazu: Es gewönne sonst aus derselben Kartenregel. */
.recordingCardActions > button.downloadMovie,
.tmdbEpisodeActions > button.downloadMovie {
	flex: 0 0 auto;
	height: 1.75rem;
	padding: 0;
	width: 1.75rem;
}

/* Folgen-Karten: "Abspielen" und der TMDB-Link werden zu Pillen, die beiden reinen Icon-Schaltflächen rund.
   Eine Nummer kleiner als im Seitenkopf (1,75rem statt 2rem), weil sie auf der Karte zwischen Fließtext sitzen. */
.tmdbEpisodeActions {
	gap: 0.5rem;
}

/* align-items/display gehören mit hierher, auch wenn .playMovie und .tmdbExternalLink sie schon mitbringen: Die
   beiden Stream-Knöpfe stehen in den Folgenkacheln ausgeschrieben im Markup (siehe inc/tmdbEpisodeCard.html) und
   haben sonst nirgends eine Regel. Ohne Flex-Container wirkt das gap darunter nicht - Icon und Beschriftung klebten
   aneinander, während dieselben Knöpfe auf den Detailseiten (.tmdbRecordingChip) und unter /shares/ Luft hatten. */
.tmdbEpisodeActions .playMovie,
.tmdbEpisodeActions .streamMovie,
.tmdbEpisodeActions .streamExternal,
.tmdbEpisodeActions .tmdbExternalLink {
	align-items: center;
	background: var(--control-bg);
	display: inline-flex;
	flex: 0 0 auto;
	white-space: nowrap;
	border: 1px solid var(--control-border);
	border-radius: 999px;
	color: var(--control-text);
	font-size: 0.8rem;
	gap: 0.3rem;
	height: 1.75rem;
	padding: 0 0.8rem;
}

.tmdbEpisodeActions .playMovie:active,
.tmdbEpisodeActions .streamMovie:active,
.tmdbEpisodeActions .streamExternal:active,
.tmdbEpisodeActions .tmdbExternalLink:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

/* Die drei runden Schaltflächen oben rechts in der Folgenkachel: Gesehen, Details, "..."-Menü. Sie standen bis zum
   03.09.2026 unten in der Aktionszeile zwischen den Abspiel-Knöpfen und wirkten dort verloren. */
.tmdbEpisodeInfoTop .actions .toggleMoreFlyout,
.tmdbEpisodeInfoTop .tmdbEpisodeDetailsBtn,
.tmdbEpisodeInfoTop .tmdbToggleWatchedBtn {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: 50%;
	color: var(--control-text);
	display: inline-flex;
	height: 1.75rem;
	justify-content: center;
	padding: 0;
	width: 1.75rem;
}

.tmdbEpisodeInfoTop .actions .toggleMoreFlyout:active,
.tmdbEpisodeInfoTop .tmdbEpisodeDetailsBtn:active,
.tmdbEpisodeInfoTop .tmdbToggleWatchedBtn:active {
	background: var(--control-bg-hover);
	border-color: var(--control-border-hover);
	color: var(--control-text-hover);
}

.tmdbEpisodeInfoTop .actions .toggleMoreFlyout i,
.tmdbEpisodeInfoTop .tmdbEpisodeDetailsBtn i,
.tmdbEpisodeInfoTop .tmdbToggleWatchedBtn i {
	font-size: 1rem;
}



/* Konvertieren (siehe convert.js) --------------------------------------------------------------- */

/* Format und Ton untereinander gleich breit wie das Namensfeld. */
#convertDialog .defaultSelect {
	width: 100%;
}

/* Die Endung steht hinter dem Namen und folgt dem gewählten Format - getippt wird nur der Name. */
.convertNameRow {
	align-items: center;
	display: flex;
	gap: 0.4rem;
}

.convertNameRow .defaultInput {
	flex: 1;
	min-width: 0;
}

.convertExtension {
	color: var(--control-text);
	flex: none;
}

/* Was mit Bild und Ton passiert, als Aufzählung im Dialog - macht vorab sichtbar, ob Surround erhalten bleibt. */
.convertPlan {
	color: var(--control-text);
	font-size: 0.8rem;
	list-style: none;
	margin: 0.75rem 0 0 0;
	padding: 0;
}

.convertPlan li {
	padding: 0.15rem 0 0.15rem 1.1rem;
	position: relative;
}

.convertPlan li::before {
	color: var(--control-border-hover);
	content: "\2022";
	left: 0.25rem;
	position: absolute;
}

/* Bei YouTube-Downloads können bis zu 27 Sprachen in der .smi stecken - deshalb begrenzte Höhe mit Scrollen,
   damit der Dialog nicht über den Bildschirm hinauswächst. */
.convertLanguages {
	max-height: 11rem;
	margin-top: 0.25rem;
	overflow-y: auto;
}

/* Fortschrittsanzeige, die einen Seitenwechsel überlebt: fest am unteren Rand, über allem außer Dialogen. */
/* Gemeinsamer Kasten für laufende Hintergrundaufträge (Konvertieren, Clips, TMDB-Ordner-Scan) - siehe base.html. Alle
   Module rendern ihre Einträge in einen eigenen Unterbereich, liegen aber im selben Kasten, damit sie sich in der
   Ecke nicht überlagern. */
.jobProgress {
	background: var(--surface-dialog);
	border: 1px solid var(--line);
	border-radius: var(--field-radius);
	bottom: 1rem;
	box-shadow: 0 4px 16px rgba(0,0,0,0.5);
	left: 1rem;
	max-width: 22rem;
	padding: 0.6rem 0.75rem;
	position: fixed;
	z-index: 900;
}

.jobProgressEntry + .jobProgressEntry {
	margin-top: 0.6rem;
}

/* Gleicher Abstand auch zwischen den beiden Bereichen, wenn Umwandlung und Scan gleichzeitig laufen: */
#convertProgress:not(:empty) + #tmdbScanProgress:not(:empty) {
	margin-top: 0.6rem;
}

.jobProgressTitle {
	color: var(--control-text);
	display: block;
	font-size: 0.75rem;
	margin-bottom: 0.35rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Oben statt unten: unten überlagert ein fest positionierter Knopf auf schmalen Bildschirmen die Aktionsschaltflächen
   der letzten sichtbaren Tabellenzeile (z.B. Timer) und macht sie unerreichbar. Der Abstand richtet sich nach der
   4rem hohen Kopfzeile, die ihrerseits fixiert ist - siehe die engere Fassung für schmale Bildschirme unten.
   Ein-/Ausblenden per Klasse statt [hidden]: chrome.js schaltet "show" abhängig vom Scrollstand, und nur über
   opacity/visibility lässt sich das Erscheinen weich animieren statt abrupt zu springen. */
.scrollTopBtn {
	align-items: center;
	background: var(--surface-dialog);
	border: 1px solid var(--line);
	border-radius: 50%;
	box-shadow: 0 4px 16px rgba(0,0,0,0.5);
	color: var(--control-text);
	cursor: pointer;
	display: flex;
	font-size: 1.2rem;
	height: 2.75rem;
	justify-content: center;
	opacity: 0;
	pointer-events: none;
	position: fixed;
	right: 1rem;
	top: 4.75rem;
	transition: opacity 0.2s;
	visibility: hidden;
	width: 2.75rem;
	z-index: 9;
}

@media (max-width: 640px) {
	/* Die Kopfzeile ist hier nur 3rem hoch (siehe header), der Knopf rückt entsprechend näher heran. */
	.scrollTopBtn {
		top: 3.75rem;
	}
}

.scrollTopBtn.show {
	opacity: 1;
	pointer-events: auto;
	visibility: visible;
}

.jobProgressBar {
	background: var(--control-bg);
	border-radius: var(--control-radius);
	display: block;
	height: 0.4rem;
	overflow: hidden;
}

.jobProgressBarFill {
	background: var(--control-border-hover);
	display: block;
	height: 100%;
	transition: width 0.3s ease;
}

/* "Stoppen" unter dem Fortschrittsbalken des Ordner-Scans: klein und unaufdringlich, der Kasten ist nur eine
   Nebenanzeige. Rechtsbündig, damit er nicht wie eine Beschriftung des Balkens wirkt. */
.jobProgressActions {
	display: flex;
	justify-content: flex-end;
	margin-top: 0.4rem;
}

.jobProgressActions .defaultBtn {
	font-size: 0.72rem;
	padding: 0.2rem 0.5rem;
}

/* Warnung im Umwandeln-Dialog, wenn die Box das Bildformat gar nicht abspielen kann (siehe MediaInfo#getVideoWarning).
   Bewusst auffällig: Ohne sie verspricht der Dialog mit "wird unverändert übernommen" eine Lösung, die es nicht gibt. */
.convertWarning {
	background: rgba(200,120,40,0.14);
	border: 1px solid #c87828;
	border-radius: var(--field-radius);
	color: #f0c088;
	font-size: 0.78rem;
	margin: 0.75rem 0 0 0;
	padding: 0.5rem 0.6rem;
}

/* Kachelfarbe einer Liste bzw. Kategorie ------------------------------------------------------------------- */

/* Eine Kachel kann eine Farbe tragen (siehe TileColors); gespeichert ist deren Name, wie sie aussieht steht
   allein hier - deshalb ließ sich das Aussehen einmal komplett austauschen, ohne eine einzige Kachel anzufassen.

   Gefärbt sind Rahmen und Symbol, die Fläche bleibt unverändert. Zwei Entwürfe davor sind verworfen: eine getönte
   Fläche legte sich wie ein Schleier über die Kachel, statt sie zu kennzeichnen; ein Farbbalken an der linken Kante
   (wie bei den Gruppenkacheln der Startseite, siehe .tile-group-label) ließ die Reihe ungleichmäßig aussehen, weil
   ihn nur die Kacheln mit Farbe tragen - ein Rahmen fällt an dieser Stelle nicht auf, weil ohnehin jede Kachel einen
   hat und sich nur seine Farbe ändert.

   Zwei Töne je Farbe, wie es die Bereichsfarben in :root vormachen: der gedeckte und der aufgehellte. Sichtbar ist
   zurzeit nur der helle (Rahmen und Symbol); der gedeckte steht bereit, falls die Fläche später doch Farbe bekommen
   soll. Die ersten drei Farben sind genau jene Bereichsfarben, die übrigen sind an ihnen ausgerichtet (Helligkeit
   um 40%, Sättigung 20-40%) - so bleibt eine Seite voller farbiger Kacheln ruhig. */
/* Der Standard - eine Kachel ohne eigene Farbe. Sie trägt das Blau, das die Kachelsymbole ohnehin haben (siehe
   ".content .tile .tileIcon"), und ist damit zugleich die blaue Farbe der Auswahl: Ein eigener Eintrag "Blau" stand
   direkt daneben und war von ihm kaum zu unterscheiden. Die Werte stehen auf allen Kacheln und allen Farbtupfern,
   die Einträge darunter überschreiben sie - so gilt eine Regel für gefärbte und ungefärbte gleichermaßen. */
.categoryTile,
.mediaListTile,
.colorPicker label {
	--category-color:        var(--group-recording);
	--category-color-bright: #68c;
}

.categoryTile[data-color="teal"],
.mediaListTile[data-color="teal"],
.colorPicker label[data-color="teal"] {
	--category-color:        #3f7078;
	--category-color-bright: #6fbfc4;
}

.categoryTile[data-color="green"],
.mediaListTile[data-color="green"],
.colorPicker label[data-color="green"] {
	--category-color:        var(--group-mediathek);
	--category-color-bright: var(--group-mediathek-bright);
}

.categoryTile[data-color="sand"],
.mediaListTile[data-color="sand"],
.colorPicker label[data-color="sand"] {
	--category-color:        var(--group-misc);
	--category-color-bright: var(--group-misc-bright);
}

.categoryTile[data-color="orange"],
.mediaListTile[data-color="orange"],
.colorPicker label[data-color="orange"] {
	--category-color:        #8a5f3c;
	--category-color-bright: #d99a5c;
}

.categoryTile[data-color="red"],
.mediaListTile[data-color="red"],
.colorPicker label[data-color="red"] {
	--category-color:        #8a4a52;
	--category-color-bright: #d9707c;
}

.categoryTile[data-color="purple"],
.mediaListTile[data-color="purple"],
.colorPicker label[data-color="purple"] {
	--category-color:        #61527a;
	--category-color-bright: var(--accent-collection);
}

/* Die beiden unbunten. Grau ist der Blaugrauton der Trennlinien (--line), damit es nicht als Fremdkörper neben den
   leicht blaustichigen Farben oben steht; "Weiß" ist bewusst kein reines #fff, sondern trägt denselben Hauch Blau -
   auf der dunklen Fläche liest es sich trotzdem als Weiß und leuchtet nicht wie eine Warnung. */
.categoryTile[data-color="gray"],
.mediaListTile[data-color="gray"],
.colorPicker label[data-color="gray"] {
	--category-color:        var(--line);
	--category-color-bright: #9aa4b8;
}

.categoryTile[data-color="white"],
.mediaListTile[data-color="white"],
.colorPicker label[data-color="white"] {
	--category-color:        #8892a8;
	--category-color-bright: #e9edf6;
}

/* Der Rahmen trägt den *gedeckten* Ton, das Symbol den hellen - dafür gibt es die beiden Werte je Farbe. Mit dem
   hellen an beiden Stellen wurde die Kachel als Ganzes zur farbigen Karte; das war deutlich, aber unruhiger als der
   Rest der Anwendung. So bleibt die Farbe am Symbol ablesbar und der Rahmen sagt sie nur leise mit.

   Ohne [data-color]: Das gilt auch für die Kacheln ohne eigene Farbe - sonst wäre der Rahmen überall in der Farbe,
   nur bei ihnen nicht, und gerade das fiele auf. Der Symbol-Selektor braucht die drei Klassen, um
   ".content .tile .tileIcon" zu schlagen (gleiche Spezifität, entschieden durch die spätere Stelle). */
.content .categoryTile,
.content .mediaListTile {
	border-color: var(--category-color);
}

.content .categoryTile .tileIcon,
.content .mediaListTile .tileIcon {
	color: var(--category-color-bright);
}

/* Die Auswahl im Bearbeiten-Dialog: dieselben Maße wie die Icon-Auswahl darunter, damit beide Reihen im selben
   Dialog ein Raster ergeben (siehe .iconPicker). Der Tupfer trägt den hellen Ton - also genau den, den Rahmen und
   Symbol der Kachel bekommen. */
.colorPicker {
	display: flex;
	flex-wrap: wrap;
	/* Breiter als die Icon-Auswahl darunter (22rem), damit die zehn Tupfer auf einem Rechner in *eine* Reihe passen -
	   als solche war die Farbwahl gedacht. Auf dem Handy ist der Dialog schmaler, dort bricht sie wie gehabt um. */
	gap: 0.4rem;
	max-width: 25rem;
}

.colorPicker label {
	align-items: center;
	display: flex;
	height: 2rem;
	justify-content: center;
	padding: 0;
	width: 2rem;
}

.colorPicker .colorSwatch {
	background: var(--category-color-bright);
	border: 1px solid var(--category-color-bright);
	border-radius: 50%;
	display: block;
	height: 1.1rem;
	width: 1.1rem;
}

/* EPG: Ansichten ------------------------------------------------------------------------------- */

/* Die Reiterzeile über der Bedienleiste. Wie auf der Suchseite darf sie auf dem Handy nicht umbrechen - die
   Pille wäre sonst zerrissen -, also wird sie geschoben. Beide Klassen im Selektor mit Absicht: .segmentedToggle
   setzt weiter oben overflow:hidden, und bei gleicher Spezifität gewänne die spätere Regel. */
.segmentedToggle.epgViewTabs {
	/* Ein Abstand nach oben, keiner nach unten - beides hängt daran, dass die Überschrift der Seite keinen Platz
	   mehr einnimmt (siehe .visuallyHidden): Ohne den oberen klebte die Reiterzeile unmittelbar an der Kopfzeile.
	   Der untere dagegen käme zum margin-top der Leiste hinzu, statt mit ihm zu verschmelzen - .segmentedToggle
	   ist inline-flex, und Ränder inline-hoher Elemente verschmelzen nicht mit denen ihrer Nachbarn; gemessen
	   waren es 25px gegen 16px weiter unten. So liegt die ganze Seite bei gleichmäßigen 16px. */
	margin-bottom: 0;
	margin-top: 1em;
	max-width: 100%;
	overflow: auto hidden;
}

/* ... aber nicht auf schmalen Geräten: Dort bekommt .content ein padding-top von 0,75rem, und beides zusammen
   ergab 26px über der Reiterzeile statt der 14px auf großen Schirmen. Den Abstand setzt hier der Innenabstand des
   Inhaltsbereichs allein.
   Diese Regel muss NACH der obigen stehen, nicht bei den übrigen EPG-Regeln weiter oben in der Datei: Beide haben
   dieselbe Spezifität, und dann gewinnt die spätere - dort platziert blieb sie wirkungslos. */
@media (max-width: 640px) {
	.segmentedToggle.epgViewTabs {
		margin-top: 0;
	}
}

/* Reiterzeile und "…"-Menü in einer Zeile. Den Abstand nach oben (siehe oben) trägt dann die Zeile; die Reiter
   dürfen schrumpfen und scrollen weiterhin in sich, statt das Menü aus dem Bild zu schieben. */
.epgHeadRow {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	margin-top: 1em;
}

.epgHeadRow .segmentedToggle.epgViewTabs {
	flex: 0 1 auto;
	margin-top: 0;
	min-width: 0;
}

@media (max-width: 640px) {
	.epgHeadRow {
		margin-top: 0;
	}
}

.epgViewTabs .seg-btn {
	flex-shrink: 0;
}

/* Bedienelemente, die nur zu einer Ansicht gehören.
   display:flex und nicht nur "sichtbar/unsichtbar": Diese Gruppe ist ein Flex-Element der Leiste, aber ohne die
   Angabe selbst keines - ihre Knöpfe richteten sich dann an der Schriftgrundlinie aus und saßen zwei Pixel höher
   als ihre Nachbarn außerhalb der Gruppe.
   Die hidden-Regel ist nötig, weil das Attribut allein hier nichts ausrichtet: .smallBtn setzt
   display:inline-flex, und jede Author-Regel schlägt hidden (dieselbe Falle wie bei .shareLinkVideo und beim
   Schnellzugriff). Sichtbar war dadurch der Aktualisieren-Knopf auch im Jetzt-Raster, wo es gar keinen einzelnen
   Sender gibt. */
span.epgViewOnly {
	align-items: center;
	display: flex;
	/* Auch diese Gruppe muss umbrechen dürfen, nicht nur die Leiste um sie herum: Sender-Auswahl, die beiden
	   Pfeile und die zwei Live-Knöpfe sind zusammen 395px breit und passten damit in kein Telefon - der letzte
	   Knopf ragte 13px über den Rand. Ein flex-wrap auf der Leiste allein hilft nicht, weil ein Flex-Element nur
	   als Ganzes umbricht. */
	flex-wrap: wrap;
	gap: 0.5em;
}

/* Während eine Ansicht geholt wird, bleibt die alte stehen und wird gedämpft: Ein leerer Bereich für einen
   Bruchteil einer Sekunde flackert mehr, als er erklärt. */
.epgLoading {
	opacity: 0.5;
	pointer-events: none;
}

/* Das Jetzt-Raster. Etwas breitere Kacheln als die Listen-Seite, weil hier zwei Sendungstitel untereinander
   stehen und nicht ein Ordnername. */
/* Auf dem Telefon gibt es das Zeitraster nicht: Ein Raster über viele Sender braucht Breite, und eine
   verstümmelte Fassung mit zwei Spalten beantwortet die Frage nicht mehr, für die es da ist ("was läuft heute
   Abend wo?"). Der Reiter verschwindet, und epgViews.js fällt dann auf "Jetzt" zurück. */
@media (max-width: 640px) {
	.epgViewTabs .epgGridTab {
		display: none;
	}
}

/* Das Zeitraster ---------------------------------------------------------------------------------
   Sender als Spalten, die Zeit läuft nach unten. Waagerecht wird geschoben, weil ein Bouquet mehr Sender hat, als
   nebeneinander passen; die Spaltenbreite ist fest, damit die Spalten beim Schieben nicht ihre Breite ändern. */
/* Ein Block, kein Flex-Container: Die Spalten liegen in den Abschnitten (.epgGridSection), die ihrerseits Flex
   sind - hier draußen wird es nicht gebraucht. Und es schadete: Als Flex-Item wurde .epgGridInner auf die Höhe
   dieses Bereichs gestaucht (gemessen 768px bei 2.966px Inhalt), womit der sticky-Bereich der Sendernamen dort
   endete - sie lösten sich beim Scrollen etwa ab dem zweiten Bildschirm. */
.epgGrid {
	overflow-x: auto;
	padding-bottom: 0.5rem;
	/* Bezugspunkt für das gemeinsame Menü der Sendungen (siehe .epgGridMenu): So liegt es an seiner Kachel und
	   wandert beim Scrollen mit, statt an der Seite zu kleben. */
	position: relative;
}

/* Ein Menü für alle Sendungen des Rasters, von epgViews.js gefüllt und unter die angetippte Kachel gesetzt.
   Fest am Bildschirm, weil es außerhalb des Rasters im Markup steht (siehe epg.html) - beim nächsten Klick
   schließt es ohnehin. */
.epgGridMenu {
	position: fixed;
	z-index: 9;
}

/* Linksbündig unter der Kachel: Die allgemeine Regel richtet ein .moreFlyout am rechten Rand seines Wrappers aus
   (right: 0), was hier - wo der Wrapper keine Breite hat - nach links aus dem Bild lief. */
.epgGridMenu .moreFlyout {
	/* Dunkler als die Kacheln, auf denen es liegt - die tragen --surface-raised, und genau die trägt ein
	   .moreFlyout sonst auch. Diese Kombination gibt es nirgends sonst: Überall anders liegt ein Flyout über
	   der dunkleren Seitenfläche. Mit der Dialogfarbe kehrt sich das Verhältnis um, statt es aufzuheben.
	   Ein Schatten allein reichte nicht, nachgeprüft - er zeichnet nur die Kante nach, nicht die Fläche. */
	background-color: var(--surface-dialog);
	/* Ein Schlagschatten, den die Menüs sonst nicht brauchen: Überall sonst liegt ein Flyout über der dunkleren
	   Seitenfläche und hebt sich schon durch seine Farbe ab - hier liegt es auf den Kacheln des Rasters, und die
	   tragen dieselbe. Ohne den Schatten war kaum zu sehen, dass da ein Menü aufgegangen ist.
	   Der Schatten statt einer anderen Farbe, weil so beides bleibt, wie es sein soll: die hellen Kacheln und das
	   Menü im Stil aller anderen. */
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
	left: 0;
	right: auto;
}

/* Der Inhalt ist so breit wie alle Spalten zusammen - ohne das würden Kopfzeile und Abschnitte einzeln auf die
   Fensterbreite gestaucht, statt gemeinsam zu schieben. */
.epgGridInner {
	width: max-content;
}

/* Im Raster bleibt der Kopf der Seite stehen: Reiterzeile und Bedienleiste über den Sendernamen, die ihrerseits
   schon haften. Ohne das scrollt man beim langen Blättern durch mehrere Tage an allem vorbei, was man zum
   Weiterarbeiten braucht - und der Tages-Knopf, dessen Beschriftung mitläuft, wäre gerade dann nicht zu sehen,
   wenn er etwas zu sagen hat. Nur hier und nicht seitenweit: Die übrigen Ansichten sind kurz genug. */
/* Im Raster scrollt der Rasterbereich selbst, nicht die Seite. Reiterzeile und Bedienleiste stehen dadurch von
   ganz allein fest - sie sind schlicht außerhalb des scrollenden Bereichs.
   Mit "sticky" ging das nicht: Die Kopfzeile der Seite ist "fixed" und 64px hoch, ein sticky-Element mit top:0
   klebte also dahinter; und .epgGrid trägt wegen des seitlichen Schiebens ein overflow:auto, womit es selbst zum
   scrollenden Vorfahren der Sendernamen wird - deren sticky bezog sich damit auf einen Bereich, der vertikal gar
   nicht scrollt, und griff nie. Beides ist hier erledigt, und der seitliche Stand bleibt beim Nachladen erhalten
   (siehe epgViews.js), statt zurückzuspringen. */
#epgPage.epgGridActive .epgGrid {
	height: calc(100vh - var(--epg-grid-top, 12rem));
	overflow: auto;
}

/* Sendernamen und Abschnitte benutzen dieselben Spaltenmaße, damit sie beim Schieben untereinander bleiben. */
.epgGridHeads,
.epgGridSection {
	display: flex;
	gap: 0.5rem;
}

.epgGridColumn {
	display: flex;
	flex-direction: column;
	flex-shrink: 0;
	/* Kein gap: Die Höhe jeder Sendung ist ausgerechnet (siehe EpgPage#distribute), und ihre Summe ergibt genau
	   die Höhe des Abschnitts. Ein Abstand dazwischen käme obendrauf - die Spalte ragte über ihren Abschnitt
	   hinaus, ohne ihn zu vergrößern, und damit war der ganze Rasterbereich zu kurz: Die Sendernamen lösten sich
	   beim Scrollen, weil ihr sticky am Ende des zu kurzen Elternelements endete. Getrennt wird stattdessen mit
	   einem Rahmen, der dank border-box in der Höhe steckt. */
	gap: 0;
	width: 13rem;
}

.epgGridHeads .epgGridHead {
	flex-shrink: 0;
	width: 13rem;
}

/* Die Sendernamen bleiben beim senkrechten Scrollen stehen - ohne das weiß man nach zwei Abschnitten nicht mehr,
   wessen Programm man liest. Der Hintergrund ist nötig, weil die Sendungen sonst darunter durchscheinen. */
.epgGridHeads {
	background-color: var(--surface);
	margin-bottom: 0.5rem;
	position: sticky;
	top: 0;
	z-index: 3;
}

.epgGridHead {
	background-color: var(--surface-raised);
	border-bottom: 1px solid var(--control-border);
	border-radius: var(--field-radius) var(--field-radius) 0 0;
	padding: 0.4rem 0.5rem;
}

/* Über die volle Spaltenbreite, damit das Senderlogo rechts andocken kann (siehe .epgPicon) - als inline-flex wäre
   der Knopf nur so breit wie sein Text, und "rechtsbündig" bezöge sich auf nichts. */
.epgGridHead .epgNowChannelBtn {
	width: 100%;
}

/* Die Tagesüberschrift zieht sich über alle Spalten - wie der Seitenkopf einer Fernsehzeitschrift. Sie ist der
   Grund, warum das Raster aus Abschnitten besteht und nicht aus durchgehenden Spalten: In einer Spaltenstruktur
   gäbe es keine Zeile, die quer darüber laufen könnte. */
.epgGridDay {
	border-bottom: 1px solid var(--control-border);
	color: var(--accent-collected);
	font-size: 0.8rem;
	font-weight: bold;
	letter-spacing: 0.05em;
	margin: 0.75rem 0 0.5rem;
	padding-bottom: 0.3rem;
	text-transform: uppercase;
}

/* Der TEXT klebt am linken Rand, nicht die Zeile. Die Zeile ist so breit wie alle Spalten zusammen (gemessen
   8.416px), ein sticky auf ihr bewirkt deshalb nichts Sichtbares: Sie bleibt zwar stehen, aber ihr Text sitzt an
   ihrem linken Ende und wandert beim seitlichen Schieben mit hinaus. Erst das innere Element hält ihn im Bild -
   damit steht die Tagesangabe auch dann noch da, wenn man bei den hinteren Sendern liest. */
.epgGridDay > span {
	display: inline-block;
	left: 0;
	position: sticky;
}

.epgGridSection + .epgGridSection {
	margin-top: 0.5rem;
}

/* Die Tage im Auswahl-Flyout: dieselbe Form wie ein Eintrag im "..."-Menü (siehe .actions .moreFlyout button) -
   ohne eigene Regel kämen sie als rohe Schaltflächen des Browsers heraus, also weiß auf weiß im dunklen Bild. */
.filterFlyoutPanel .epgGridDayChoice {
	/* Linksbündig wie die Einträge eines "..."-Menüs - bei acht verschieden langen Tagesnamen sieht zentriert
	   ungeordnet aus. Es braucht justify-content und nicht text-align: Der Knopf ist von anderer Stelle her ein
	   Flex-Element, und dort richtet nicht text-align den Inhalt aus, sondern justify-content. Genau daran ist
	   ein text-align hier zweimal wirkungslos abgeprallt. */
	justify-content: flex-start;
	text-align: left;
}

.epgGridDayChoice {
	background: none;
	border: 0;
	border-radius: 6px;
	color: var(--control-text);
	cursor: pointer;
	font-family: inherit;
	font-size: 0.85rem;
	padding: 0.4em 0.75em;
	text-align: left;
	white-space: nowrap;
	width: 100%;
}

.epgGridDayChoice:hover,
.epgGridDayChoice:active {
	background-color: rgba(102, 153, 221, 0.2);
	color: #fff;
}

.epgGridMore,
.epgGridEnd {
	color: var(--text-muted);
	font-size: 0.8rem;
	left: 0;
	margin-top: 1rem;
	padding: 0.75rem 0;
	position: sticky;
	text-align: center;
	width: 100%;
}

.epgGridSlot {
	align-items: flex-start;
	/* Heller als die Kacheln der Anwendung sonst (--surface), und das ist geprüft: Am 15.09.2026 einmal auf den
	   dunkleren Ton umgestellt und wieder zurückgenommen - im Raster liegen die Flächen dicht beieinander und
	   verlieren dunkel ihre Abgrenzung, dann bräuchte jede einen Rahmen. Die Jetzt-Kacheln daneben bleiben
	   umgekehrt beim dunklen Ton: Die stehen einzeln und sind ohnehin deutlich abgesetzt. */
	background-color: var(--surface-raised);
	/* Der Rahmen ist der Abstand zur nächsten Sendung, und er muss durchsichtig BLEIBEN: Ein Hintergrund reicht
	   normalerweise bis zur Außenkante des Rahmens und füllte ihn wieder auf - die Kacheln stießen dann
	   unsichtbar aneinander. Mit padding-box endet er am Innenrand, und der Rahmen zeigt den Untergrund.
	   Abstand über den Rahmen und nicht über margin oder gap, weil nur er dank border-box in der ausgerechneten
	   Höhe steckt - alles andere käme obendrauf und schöbe die Spalte über ihren Abschnitt hinaus. */
	background-clip: padding-box;
	border: 2px solid transparent;
	border-bottom-width: 3px;
	border-radius: var(--field-radius);
	color: var(--text-normal);
	cursor: pointer;
	display: flex;
	flex-direction: column;
	font-family: inherit;
	/* Kein Zwischenraum zwischen Titelzeile und Beschreibung: Die 1,6px entschieden darüber, ob eine
	   Beschreibung noch hineinpasst - bei 46px hohen Kacheln ("heute journal", "37 Grad") fehlten genau sie.
	   Die Zeilenhöhe von 1,2 lässt ohnehin genug Luft. */
	gap: 0;
	/* Der Inhalt wird abgeschnitten, nicht die Höhe gedehnt: Die Höhe sagt hier etwas aus (die Dauer), und ein
	   langer Titel darf diese Aussage nicht verfälschen. */
	overflow: hidden;
	padding: 0.35rem 0.5rem;
	text-align: left;
}

/* Hervorhebung und Zeigerkontakt als aufgelegte Linie, nicht über die Rahmenfarbe: Der Rahmen ist hier der
   Abstand zwischen den Kacheln, ein eingefärbter machte ihn zum dicken Strich.
   Und als Pseudo-Element statt als inset-Schatten, weil ein Schatten HINTER dem Inhalt liegt: Ein Titel, den die
   Kachel unten abschneidet, schnitt dann mitten durch die Linie. So liegt sie darüber und schließt die Kachel
   sichtbar ab. */
.epgGridSlot::after {
	border-radius: inherit;
	content: "";
	inset: 0;
	pointer-events: none;
	position: absolute;
}

.epgGridSlot {
	position: relative;
}

.epgGridSlot:hover::after {
	border: 1px solid var(--control-border);
}

/* Was gerade läuft, ist der Bezugspunkt beim Hinsehen - dieselbe Farbe wie der Fortschrittsbalken darunter. */
.epgGridRunning::after {
	border: 1px solid var(--accent-collected);
}

.epgGridTime {
	color: var(--text-muted);
	flex-shrink: 0;
	font-size: 0.75rem;
	/* Auf der Grundlinie des Titels, nicht am oberen Rand: Sie ist kleiner gesetzt und schwämme sonst oben. */
	line-height: 1.35;
}

/* Uhrzeit und Titel stehen nebeneinander, nicht untereinander - das halbiert die Höhe einer kurzen Sendung, und
   die kurzen sind es, die den ganzen Abschnitt in die Länge ziehen (alle Spalten darin sind gleich hoch, also
   bestimmt der dichteste Sender die Höhe für alle). Die Uhrzeit gibt nicht nach, der Titel schon. */
.epgGridLine {
	display: flex;
	gap: 0.4rem;
	line-height: 1.2;
}

.epgGridTitle {
	/* Lange Titel werden mit Auslassungspunkten gekürzt statt an der Kante abgeschnitten - die Höhe steht hier
	   für die Dauer und darf sich nicht nach dem Text richten. */
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
	display: -webkit-box;
	font-size: 0.85rem;
	font-weight: bold;
	line-height: 1.2;
	min-width: 0;
	overflow: hidden;
}

.epgGridDesc {
	color: var(--text-muted);
	font-size: 0.75rem;
	line-height: 1.2;
}

.epgGridEmpty {
	color: var(--text-muted);
	font-size: 0.8rem;
	padding: 0.5rem;
}

/* Die Spaltenbreite des Jetzt-Rasters. Bis zum 27.09.2026 stand hier ".epgNowGrid" allein und verlor gegen
   ".content .tiles--grid" (zwei Klassen gegen eine) - wirksam war also dessen "15vw, mindestens 9rem", und das gab in
   jeder Lage fünf Spalten: auf dem Tablet hochkant fünf Kacheln in Handybreite. Jetzt mit beiden Klassen, damit die
   Regel auch gilt, und mit drei Grenzen:
   - 15vw bleibt die Breite auf großen Schirmen, damit sich dort nichts ändert (quer auf dem Tablet 5 Spalten,
     ebenso am Desktop);
   - 14rem ist die Untergrenze darunter: hochkant auf dem Tablet werden es 3 Spalten, so breit wie quer;
   - 47% hält das Handy bei zwei Spalten. */
.content .tiles--grid.epgNowGrid {
	grid-template-columns: repeat(auto-fill, minmax(min(max(15vw, 14rem), 47%), 1fr));
}

/* Linksbündig und knapp: Hier stehen vier Zeilen Text untereinander, und zentriert liest sich das wie ein
   Plakat statt wie eine Liste. ".content .tile" setzt text-align:center für die Kachelseiten der Anwendung -
   dort ist es richtig, hier nicht.
   Je flacher die Kachel, desto mehr Sender passen auf den Schirm, und genau darum geht es in dieser Ansicht. */
.content .tile.epgNowTile {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	padding: 0.55rem 0.7rem;
	/* Kein overflow:hidden - das schnitte das Flyout der Kachel ab (siehe .tmdbTile). */
	position: relative;
	text-align: left;
}

/* Der Sendername führt in die Tabelle dieses Senders. Als Schaltfläche und nicht als Link, weil der Wechsel
   keine Navigation ist, sondern ein Austausch des Inhalts. */
.epgNowChannelBtn {
	align-items: center;
	background: none;
	border: 0;
	color: var(--accent-collected);
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.8rem;
	font-weight: bold;
	gap: 0.35rem;
	max-width: 100%;
	/* Etwas höher als das Senderlogo (siehe .epgPicon), und diese Höhe gilt auch ohne eines: Nur ein Teil der
	   Sender hat ein Logo, und ohne die feste Höhe wäre jede zweite Spalte der Rasterkopfzeile flacher als ihre
	   Nachbarin - nachgemessen 15px gegen 18px, als das Bild noch 1,15rem hoch war. Der Abstand zum Logo ist
	   zugleich der Grund, warum es nicht über die Buchstaben des Namens hinausragt. */
	min-height: 1.25rem;
	/* Bewusst ohne "overflow: hidden": Das Senderlogo ragt in der Jetzt-Kachel absichtlich 4px über die Zeile
	   hinaus (siehe .epgNowChannel .epgPicon), und ein Überlauf am Knopf schnitt genau diese 4px ab - bei jedem
	   Logo, dessen Inhalt seine Fläche füllt (ZDF, ProSieben, Sky Sci-Fi ...). Gekürzt wird der lange Sendername
	   ohnehin nicht hier, sondern am <span> darin; am Flex-Container wirkt text-overflow gar nicht erst.
	   white-space bleibt stehen, weil es sich an den <span> vererbt. */
	padding: 0;
	text-align: left;
	white-space: nowrap;
}

.epgNowChannelBtn:hover {
	text-decoration: underline;
}

/* Der Name nimmt den Platz, der zwischen Symbol und Logo übrig bleibt, und kürzt sich selbst. Die Regeln müssen am
   <span> stehen, nicht am Knopf: Der ist ein Flex-Container, und text-overflow wirkt nicht auf dessen Kinder. Ohne
   min-width:0 weigert sich ein Flex-Element, unter seine Inhaltsbreite zu schrumpfen - dann schöbe ein langer Name
   das Logo aus der Zeile. */
.epgNowChannelBtn > span {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Nur die Uhrzeit, kein Datum: Welcher Tag gemeint ist, hat man oben eingestellt oder mit "Jetzt" beantwortet.
   Die Restzeit steht als "(+12 Min.)" direkt dahinter - bis zum 27.09.2026 stand sie am rechten Rand, und dort
   gehört der Platz jetzt dem Logo (siehe .epgNowHead). */
.epgNowTime {
	align-items: baseline;
	color: var(--text-muted);
	display: flex;
	font-size: 0.75rem;
	gap: 0.3rem;
	min-width: 0;
}

.epgNowLeft {
	white-space: nowrap;
}

/* Titel und Kurzbeschreibung je eine Zeile. Ein zweizeiliger Titel verschiebt alles darunter, und schon bei
   wenigen Kacheln steht in jeder etwas anderes an anderer Stelle - dann findet das Auge keine Spur mehr. */
.epgNowTitle,
.epgNowDesc,
.epgNowEmpty {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.epgNowTitle {
	font-size: 0.95rem;
	font-weight: bold;
	line-height: 1.2;
}

.epgNowDesc,
.epgNowEmpty {
	color: var(--text-muted);
	font-size: 0.78rem;
	line-height: 1.2;
}

/* Dünner als der Balken der Tabelle: Dort ist er die einzige Anzeige in seiner Zelle, hier eine von fünf Zeilen
   und nur eine Nebenauskunft. */
.epgNowTile .epgProgress {
	height: 0.3em;
	margin: 0.25em 0 0.1em;
}

.epgNowTile .epgProgress .epgProgressBar {
	height: 0.3em;
	margin: 0;
}

/* Was danach kommt: Uhrzeit gedämpft, Titel in normaler Schriftfarbe. Stünde beides grau, ginge die Zeile als
   Fußnote unter - dabei ist sie die halbe Antwort auf "und dann?". Ohne Datum und ohne Dauer, damit dem Titel
   die Breite bleibt. */
/* Die Fußzeile der Kachel: links die nächste Sendung, rechts das "..."-Menü. align-items richtet beide auf
   dieselbe Mittellinie aus - dasselbe, was die Kopfzeile für Name und Menü tat, als das Menü noch dort stand. */
.epgNowNext {
	align-items: center;
	display: flex;
	font-size: 0.78rem;
	gap: 0.4rem;
	margin-top: 0.15rem;
	min-width: 0;
}

.epgNowNextTime {
	color: var(--text-muted);
	flex-shrink: 0;
}

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

/* Die Kopfzeile trägt seit dem 15.09.2026 nur noch Sendername und Logo - das "..."-Menü ist in die Fußzeile
   gewandert (siehe .epgNowNext). Dadurch steht die ganze Zeilenbreite für das Logo zur Verfügung, das sonst mit
   dem Menü um denselben Platz stritt. */
.epgNowChannel {
	align-items: center;
	display: flex;
	gap: 0.5rem;
}

.epgNowChannel .epgNowChannelBtn {
	flex: 1;
	min-width: 0;
}

/* Der Kopf der Jetzt-Kachel: links Sendername und Zeitzeile untereinander, rechts das Logo über beide Zeilen.
   Seit die Restlaufzeit hinter der Uhrzeit steht (27.09.2026), ist rechts unter dem Namen Platz, und das Logo darf
   gut doppelt so hoch werden wie die eine Zeile, die es vorher hatte - das rettet vor allem die flachen, deren
   Schrift sonst kaum zu lesen war (RTL). Wie weit es wächst, entscheidet weiter die Breitengrenze: Ein Logo, das
   schon vorher an ihr stand (Kabel Eins CLASSICS), bleibt, wie es war.

   container-type, damit die Grenze "45 % der Kachel" auch im Raster noch eine Kachelbreite meint - ein
   Prozentwert am Bild bezöge sich hier auf seine eigene, erst aus ihm errechnete Spalte. */
.epgNowHead {
	align-items: center;
	column-gap: 0.5rem;
	container-type: inline-size;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	row-gap: 0.15rem;
}

.epgNowHead > .epgNowChannel,
.epgNowHead > .epgNowTime {
	grid-column: 1;
}

.epgPicon.epgNowPicon {
	grid-column: 2;
	grid-row: 1 / span 2;
	height: 2rem;
	margin-left: 0;
	max-width: min(5rem, 45cqw);
}

/* Auf einer schmalen Kachel (Handy, zwei Spalten) bleibt neben dem großen Logo zu wenig für "02:05 (+57 Min.)" -
   die Zeitzeile lief dort unter das Logo. Dann gilt die Anordnung von vorher: Logo in der Namenszeile und so hoch
   wie früher, die Zeitzeile über die ganze Breite. */
@container (max-width: 12rem) {
	.epgNowHead > .epgNowTime {
		grid-column: 1 / -1;
	}

	.epgPicon.epgNowPicon {
		grid-row: 1;
		height: 1rem;
	}
}


/* Das Senderlogo von der Dreambox (siehe PiconHandler). Es steht rechts *neben* dem Namen, nie an seiner Stelle:
   Nur ein Teil der Sender hat eines, und eine Spalte, die mal ein Bild und mal Text zeigt, liest sich nicht als
   Reihe. margin-left:auto schiebt es an den rechten Rand, flex-shrink:0 hält es dort in voller Größe - schrumpfen
   soll der Text, nicht das Bild.

   Die Bilder tragen ihre eigene Transparenz und stammen auf der Box des Nutzers aus der Variante
   "transparent-dunkle-skin", passen also ohne weitere Behandlung auf den dunklen Grund. Ihr durchsichtiger Rand
   ist beim Übernehmen abgeschnitten (siehe PiconHandler#trim), sodass hier jedes Logo seine Fläche wirklich füllt.

   Zwei Grenzen statt einer, weil die Seitenverhältnisse weit auseinanderliegen (nach dem Schnitt von 0,8 bei QVC
   bis 10 bei Eurosport): Bei einem kompakten Logo entscheidet die Höhe, bei einem flachen die Breite. Der Deckel
   ist "min(5rem, 45%)" und keine feste Zahl - 5rem wären auf einer schmalen Handykachel mehr als die Hälfte der
   Zeile und ließen für den Sendernamen nichts übrig.

   Die beiden Grenzen sind getrennt zu behandeln, auch wenn beide "das Logo kleiner machen": Die Höhe wirkt nur auf
   die kompakten Logos, die Breite nur auf die flachen. Als hier einmal beide zugleich zurückgingen, um die
   kompakten zu bändigen, verlor Eurosport (Verhältnis 10) ein Zehntel seiner Höhe - 8,0 auf 7,2px - obwohl die
   Höhenangabe es gar nicht berührt. Wer die kompakten kleiner haben will, ändert die Höhe und sonst nichts.

   Die Höhe bleibt unter der Zeilenhöhe des Knopfes (1rem gegen 1,25rem): So sitzt das Logo mittig zum Sendernamen,
   statt oben über dessen Buchstaben hinauszuragen, und die Luft zur Restlaufzeit darunter ergibt sich von selbst,
   ohne verschobene Ränder. Auf die flachen Logos wirkt diese Höhe ohnehin nicht - bei ihnen entscheidet die
   Breite, sie verlieren durch eine kleinere Höhe also nichts. */
.epgPicon {
	flex-shrink: 0;
	height: 1rem;
	margin-left: auto;
	max-width: min(5rem, 45%);
	object-fit: contain;
	width: auto;
}

.epgNowActions {
	flex-shrink: 0;
}

.epgNowActions .toggleMoreFlyout {
	background: none;
	border: 0;
	color: var(--text-muted);
	cursor: pointer;
	padding: 0.1rem;
}

/* ---------------------------------------------------------------------------------------------
   Die Schnittseite (/cut/, siehe CutPage und cut.js): Bild, Zeitleiste, Bedienung, Markenliste.

   Die Zeitleiste ist die eigentliche Auskunft der Seite - sie zeigt nicht den Fortschritt, sondern das Ergebnis:
   helle Abschnitte bleiben, der dunkle Grund fällt weg. Deshalb liegen vier Ebenen übereinander (behaltene
   Abschnitte, Schnittmarken, Sprungmarken der Box, Abspielkopf) statt einer eingefärbten Leiste; jede ist für
   sich zu lesen und keine verdeckt die andere.
   --------------------------------------------------------------------------------------------- */

.cutTitle {
	color: var(--text-muted);
	margin-bottom: 0.75rem;
}

.cutStage {
	background: #000;
	border: 1px solid var(--control-border);
	border-radius: var(--field-radius);
	overflow: hidden;
	position: relative;
}

/* Die Höhe ist gedeckelt, nicht die Breite: Ohne Deckel füllt ein 16:9-Bild auf dem Schreibtisch die ganze
   Fensterhöhe, und Zeitleiste und Bedienung - das eigentliche Werkzeug dieser Seite - stünden unter dem Falz.
   Der schwarze Grund der Bühne füllt, was das Bild seitlich frei lässt. */
#cutVideo,
#clipVideo {
	aspect-ratio: 16 / 9;
	display: block;
	margin: 0 auto;
	max-height: 55vh;
	max-width: 100%;
}

.cutStatus {
	color: var(--control-text);
	left: 50%;
	position: absolute;
	top: 50%;
	transform: translate(-50%, -50%);
}

/* Höhe bewusst großzügig: Auf dem Telefon wird hier mit dem Finger gezielt, und die Marken sind schmale Striche. */
.cutTimeline {
	background: var(--control-bg-disabled);
	border: 1px solid var(--control-border);
	border-radius: var(--field-radius);
	cursor: pointer;
	height: 2.25rem;
	margin-top: 0.75rem;
	position: relative;
}

.cutTimeline > div {
	bottom: 0;
	left: 0;
	position: absolute;
	right: 0;
	top: 0;
}

.cutTimelineKept {
	background: var(--control-bg-hover);
	bottom: 0;
	position: absolute;
	top: 0;
}

.cutTimelineMark {
	position: absolute;
	top: 0;
	bottom: 0;
	width: 2px;
}

.cutTimelineMark.in {
	background: #6c6;
}

.cutTimelineMark.out {
	background: #d66;
}

/* Die Sprungmarken der Box stehen nur zur Orientierung da ("hier habe ich an der Fernbedienung gedrückt") und
   dürfen deshalb nicht mit den Schnittmarken verwechselt werden: halbe Höhe, gedämpft, unten angeschlagen. */
.cutTimelineJump {
	background: var(--text-muted);
	bottom: 0;
	height: 40%;
	opacity: 0.6;
	position: absolute;
	top: auto;
	width: 1px;
}

.cutTimelineHead {
	background: #fff;
	bottom: 0;
	position: absolute;
	top: 0;
	width: 2px;
}

.cutPosition {
	align-items: baseline;
	display: flex;
	gap: 0.6rem;
	margin-top: 0.4rem;
}

.cutPositionNow {
	font-family: monospace;
	font-size: 1.1rem;
}

.cutPositionTotal {
	color: var(--text-muted);
	font-size: 0.85rem;
}

.cutControls {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	margin-top: 0.75rem;
}

.cutControlGroup {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}

.cutMarkTable {
	border-collapse: collapse;
	width: 100%;
}

.cutMarkTable td {
	border-bottom: 1px solid var(--control-border-disabled);
	padding: 0.3rem 0.5rem;
}

.cutMarkType {
	width: 4rem;
}

.cutMarkTime {
	font-family: monospace;
}

.cutMarkActions {
	text-align: right;
	white-space: nowrap;
}

.cutMarkActions button {
	background: none;
	border: 0;
	color: var(--control-text);
	cursor: pointer;
	font-size: 1.1rem;
	padding: 0.15rem 0.35rem;
}

.cutChipIn,
.cutChipOut {
	border-radius: var(--control-radius);
	color: #fff;
	font-size: 0.75rem;
	padding: 0.1rem 0.5rem;
}

.cutChipIn {
	background: #3a6b4a;
}

.cutChipOut {
	background: #7a3a3a;
}

.cutActions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 1rem;
}

/* Clip-Seite (clip.html): Anfang und Ende eines Bereichs untereinander, jedes zum Antippen, darunter gedämpft die
   Länge. Die Knöpfe sehen aus wie Text - sie sind die Zeitangabe selbst, nicht noch ein Symbol in der Zeile. */
.clipRangeTimes button {
	align-items: center;
	background: none;
	border: 0;
	color: var(--control-text);
	cursor: pointer;
	display: flex;
	font-family: monospace;
	font-size: inherit;
	gap: 0.4rem;
	padding: 0.1rem 0;
	white-space: nowrap;
}

/* Der Vorschau-Modus ist ein Schalter: eingeschaltet in derselben Hervorhebung wie ein aktiver Filterknopf
   (.filterFlyoutToggleBtn.active), damit kein neuer Blauton entsteht. */
#clipPreview.active {
	background-color: rgba(102, 153, 221, 0.3);
	border-color: #6af;
	color: #6af;
}

/* Ordner und Format untereinander gleich breit; die Ordnerliste ist es durch ihre langen Pfade ohnehin. */
#clipDialog .defaultSelect {
	width: 100%;
}

.clipRangeLength {
	color: var(--text-muted);
	font-size: 0.8rem;
	padding-left: 1.4rem;
}

/* Auf breiten Bildschirmen steht das Bild links und die Markenliste rechts daneben - sonst scrollt man auf dem Tablet
   quer für jede Marke zur Liste hinunter und zum Bild wieder hinauf. Im Hochformat bleibt es untereinander, dort
   fehlt der Liste neben dem Bild die Breite. Deshalb hängt die Regel an der Ausrichtung und nicht allein an der
   Breite der Anwendung (1025px): Ein Tablet ist quer 1024px breit und fiele damit heraus.

   Die linke Spalte klebt beim Scrollen oben fest, denn eine lange Markenliste ist genau der Fall, für den die zwei
   Spalten da sind - und während man in ihr blättert, soll das Bild stehen bleiben. Die Höhe des Bildes ist auf 55vh
   begrenzt (siehe #cutVideo), sodass Zeitleiste und Bedienung unter dem Kopf (4rem) immer noch mit ins Bild passen.
   Ohne min-width: 0 auf der linken Spalte drückte das Video sie in seiner natürlichen Breite auf. */
@media (min-width: 900px) and (orientation: landscape) {
	.cutLayout {
		align-items: flex-start;
		display: flex;
		gap: 1.5rem;
	}

	.cutMain {
		flex: 1 1 0;
		min-width: 0;
		position: sticky;
		top: 4.75rem;
	}

	.cutSide {
		flex: 0 0 24rem;
	}

	.cutSide .infoBar {
		margin-top: 0;
	}
}

/* ---------------------------------------------------------------------------------------------
   "Anfang/Ende muten" (/mute/, siehe MutePage und mute.js).

   Je Rand drei Ebenen auf derselben Zeitachse übereinander: Bildstreifen, Pegel, und darüber die Linie samt der
   gestreiften Fläche, die stumm wird. Die ganze Spur nimmt das Ziehen an, nicht nur der Griff - auf dem Tablet ist
   eine 3 px breite Linie mit dem Finger nicht zu treffen. touch-action: none, sonst scrollt das Ziehen die Seite.
   --------------------------------------------------------------------------------------------- */

.muteIntro {
	margin: 0 0 1rem;
}

.muteNav {
	align-items: center;
	display: flex;
	gap: 0.5rem;
	margin-left: auto;
}

.muteNavPos {
	color: var(--text-muted);
	font-size: 0.9rem;
}

.muteSearch {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

/* Ergebnis von "Alle im Ordner muten": Die Liste kann lang werden (ein Ordner hatte 98 Aufnahmen) - sie scrollt im
   Dialog, statt ihn über den Bildschirm hinaus zu strecken. */
.muteFolderChanged,
.muteFolderFailed {
	margin: 0.4rem 0 0.8rem;
	max-height: 40vh;
	overflow-y: auto;
	padding-left: 1.2rem;
}

.muteSpinner,
.muteSearch .ph-spinner-gap {
	animation: muteSpin 1s linear infinite;
}

@keyframes muteSpin {
	to {
		transform: rotate(360deg);
	}
}

.muteRegion {
	background: var(--surface);
	border-radius: var(--field-radius);
	margin-bottom: 1rem;
	padding: 0.75rem;
}

.muteRegionHead {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1rem;
	margin-bottom: 0.6rem;
}

.muteCheck {
	align-items: center;
	display: flex;
	font-weight: bold;
	gap: 0.45rem;
}

.muteCheck input {
	margin: 0;
}

.muteInfo {
	color: var(--text-muted);
	flex: 1 1 auto;
}

.muteButtons {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-left: auto;
}

/* Der Vorschlag, wenn die Linie woanders steht: gestrichelt und gedämpft, damit er nicht mit der Linie verwechselt wird. */
.muteSuggestMark {
	border-left: 2px dashed rgba(255, 204, 102, 0.55);
	bottom: 0;
	margin-left: -1px;
	pointer-events: none;
	position: absolute;
	top: 0;
}

/* Feste Fläche, schwarz, solange es an der Stelle kein Bild gibt - siehe mute.js#updateBig. Genau so hoch wie die
   Zeitleiste daneben: Bildstreifen 3,5 + Pegel 4 + Skala 0,3 + 0,8 × 1,25 = 8,8rem. */
.muteBig {
	aspect-ratio: 16 / 9;
	background: #000;
	border-radius: 4px;
	height: 8.8rem;
	margin-bottom: 0.6rem;
	max-width: 100%;
	overflow: hidden;
}

.muteBigImg {
	display: block;
	height: 100%;
	object-fit: contain;
	width: 100%;
}

/* Breit stehen Bild und Zeitleiste nebeneinander - im Querformat eines Tablets passt die Seite so ohne Scrollen.
   Hochkant bleibt die Zeitleiste über die volle Breite; dort wäre sie neben dem Bild zu schmal. */
@media (min-width: 1025px) {
	.muteBody {
		align-items: flex-start;
		display: flex;
		gap: 1rem;
	}

	.muteBig {
		flex: none;
		margin-bottom: 0;
	}

	.muteTimeline {
		flex: 1;
		min-width: 0;
	}
}

.muteTrack {
	cursor: ew-resize;
	position: relative;
	touch-action: none;
	user-select: none;
}

.muteThumbs {
	background: #000;
	height: 3.5rem;
	overflow: hidden;
	position: relative;
}

.muteThumbs img {
	height: 100%;
	object-fit: cover;
	pointer-events: none;
	position: absolute;
	top: 0;
}

.muteNoPicture {
	color: var(--text-muted);
	left: 0.5rem;
	position: absolute;
	top: 1rem;
}

.muteLevels {
	background: #0a1020;
	display: block;
	height: 4rem;
	width: 100%;
}

.muteShade {
	background: repeating-linear-gradient(135deg, rgba(0, 0, 0, 0.55) 0 6px, rgba(0, 0, 0, 0.25) 6px 12px);
	bottom: 0;
	pointer-events: none;
	position: absolute;
	top: 0;
}

.muteLine {
	background: #fc6;
	bottom: -0.3rem;
	margin-left: -1.5px;
	outline: none;
	position: absolute;
	top: -0.3rem;
	width: 3px;
}

.muteHandle {
	background: #fc6;
	border-radius: 50%;
	height: 0.9rem;
	left: -0.45rem;
	position: absolute;
	top: -0.45rem;
	width: 0.9rem;
}

.muteLine:focus-visible .muteHandle {
	box-shadow: 0 0 0 3px var(--control-border-hover);
}

/* Gelb: Vorschlag oder ungespeichert. Grün: genau so gespeichert (siehe mute.js#updateSavedState). */
.muteSaved .muteLine,
.muteSaved .muteHandle {
	background: var(--accent-watched);
}

.muteState {
	border: 1px solid #fc6;
	border-radius: var(--control-radius);
	color: #fc6;
	font-size: 0.85rem;
	padding: 0.05rem 0.6rem;
}

.muteState.muteStateSaved {
	border-color: var(--accent-watched);
	color: var(--accent-watched);
}

.muteOff .muteLine,
.muteOff .muteHandle {
	background: var(--text-muted);
}

.mutePlayhead {
	background: #fff;
	bottom: 0;
	pointer-events: none;
	position: absolute;
	top: 0;
	width: 1px;
}

.muteScale {
	color: var(--text-muted);
	display: flex;
	font-size: 0.8rem;
	justify-content: space-between;
	line-height: 1.25; /* Teil der Höhe, an der sich .muteBig ausrichtet */
	margin-top: 0.3rem;
}

/* ---------------------------------------------------------------------------------------------
   Die Statistik-Seite (/statistics.html, siehe StatisticsPage und StatisticsHandler).

   Ein Diagramm trägt genau eine Größe und damit genau eine Farbe - die seines Abschnitts, also dieselben drei
   Bereichsfarben wie Menü und Startseite. Damit hängt keine Aussage an einer Farbunterscheidung: Was ein Balken
   bedeutet, steht als Text daneben, und die Farbe sagt nur, in welchem Abschnitt man ist. Nachgemessen an den drei
   Tönen: Als nebeneinander zu unterscheidende Palette taugen sie nicht (--group-mediathek-bright gegen
   --group-misc-bright liegen auch bei normalem Farbsehen zu dicht beieinander), gegen die Kachelfläche haben aber
   alle drei über 3:1 - und mehr wird hier nicht von ihnen verlangt. Zwei Größen in ein Diagramm zu legen, wäre
   deshalb nicht nur unübersichtlich, sondern würde eine Unterscheidung verlangen, die diese Farben nicht leisten.

   Der Balken ist Zugabe, nicht Träger: Beschriftung und Wert stehen als Text da, die Zeile bleibt also lesbar,
   wenn das CSS nicht ankommt oder jemand sie vorgelesen bekommt.
   --------------------------------------------------------------------------------------------- */

.statNav {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-bottom: 1.5rem;
}

.statNavItem {
	align-items: center;
	background: var(--control-bg);
	border: 1px solid var(--control-border);
	border-radius: var(--control-radius);
	color: var(--control-text);
	display: inline-flex;
	gap: 0.4rem;
	height: var(--control-height);
	padding: 0 0.9rem;
	text-decoration: none;
}

.statBlock {
	margin-bottom: 2.5rem;
}

.statBlockTitle {
	align-items: center;
	border-bottom: 1px solid var(--line-subtle);
	display: flex;
	gap: 0.5rem;
	margin: 0 0 1rem 0;
	padding-bottom: 0.4rem;
}

/* Kennzahlen: Der Wert steht über seiner Beschriftung, nicht daneben - so fluchten die Zahlen über alle Kacheln
   hinweg, und die Kachel bleibt schmal genug, dass auf dem Telefon zwei nebeneinander passen. */
.statFigures {
	display: grid;
	gap: 0.75rem;
	grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
}

.statFigure {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: var(--field-radius);
	padding: 0.7rem 0.8rem;
}

/* Bewusst ohne tabular-nums: Bei dieser Größe gibt die feste Ziffernbreite einer Zahl wie "1.982" sichtbare Lücken.
   Die Spalten von Zahlen an den Balken haben sie dagegen (siehe .statBarValue), dort fluchten sie untereinander. */
.statFigureValue {
	color: var(--control-text-hover);
	font-size: 1.45rem;
	font-weight: 600;
	line-height: 1.2;
}

.statFigureLabel {
	margin-top: 0.15rem;
}

.statFigureHint {
	color: var(--text-muted);
	font-size: 0.8rem;
	margin-top: 0.1rem;
}

/* Mehrspaltensatz und kein Raster: Im Raster ist jede Zeile so hoch wie ihre höchste Karte, und weil die Diagramme
   zwischen 6 und 28 Balken tragen, stünde neben der längsten Karte eine tote Fläche von mehreren hundert Pixeln. So
   füllen die Karten ihre Spalte dicht. Der Preis ist die Lesereihenfolge - sie läuft spaltenweise statt zeilenweise;
   das ist hier verschmerzbar, weil jedes Diagramm für sich steht und keines auf dem vorigen aufbaut. */
.statCharts {
	column-gap: 1rem;
	columns: 21rem;
	margin-top: 1.25rem;
}

.statChart {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: var(--field-radius);
	/* Ohne das zerschneidet der Mehrspaltensatz eine Karte am Spaltenende mitten im Diagramm. */
	break-inside: avoid;
	margin-bottom: 1rem;
	padding: 0.8rem 1rem 1rem 1rem;
}

.statChartTitle {
	font-size: 1rem;
	margin: 0;
}

.statChartHint,
.statChartFoot {
	color: var(--text-muted);
	font-size: 0.8rem;
}

.statChartHint {
	margin-bottom: 0.6rem;
}

.statChartFoot {
	border-top: 1px solid var(--line-subtle);
	margin-top: 0.7rem;
	padding-top: 0.5rem;
}

.statBars {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	margin-top: 0.6rem;
}

.statBar {
	align-items: center;
	display: grid;
	column-gap: 0.6rem;
	grid-template-columns: minmax(0, 11rem) 1fr auto;
}

/* Ohne eigene Farbregel: Ein Link ist in dieser Anwendung schlicht weiß statt --text (siehe die globale a-Regel),
   und genau dieser leise Unterschied soll die anklickbaren Beschriftungen von den übrigen trennen. Eine eigene
   Regel mit "color: inherit" stand kurz hier und nahm ihn weg. */
.statBarLabel {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.statBarTrack {
	background: var(--page-bg);
	border-radius: 3px;
	height: 0.55rem;
	overflow: hidden;
}

/* Links an der Grundlinie eckig, rechts am Datenende abgerundet - der Balken wächst aus einer gemeinsamen Kante. */
.statBarFill {
	border-radius: 0 3px 3px 0;
	display: block;
	height: 100%;
}

.statBarValue {
	font-variant-numeric: tabular-nums;
	text-align: right;
	white-space: nowrap;
}

.statBarExtra {
	color: var(--text-muted);
	display: block;
	font-size: 0.75rem;
}

.statBlock--recording .statBlockTitle i { color: var(--group-recording-bright); }
.statBlock--mediathek .statBlockTitle i { color: var(--group-mediathek-bright); }
.statBlock--misc      .statBlockTitle i { color: var(--group-misc-bright); }

.statBlock--recording .statBarFill { background: var(--group-recording-bright); }
.statBlock--mediathek .statBarFill { background: var(--group-mediathek-bright); }
.statBlock--misc      .statBarFill { background: var(--group-misc-bright); }

/* Schmal reicht die Breite nicht für drei Spalten: Beschriftung und Wert teilen sich die erste Zeile, der Balken
   steht darunter über die ganze Breite. Er verliert dabei nichts - verglichen wird ohnehin senkrecht. */
@media (max-width: 640px) {
	.statBars {
		gap: 0.7rem;
	}

	.statBar {
		grid-template-columns: 1fr auto;
		row-gap: 0.15rem;
	}

	.statBarTrack {
		grid-column: 1 / -1;
		grid-row: 2;
	}

	.statBarLabel {
		grid-column: 1;
		grid-row: 1;
	}

	.statBarValue {
		grid-column: 2;
		grid-row: 1;
	}

	.statBarExtra {
		display: inline;
		margin-left: 0.4rem;
	}
}

/* Bouquet-Editor (bouquets.html, bouquets.js) ----------------------------------------------------------------------
   Breit: links alle Sender über die volle Höhe, rechts oben die Bouquets, darunter der Inhalt des gewählten. Die
   Listen scrollen in sich - anders als bei den Flyouts (die nie einen eigenen Scrollbalken bekommen) ist das hier die
   Arbeitsfläche: Man wählt links und fügt rechts ein, und beides muss dabei gleichzeitig zu sehen sein. Auf dem Handy
   steht alles untereinander, in der Reihenfolge Bouquets, Inhalt, alle Sender. */

.bouquetEditor .pageTitleRow h2 {
	align-items: center;
	display: flex;
	gap: 0.6rem;
}

.bqBoxName {
	color: var(--text-muted);
	font-size: 1rem;
	font-weight: normal;
}

.bqToolbar {
	margin-bottom: 1rem;
}

/* So hoch wie der Bildschirm unter dem Kopf (4rem), mit 1rem Luft oben und unten: Titel und Reiter darf man
   wegscrollen, dann stehen die drei Kästen vollständig im Bild. Bis dahin war die Höhe um Titel und Reiter gekürzt -
   dieselbe Fläche, nur ohne Titel sichtbar, blieb unten leer. */
.bqLayout {
	display: grid;
	gap: 1rem;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	height: calc(100dvh - 6rem);
	min-height: 32rem;
}

.bqRight {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	min-height: 0;
}

.bqPanel {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: var(--field-radius);
	display: flex;
	flex-direction: column;
	min-height: 0;
	padding: 0.6rem;
}

.bqContentPanel {
	flex: 1;
}

.bqPanelHead h3 {
	font-size: 1rem;
	margin: 0 0 0.5rem;
}

.bqCount {
	color: var(--text-muted);
	font-weight: normal;
}

.bqPanelBar {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0.5rem 0;
}

.bqPanelBar.bqActions {
	margin-bottom: 0;
}

.bqFilter {
	flex: 1;
	min-width: 8rem;
}

.bqHint {
	color: var(--text-muted);
	font-size: 0.85rem;
}

.bqList {
	border-top: 1px solid var(--line-subtle);
	flex: 1;
	min-height: 0;
	overflow-y: auto;
}

/* Im Querformat knapp gehalten: Was die Höhe hergibt, geht an den Inhalt des Bouquets darunter. Hochkant ist Höhe
   dagegen reichlich da, und bei 10rem stand ein kurzes Bouquet unter einer abgeschnittenen Liste vor viel leerer
   Fläche (Tablet des Nutzers, 25.09.2026) - dort bekommt die Liste mehr, siehe die Regel direkt darunter. */
.bqBouquetList {
	flex: 0 1 auto;
	max-height: 10rem;
}

/* Hochkant höchstens 40% der rechten Spalte statt eines festen Anteils des Bildschirms: Mit 35dvh bekam die Liste im
   geteilten Bildschirm (zwei Fenster nebeneinander, jedes höher als breit, also ebenfalls "portrait") fast die halbe
   Spalte, und dem Inhalt darunter blieben drei Zeilen (so auf dem Tablet gesehen, 25.09.2026). Als Anteil der Spalte
   wächst und schrumpft sie mit dem Fenster - auf dem ganzen Tablet hochkant reicht es weiter für alle Bouquets. */
@media (orientation: portrait) and (min-width: 701px) {
	.bqBouquetPanel {
		max-height: 40%;
	}

	.bqBouquetList {
		max-height: none;
		min-height: 0;
	}
}

.bqRow {
	align-items: center;
	border-bottom: 1px solid var(--line-subtle);
	cursor: pointer;
	display: flex;
	gap: 0.5rem;
	min-height: 2rem;
	padding: 0.15rem 0.4rem;
	user-select: none;
}

.bqRow.selected {
	background: var(--control-bg-hover);
	color: var(--control-text-hover);
}

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

.bqRow .bqCheck {
	color: var(--control-border);
}

.bqRow.selected .bqCheck {
	color: var(--control-text-hover);
}

/* Das Logo bekommt eine feste Spalte, damit die Namen fluchten, auch wo keines da ist (siehe PiconHandler). */
.bqLogo {
	align-items: center;
	display: inline-flex;
	flex: 0 0 3.5rem;
	justify-content: center;
}

/* Höhe und Breite sind Obergrenzen, keine festen Maße: Mit fester Höhe und Höchstbreite wurde ein breites Logo
   (Eurosport) in der Breite gekappt und in der Höhe nicht - also gestaucht. */
.bqLogo img {
	height: auto;
	max-height: 1rem;
	max-width: 3.5rem;
	width: auto;
}

.bqRowCount {
	color: var(--text-muted);
	font-size: 0.85rem;
}

/* Pay-TV (€) bzw. verschlüsselt (Schlüssel, .cryptIcon wie in der Timerliste) am Ende einer Senderzeile - beide gleich
   hell. .cryptIcon hat außerhalb der Timerliste keine eigene Farbe und stand deshalb heller da als das €. In den
   gedämpften Zeilen des Abgleichs treten beide mit der Zeile zurück. */
.bqPayTvIcon,
.bqRow .cryptIcon,
.bqsRow .cryptIcon {
	color: var(--text-muted);
}

.bqsRow.bqsCommon .bqPayTvIcon,
.bqsRow.bqsCommon .cryptIcon {
	color: inherit;
}

/* Schon im Bouquet: nicht wählbar (die Box nimmt denselben Sender nicht zweimal) und zurückgenommen. */
.bqRow.bqContained {
	cursor: default;
}

.bqContained .bqName,
.bqContained .bqCheck {
	color: var(--text-muted);
}

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

.bqMarker {
	background: var(--surface-band);
	font-style: italic;
}

.bqListEmpty {
	margin: 0.6rem 0.4rem;
}

.bouquetEditor .dragHandle {
	background: none;
	border: none;
	color: var(--text-muted);
	cursor: grab;
	padding: 0 0.1rem;
	touch-action: none;
}

.bouquetEditor .dragHandle:active {
	cursor: grabbing;
}

.bouquetEditor .dragSortActive {
	background: var(--control-bg);
	box-shadow: 0 6px 18px rgba(0,0,0,0.55);
	position: relative;
	z-index: 2;
}

.bqBusy .bqList {
	opacity: 0.6;
	pointer-events: none;
}

.bqBackupHead {
	margin-top: 2rem;
}

.bqBackupBar {
	margin: 0.6rem 0;
}

.bqBackupActions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	justify-content: flex-end;
}

#bqNameInput {
	width: 100%;
}

/* Untereinander erst auf dem Handy: Ein Tablet hochkant hat für zwei Spalten Breite genug (Sendernamen sind kurz) und
   in der Höhe viel Platz für lange Listen - dort ist das Nebeneinander die bessere Ansicht (so vom Nutzer gewünscht). */
@media (max-width: 700px) {
	.bqLayout {
		display: flex;
		flex-direction: column;
		height: auto;
		min-height: 0;
	}

	.bqAllPanel {
		order: 2;
	}

	.bqList,
	.bqBouquetList {
		flex: none;
		max-height: 55vh;
	}
}

/* Handlung am Fuß einer Info-Kachel der System-Seite ("Bouquets bearbeiten"). */
.db-actions {
	border-top: 1px solid var(--line-subtle);
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 0.6rem;
	padding-top: 0.6rem;
}

.bqToolbar {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
}

/* Bouquet-Abgleich (bouquetsync.html, bouquetSync.js): zwei Spalten, links die aktive Box, rechts die andere. Was auf
   beiden Seiten steht, tritt zurück (.bqsCommon) - hervor sticht, was nur auf einer steht. Die Seite scrollt als
   Ganzes, die Spalten nicht einzeln: Gleichnamige Bouquets sollen auf gleicher Höhe beginnen. */

.bqsHeads,
.bqsCols {
	display: grid;
	gap: 1rem;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.bqsHead {
	align-items: center;
	display: flex;
	font-size: 1.1rem;
	gap: 0.6rem;
	margin: 0.5rem 0;
}

.bqsPair {
	background: var(--surface);
	border: 1px solid var(--line-subtle);
	border-radius: var(--field-radius);
	margin-bottom: 0.8rem;
	padding: 0.5rem 0.8rem;
}

.bqsPairHead {
	cursor: pointer;
	font-weight: bold;
	padding: 0.2rem 0;
}

.bqsStatus {
	color: var(--text-muted);
	font-size: 0.85rem;
	font-weight: normal;
	margin-left: 0.6rem;
}

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

/* Beide Seiten eines Paares teilen sich ein Raster aus zwei Zeilen - Knopfleiste, Senderliste. Mit subgrid bekommt die
   Leistenzeile die Höhe der höheren Leiste, und die Listen beginnen links und rechts auf derselben Höhe; vorher stand
   eine Seite ohne Knöpfe um deren Höhe versetzt, und gleiche Sender lagen nicht nebeneinander. */
.bqsCols {
	grid-template-rows: auto auto;
}

.bqsSide {
	display: grid;
	grid-row: span 2;
	grid-template-rows: subgrid;
	min-width: 0;
}

.bqsBar:empty {
	margin: 0;
}

.bqsBar {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin: 0.5rem 0;
}

.bqsRow {
	align-items: center;
	border-top: 1px solid var(--line-subtle);
	display: flex;
	gap: 0.5rem;
	min-height: 2rem;
	padding: 0.1rem 0.3rem;
	user-select: none;
}

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

.bqsRow.bqsUnique {
	cursor: pointer;
}

.bqsRow.selected {
	background: var(--control-bg-hover);
	color: var(--control-text-hover);
}

.bqsRow .bqCheck {
	color: var(--control-border);
}

.bqsRow.selected .bqCheck {
	color: var(--control-text-hover);
}

.bqsRow.bqsCommon {
	color: var(--text-faint);
}

.bqsRow.bqsCommon .bqCheck {
	color: var(--text-faint);
}

.bqsRow.bqsCommon img {
	opacity: 0.35;
}

.bqsRow.bqsMarker {
	background: var(--surface-band);
	color: var(--text-muted);
	font-style: italic;
}

.bqsMissing {
	align-self: start;
}

.bqsPhoneHint {
	display: none;
}

@media (max-width: 700px) {
	.bqsDesktop,
	.bqSyncLink {
		display: none;
	}

	.bqsPhoneHint {
		display: block;
	}
}

.bqPanelHead {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	justify-content: space-between;
	margin-bottom: 0.5rem;
}

.bqPanelHead h3 {
	margin-bottom: 0;
}

.bqSelectButtons {
	display: inline-flex;
	gap: 0.4rem;
}

/* Die Stecknadel vor dem Namen eines Trennmarkers (bouquets.js#markerName). */
.bqPin {
	font-style: normal;
	margin-right: 0.4rem;
}

/* Beim Ziehen die Liste verlassen (dragSort.js#setOutside): Die Zeile steht wieder an ihrem Platz und zeigt, dass
   Loslassen hier abbricht. Rot, weil es ein Fehlerzustand ist - zu weit gezogen. */
.dragSortOutside {
	outline: 2px dashed #d44;
	outline-offset: -2px;
}

.bqRow.dragSortOutside::after {
	color: #d44;
	content: "\e3de";
	font-family: "Phosphor-Bold";
	margin-left: auto;
}

html.dragSortForbidden,
html.dragSortForbidden * {
	cursor: not-allowed !important;
}

/* Der "…"-Auslöser in der Leiste des Bouquet-Inhalts sieht aus wie die runden Pfeilknöpfe daneben. ".actions button"
   nimmt jedem Knopf in einem Menübereich Rahmen und Fläche - das ist für die Zeilenmenüs gedacht, nicht für einen
   Knopf in einer Leiste. */
.bqMoreActions > .actionWrapper > .toggleMoreFlyout {
	background-color: var(--control-bg);
	border: 1px solid var(--control-border);
	color: var(--control-text);
	height: var(--control-height);
	padding: 0;
	width: var(--control-height);
}

.bqMoreActions > .actionWrapper > .toggleMoreFlyout i {
	font-size: 1.1rem;
}

/* In den Leisten von Editor und Abgleich regelt gap den Abstand - der Außenabstand, den .defaultBtn/.smallBtn rechts
   mitbringen, kam sonst noch dazu (13,6 statt 6,4px) und brach die Leiste des Abgleichs auf dem Tablet im Querformat
   um 13px in zwei Zeilen um. */
.bqPanelBar > .defaultBtn,
.bqPanelBar > .bqMoreActions,
.bqSelectButtons > .defaultBtn,
.bqsBar > .defaultBtn {
	margin-right: 0;
}

.bqMoreActions > .actionWrapper > .toggleMoreFlyout[disabled] {
	background-color: var(--control-bg-disabled);
	border-color: var(--control-border-disabled);
	color: var(--control-text-disabled);
}

/* Ausnahme von "Menüs öffnen unter ihrem Knopf" (Wunsch des Nutzers, 25.09.2026): Dieser Knopf sitzt immer am unteren
   Rand der Arbeitsfläche, die den Bildschirm ausfüllt. Nach unten geöffnet scrollte die Seite jedes Mal nach
   (scrollFlyoutIntoView), und nach dem Schließen musste man zurückscrollen. Darüber ist immer Platz - dort steht der
   Inhalt des Bouquets. */
.actions.bqMoreActions .moreFlyout {
	bottom: 100%;
	margin-bottom: 2px;
	margin-top: 0;
	top: auto;
}

/* In einem schmalen Kasten (geteilter Bildschirm, Tablet hochkant) verlieren "Trennmarker…"/"Umbenennen…" ihre
   Beschriftung und werden rund wie die Pfeile daneben - so passt die Leiste in eine Zeile (Wunsch des Nutzers). Nach
   der Breite des Kastens, nicht des Bildschirms: Die hängt davon ab, wie viele Spalten nebeneinander stehen. Der
   Stift ist ohnehin eindeutig, die Stecknadel ist das Zeichen, das vor jedem Trennmarker in der Liste steht. */
.bqContentPanel {
	container: bqcontent / inline-size;
}

@container bqcontent (max-width: 460px) {
	.bqAddMarker > span,
	.bqRenameMarker > span {
		display: none;
	}

	.bqAddMarker,
	.bqRenameMarker {
		border-radius: 50%;
		justify-content: center;
		min-width: auto;
		padding: 0;
		width: var(--control-height);
	}

	.bqAddMarker i,
	.bqRenameMarker i {
		margin: 0;
	}
}

/* Die Auswahl der Senderliste (Alle / Satelliten / Anbieter) links vom Filter: so breit wie ihr Inhalt, höchstens
   aber ein Drittel der Leiste - "Kabel - HD Kanäle FTA" soll das Filterfeld nicht verdrängen. */
.bqSource {
	flex: 0 1 auto;
	max-width: 33%;
	min-width: 6rem;
}

/* Der feste Platz für € bzw. Schlüssel am Ende einer Senderzeile (bouquets.js#channelMarks). */
.bqMarkSlot {
	display: inline-flex;
	flex: 0 0 1.2rem;
	justify-content: center;
}

/* Eigener Name eines Senders bzw. Zahl der Sender einer Alternative, gedämpft hinter dem Namen. */
.bqOrigName {
	color: var(--text-muted);
	font-size: 0.85em;
}

.bqAltToggle,
.bqMemberUp,
.bqMemberRemove {
	background: none;
	border: none;
	color: var(--control-text);
	cursor: pointer;
	padding: 0 0.3rem;
}

.bqMemberUp[disabled] {
	color: var(--text-faint);
	cursor: default;
}

/* Die Sender einer aufgeklappten Alternative: eingerückt unter ihr, mit ihrer Rangfolge. */
.bqMemberRow {
	align-items: center;
	background: var(--page-bg);
	border-bottom: 1px solid var(--line-subtle);
	display: flex;
	gap: 0.5rem;
	min-height: 1.8rem;
	/* So weit eingerückt, dass Logo und Name genau unter denen der Alternative stehen: Die Rangzahl nimmt den Platz
	   von Greifer und Kästchen ein. */
	padding: 0.1rem 0.4rem 0.1rem calc(1.9rem - 2px);
}

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

.bqMemberRank {
	color: var(--text-muted);
	font-size: 0.85rem;
	min-width: 1.2rem;
}

.bqMemberRemove[disabled] {
	color: var(--text-faint);
	cursor: default;
}

.bqMemberHint {
	background: var(--page-bg);
	justify-content: flex-start;
}

/* Das Blau der Textlinks wie in Hinweisen und Hilfe (.settingsHint a, .helpSection a) - als Link erkennbar. */
.bqDissolveHere {
	color: #6af;
	font-size: 0.9rem;
}

/* Im Abgleich steht eine Alternative als ihr erster Sender da; das Symbol sagt, dass es eine ist. */
.bqsAltIcon,
.bqAltIcon {
	color: var(--text-muted);
	margin-left: 0.35rem;
}
