Die Oberfläche nach Plex' Vorbild — Hintergrund, Schriftzug, Besetzung
Nach den Bildern deiner Plex-Installation umgebaut. Übernommen ist der Aufbau, nicht die Farbe: Plex ist bernsteingelb, Flaro bleibt Orchidee. **Kopfleiste oben** mit Marke, Suche und Konto. Die Suche gehört dorthin und nicht in jede Mediathek: wer einen Titel sucht, weiss oft gar nicht, in welcher er liegt. Sie geht quer durch alles. **Seitenleiste mit Icons** — echte SVG, keine Zeichen aus einer Schriftart. Ein ▶ aus Unicode sieht auf jedem System anders aus, lässt sich nicht einfärben und springt in der Grundlinie. Die aktive Zeile bekommt einen schmalen Balken links statt eines leuchtenden Blocks; das liest sich in einer langen Liste ruhiger. **Die Kachel steht jetzt an einer Stelle** statt an fünfen. Sie trägt den Haken für Gesehenes in der Ecke — wie bei Plex, ein Blick über das Raster genügt —, die Zahl offener Folgen an derselben Stelle, den Fortschrittsbalken unten und beim Überfahren einen Abspielknopf. Folgen sind dreizeilig: Serie, Folgentitel, „S14 · F22". **Reihen haben Pfeile.** Zwanzig Kacheln passen nicht in den Bildschirm, und quer zu scrollen geht mit dem Rad nur mit Umschalttaste. Die Überschrift nennt die Mediathek beim Namen: „Zuletzt in Dokumentationen hinzugefügt". **Mediatheken haben drei Reiter** — Empfehlungen, Mediathek, Kategorien. Darunter eine Filterzeile mit Genre, Sortierung und der Anzahl. Die Kategorien sind farbige Kacheln; die Farbe kommt aus dem Namen, nicht aus einer festen Liste, die jedes Genre kennen müsste, das TMDB je erfindet. **Die Detailseite** hat jetzt den unscharfen Hintergrund über die ganze Seite, den **Schriftzug des Films** statt der Systemschrift, eine Zeile mit Jahr, Genres, Laufzeit, Altersfreigabe und Bewertung, runde Knöpfe für gesehen/Favorit/weglegen, die Medienangaben als Tabelle — Datei, Video, Ton, Untertitel — und zuletzt Besetzung & Stab mit runden Porträts. **Dazu am Server:** ein Name. Ohne ihn zeigten die Clients den Hostnamen, und die App schrieb „localhost" über die Anmeldung. Vorgabe ist der Rechnername des Containers. --- **Der Fehler, den das erste Bild zeigte:** die Lupe in der Suchleiste war dreihundert Bildpunkte gross und lag über der halben Seite. Ein rohes `<svg>` ohne Breite füllt seinen Container; die Regel galt nur für `.icon`. Jetzt für jedes. 368 Tests grün. Am Container nachgesehen: „Der Untergang" mit eigenem Schriftzug, FSK 12, Bewertung 7,9, Genres Drama/Historie/Kriegsfilm, beide Tonspuren in der Tabelle, 22 Porträts darunter. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ede4069cd4
commit
8c395ac051
+363
-182
@@ -1,292 +1,473 @@
|
||||
/* Flaro — Weboberfläche
|
||||
/* Flaro — Weboberfläche.
|
||||
*
|
||||
* Der Aufbau folgt Plex: Seitenleiste links, Inhalt als waagerechte Reihen,
|
||||
* Detailseite mit grossem unscharfem Hintergrund. Die Farben nicht — Orchid
|
||||
* stimmt mit der iOS-App überein, und Plex' Orange ist deren Marke.
|
||||
*/
|
||||
* Der Aufbau folgt Plex: Kopfleiste oben, Seitenleiste links mit Icons,
|
||||
* waagerechte Reihen auf der Startseite, Plakate im Verhältnis 2:3 mit Haken
|
||||
* und Fortschrittsbalken, eine Detailseite mit unscharfem Hintergrund und
|
||||
* dem Schriftzug des Films.
|
||||
*
|
||||
* **Die Farbe nicht.** Plex ist bernsteingelb, Flaro ist Orchidee. Das
|
||||
* Vorbild ist die Anordnung, nicht das Aussehen. */
|
||||
|
||||
:root {
|
||||
--accent: #C04AC9;
|
||||
--accent-dim: #8E3595;
|
||||
--accent-soft: rgba(192, 74, 201, .16);
|
||||
|
||||
--canvas: #0B0B0D;
|
||||
--surface: #141417;
|
||||
--elevated: #1D1D21;
|
||||
--placeholder: #26262B;
|
||||
--text: #F5F5F7;
|
||||
--text-dim: #A1A1A8;
|
||||
--text-faint: #6E6E76;
|
||||
--separator: rgba(255, 255, 255, .10);
|
||||
--elevated: #1D1D22;
|
||||
--raised: #26262C;
|
||||
--placeholder: #202026;
|
||||
--line: rgba(255, 255, 255, .08);
|
||||
|
||||
--r-card: 6px;
|
||||
--r-control: 8px;
|
||||
--r-panel: 14px;
|
||||
--text: #F2F2F5;
|
||||
--text-dim: #B4B4BE;
|
||||
--text-muted: #8A8A95;
|
||||
--text-faint: #65656F;
|
||||
--destructive: #E5484D;
|
||||
|
||||
--s-tight: 4px; --s-snug: 8px; --s-regular: 12px;
|
||||
--s-loose: 16px; --s-section: 28px;
|
||||
--s-loose: 16px; --s-section: 24px; --s-page: 32px;
|
||||
|
||||
--r-control: 8px; --r-card: 6px; --r-pill: 999px;
|
||||
|
||||
--card-w: 150px;
|
||||
--sidebar-w: 240px;
|
||||
--topbar-h: 56px;
|
||||
|
||||
--font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
html, body {
|
||||
margin: 0; padding: 0; height: 100%;
|
||||
background: var(--canvas); color: var(--text);
|
||||
font-family: var(--font); font-size: 14px; line-height: 1.45;
|
||||
html, body { height: 100%; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--canvas);
|
||||
color: var(--text);
|
||||
font: 400 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
button, input, select { font: inherit; color: inherit; }
|
||||
button, input, select, textarea { font: inherit; color: inherit; }
|
||||
button { cursor: pointer; }
|
||||
.hidden { display: none !important; }
|
||||
|
||||
/* ---------- Gerüst ---------- */
|
||||
/* **Jedes SVG bekommt eine Grösse, nicht nur die in `.icon`.** Ein rohes
|
||||
`<svg>` ohne Breite füllt sonst seinen Container — und die Lupe in der
|
||||
Suchleiste war dreihundert Bildpunkte gross und lag über der Seite. */
|
||||
svg { width: 20px; height: 20px; display: block; flex: none; }
|
||||
.icon { width: 20px; height: 20px; display: block; flex: none; }
|
||||
|
||||
#app { display: flex; min-height: 100%; }
|
||||
/* ---------- Kopfleiste ---------- */
|
||||
|
||||
#chrome {
|
||||
width: var(--sidebar-w); flex: 0 0 var(--sidebar-w);
|
||||
background: var(--surface);
|
||||
border-right: 1px solid var(--separator);
|
||||
padding: var(--s-loose) 0;
|
||||
display: flex; flex-direction: column; gap: var(--s-tight);
|
||||
position: sticky; top: 0; height: 100vh; overflow-y: auto;
|
||||
#topbar {
|
||||
position: fixed; inset: 0 0 auto 0; height: var(--topbar-h); z-index: 30;
|
||||
display: flex; align-items: center; gap: var(--s-loose);
|
||||
padding: 0 var(--s-loose);
|
||||
background: #0E0E11;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
#topbar .marke {
|
||||
font-size: 20px; font-weight: 700; letter-spacing: -.02em;
|
||||
color: var(--accent); user-select: none;
|
||||
}
|
||||
#topbar .suchfeld {
|
||||
flex: 1; max-width: 420px;
|
||||
display: flex; align-items: center; gap: var(--s-snug);
|
||||
background: var(--elevated); border: 1px solid transparent;
|
||||
border-radius: var(--r-pill); padding: 0 var(--s-regular); height: 34px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
#topbar .suchfeld:focus-within { border-color: var(--accent); color: var(--text); }
|
||||
#topbar .suchfeld input {
|
||||
flex: 1; min-width: 0; background: none; border: 0; outline: none; color: var(--text);
|
||||
}
|
||||
#topbar .rechts { margin-left: auto; display: flex; align-items: center; gap: var(--s-regular); }
|
||||
#topbar .konto {
|
||||
display: flex; align-items: center; gap: var(--s-snug);
|
||||
background: none; border: 0; color: var(--text-dim); padding: 0;
|
||||
}
|
||||
#topbar .konto .kreis {
|
||||
width: 28px; height: 28px; border-radius: 50%;
|
||||
background: var(--accent); color: #fff;
|
||||
display: grid; place-items: center; font-size: 13px; font-weight: 600;
|
||||
}
|
||||
|
||||
.marke {
|
||||
font-size: 20px; font-weight: 700; letter-spacing: -.02em;
|
||||
padding: 0 var(--s-loose) var(--s-loose);
|
||||
color: var(--accent);
|
||||
/* ---------- Grundgerüst ---------- */
|
||||
|
||||
#app { display: flex; min-height: 100%; padding-top: var(--topbar-h); }
|
||||
|
||||
#chrome {
|
||||
position: fixed; top: var(--topbar-h); bottom: 0; left: 0;
|
||||
width: var(--sidebar-w); overflow-y: auto;
|
||||
background: #0E0E11;
|
||||
border-right: 1px solid var(--line);
|
||||
padding: var(--s-loose) 0;
|
||||
display: flex; flex-direction: column; gap: 2px;
|
||||
}
|
||||
|
||||
.nav-gruppe {
|
||||
font-size: 11px; text-transform: uppercase; letter-spacing: .08em;
|
||||
color: var(--text-faint); padding: var(--s-loose) var(--s-loose) var(--s-tight);
|
||||
font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
|
||||
color: var(--text-faint); padding: var(--s-loose) var(--s-loose) var(--s-snug);
|
||||
}
|
||||
|
||||
#chrome button {
|
||||
display: block; width: calc(100% - var(--s-regular)); margin: 0 var(--s-snug);
|
||||
text-align: left; background: none; border: 0; cursor: pointer;
|
||||
padding: var(--s-snug) var(--s-regular); border-radius: var(--r-control);
|
||||
color: var(--text-dim); font-size: 14px;
|
||||
display: flex; align-items: center; gap: var(--s-regular);
|
||||
background: none; border: 0; text-align: left;
|
||||
padding: 9px var(--s-loose); color: var(--text-dim);
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
/* Jede Mediathek eine Zeile: Name links, Zahl rechts. */
|
||||
#chrome button { display: flex; align-items: center; gap: var(--s-tight); }
|
||||
#chrome button > span:first-child {
|
||||
#chrome button > span.name {
|
||||
flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
}
|
||||
#chrome button .icon { flex: none; color: var(--text-muted); }
|
||||
#chrome button:hover { color: var(--text); background: rgba(255, 255, 255, .04); }
|
||||
#chrome button:hover .icon { color: var(--text-dim); }
|
||||
|
||||
/* **Der Balken links, nicht ein gefüllter Knopf.** Bei Plex markiert ein
|
||||
schmaler farbiger Strich die aktive Zeile; das liest sich in einer langen
|
||||
Liste ruhiger als ein leuchtender Block. */
|
||||
#chrome button.check {
|
||||
color: var(--accent); border-left-color: var(--accent);
|
||||
background: linear-gradient(90deg, var(--accent-soft), transparent 60%);
|
||||
}
|
||||
#chrome button.check .icon { color: var(--accent); }
|
||||
|
||||
#chrome button .zahl {
|
||||
flex: none; font-size: 11px; font-variant-numeric: tabular-nums;
|
||||
color: var(--text-muted); background: var(--elevated);
|
||||
padding: 1px 6px; border-radius: 8px;
|
||||
color: var(--text-faint);
|
||||
}
|
||||
#chrome button.check .zahl { background: rgba(255, 255, 255, .22); color: #fff; }
|
||||
|
||||
#chrome button:hover { background: var(--elevated); color: var(--text); }
|
||||
#chrome button.check { background: var(--accent-dim); color: #fff; }
|
||||
#chrome button.check .zahl { color: var(--accent); }
|
||||
|
||||
.nav-fuss { margin-top: auto; padding-top: var(--s-loose); }
|
||||
|
||||
#content { flex: 1; min-width: 0; padding: var(--s-section); }
|
||||
#content {
|
||||
flex: 1; min-width: 0;
|
||||
margin-left: var(--sidebar-w);
|
||||
padding: var(--s-section) var(--s-page) var(--s-page);
|
||||
}
|
||||
|
||||
/* ---------- Anmeldung ---------- */
|
||||
|
||||
#login {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
min-height: 100vh; padding: var(--s-loose);
|
||||
min-height: 100vh; display: grid; place-items: center; padding: var(--s-section);
|
||||
background: var(--canvas);
|
||||
}
|
||||
.login-card {
|
||||
width: 100%; max-width: 360px; background: var(--surface);
|
||||
border: 1px solid var(--separator); border-radius: var(--r-panel);
|
||||
padding: var(--s-section); display: flex; flex-direction: column; gap: var(--s-regular);
|
||||
width: 100%; max-width: 360px;
|
||||
display: flex; flex-direction: column; gap: var(--s-regular);
|
||||
background: var(--surface); border: 1px solid var(--line);
|
||||
border-radius: var(--r-control); padding: var(--s-section);
|
||||
}
|
||||
.login-card h1 { margin: 0; font-size: 26px; letter-spacing: -.02em; }
|
||||
.login-card h1 { margin: 0; font-size: 26px; letter-spacing: -.02em; color: var(--accent); }
|
||||
|
||||
/* ---------- Bedienelemente ---------- */
|
||||
/* ---------- Kopf einer Mediathek ---------- */
|
||||
|
||||
.field {
|
||||
width: 100%; background: var(--elevated); border: 1px solid var(--separator);
|
||||
border-radius: var(--r-control); padding: 10px var(--s-regular); outline: none;
|
||||
.seitenkopf {
|
||||
display: flex; align-items: flex-start; gap: var(--s-section);
|
||||
margin-bottom: var(--s-section);
|
||||
}
|
||||
.field:focus { border-color: var(--accent); }
|
||||
|
||||
.btn {
|
||||
background: var(--elevated); border: 1px solid var(--separator);
|
||||
border-radius: var(--r-control); padding: 9px var(--s-loose);
|
||||
cursor: pointer; white-space: nowrap;
|
||||
.seitenkopf .wer { min-width: 0; }
|
||||
.seitenkopf h1 { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.02em; }
|
||||
.seitenkopf .quelle {
|
||||
font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint);
|
||||
}
|
||||
.btn:hover:not(:disabled) { background: #2A2A30; }
|
||||
.btn:disabled { opacity: .5; cursor: default; }
|
||||
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
|
||||
.btn-primary:hover:not(:disabled) { background: #CB5BD3; }
|
||||
.btn-row { display: flex; gap: var(--s-snug); flex-wrap: wrap; align-items: center; }
|
||||
|
||||
.seg { display: inline-flex; background: var(--elevated); border-radius: var(--r-control); padding: 2px; }
|
||||
.seg button {
|
||||
background: none; border: 0; cursor: pointer; color: var(--text-dim);
|
||||
padding: 6px var(--s-loose); border-radius: 6px;
|
||||
/* Reiter in der Mitte, aktiver unterstrichen — wie bei Plex. */
|
||||
.reiter { display: flex; gap: var(--s-section); margin: 0 auto; }
|
||||
.reiter button {
|
||||
background: none; border: 0; padding: 4px 0 8px;
|
||||
color: var(--text-muted); font-weight: 500;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
.seg button.check { background: var(--accent); color: #fff; }
|
||||
.reiter button:hover { color: var(--text); }
|
||||
.reiter button.check { color: var(--accent); border-bottom-color: var(--accent); }
|
||||
|
||||
.seitentitel { margin: 0; font-size: 24px; letter-spacing: -.02em; }
|
||||
.row { display: flex; gap: var(--s-regular); align-items: center; margin-bottom: var(--s-section); }
|
||||
.row .field { max-width: 280px; margin-left: auto; }
|
||||
/* Die Sortierung steht neben der Suche und braucht weniger Platz. */
|
||||
.row .field.schmal { max-width: 190px; margin-left: auto; }
|
||||
.row .field.schmal + .field { margin-left: 0; }
|
||||
/* Filterzeile darunter. */
|
||||
.filterzeile {
|
||||
display: flex; align-items: center; gap: var(--s-regular);
|
||||
margin-bottom: var(--s-section); flex-wrap: wrap;
|
||||
}
|
||||
.filterzeile .anzahl {
|
||||
background: var(--elevated); border-radius: var(--r-card);
|
||||
padding: 2px 10px; font-size: 13px; color: var(--text-dim);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.filterzeile select, .filterzeile input {
|
||||
background: var(--elevated); border: 1px solid transparent;
|
||||
border-radius: var(--r-control); padding: 6px 10px; color: var(--text); outline: none;
|
||||
}
|
||||
.filterzeile select:focus, .filterzeile input:focus { border-color: var(--accent); }
|
||||
.filterzeile .suche { margin-left: auto; min-width: 220px; }
|
||||
|
||||
/* ---------- Karten und Raster ---------- */
|
||||
/* ---------- Kacheln ---------- */
|
||||
|
||||
.grid {
|
||||
.raster {
|
||||
display: grid; gap: var(--s-loose);
|
||||
grid-template-columns: repeat(auto-fill, minmax(var(--card-w), 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
}
|
||||
|
||||
.card {
|
||||
background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
|
||||
.kachel {
|
||||
display: flex; flex-direction: column; gap: var(--s-snug);
|
||||
background: none; border: 0; padding: 0; text-align: left; min-width: 0;
|
||||
}
|
||||
.card:hover .poster { transform: translateY(-3px); box-shadow: 0 10px 24px rgba(0,0,0,.5); }
|
||||
|
||||
.poster {
|
||||
aspect-ratio: 2 / 3; width: 100%; background: var(--placeholder);
|
||||
border-radius: var(--r-card); overflow: hidden; position: relative;
|
||||
.plakat {
|
||||
position: relative; width: 100%; aspect-ratio: 2 / 3;
|
||||
background: var(--placeholder);
|
||||
border-radius: var(--r-card); overflow: hidden;
|
||||
transition: transform .15s ease, box-shadow .15s ease;
|
||||
}
|
||||
.poster img { width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .2s; }
|
||||
.poster.geladen img { opacity: 1; }
|
||||
.plakat img {
|
||||
width: 100%; height: 100%; object-fit: cover;
|
||||
opacity: 0; transition: opacity .2s;
|
||||
}
|
||||
.plakat.geladen img { opacity: 1; }
|
||||
|
||||
/* Der Fortschrittsbalken auf der Kachel. Flaro zeigt ihn ab der ersten
|
||||
Sekunde — es gibt keinen Anteil, der zu klein wäre, um ihn zu merken. */
|
||||
.kachel:hover .plakat {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, .55);
|
||||
}
|
||||
|
||||
/* Der Abspielknopf erscheint beim Überfahren, mittig. */
|
||||
.schweber {
|
||||
position: absolute; inset: 0; display: grid; place-items: center;
|
||||
background: rgba(0, 0, 0, .45);
|
||||
opacity: 0; transition: opacity .15s ease;
|
||||
}
|
||||
.schweber svg { width: 44px; height: 44px; color: #fff; filter: drop-shadow(0 2px 8px rgba(0,0,0,.6)); }
|
||||
.kachel:hover .schweber { opacity: 1; }
|
||||
|
||||
/* **Haken und Zahl sitzen in derselben Ecke**, weil sie dieselbe Frage
|
||||
beantworten: ist hier noch etwas offen? */
|
||||
.ecke {
|
||||
position: absolute; top: 0; right: 0; z-index: 2;
|
||||
min-width: 26px; height: 26px; padding: 0 6px;
|
||||
display: grid; place-items: center;
|
||||
font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
|
||||
border-bottom-left-radius: var(--r-card);
|
||||
}
|
||||
.ecke.haken { background: rgba(0, 0, 0, .72); color: #fff; }
|
||||
.ecke.haken svg { width: 15px; height: 15px; }
|
||||
.ecke.zahl { background: var(--accent); color: #fff; }
|
||||
|
||||
/* Ab der ersten Sekunde sichtbar — darum die Mindestbreite. */
|
||||
.fortschritt {
|
||||
position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
|
||||
position: absolute; left: 0; right: 0; bottom: 0; height: 3px; z-index: 2;
|
||||
background: rgba(255, 255, 255, .22);
|
||||
}
|
||||
/* Eine Mindestbreite, damit auch eine einzige Minute sichtbar ist — bei
|
||||
2:36 Laufzeit wären das sonst anderthalb Bildpunkte. */
|
||||
.fortschritt > div { height: 100%; min-width: 4px; background: var(--accent); }
|
||||
|
||||
/* Die Plakette mit den offenen Folgen, wie bei Plex in der Ecke. */
|
||||
.offen {
|
||||
position: absolute; top: 6px; right: 6px;
|
||||
min-width: 18px; padding: 1px 5px; border-radius: 9px;
|
||||
background: var(--accent); color: #fff;
|
||||
font-size: 11px; font-weight: 600; line-height: 16px; text-align: center;
|
||||
.kacheltext { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
|
||||
.kacheltext strong {
|
||||
font-weight: 500; font-size: 13px;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
}
|
||||
|
||||
.rowline { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
|
||||
.rowline strong { font-weight: 500; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
|
||||
/* ---------- Waagerechte Reihen, wie bei Plex ---------- */
|
||||
|
||||
.reihe { margin-bottom: var(--s-section); }
|
||||
.reihe h2 {
|
||||
font-size: 17px; font-weight: 600; margin: 0;
|
||||
letter-spacing: -.01em;
|
||||
.kacheltext span {
|
||||
font-size: 12px; color: var(--text-muted);
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
}
|
||||
.kacheltext .dritte { color: var(--text-faint); }
|
||||
|
||||
/* ---------- Waagerechte Reihen ---------- */
|
||||
|
||||
.reihe { margin-bottom: var(--s-page); }
|
||||
|
||||
/* Überschrift links, „Alle zeigen" rechts — steht mehr drin, als die Reihe
|
||||
zeigt, soll die Reihe keine Sackgasse sein. */
|
||||
.reihe-kopf {
|
||||
display: flex; align-items: baseline; gap: var(--s-regular);
|
||||
display: flex; align-items: center; gap: var(--s-regular);
|
||||
margin-bottom: var(--s-regular);
|
||||
}
|
||||
.reihe-kopf h2 { margin: 0; font-size: 19px; font-weight: 700; letter-spacing: -.01em; }
|
||||
.reihe-kopf .mehr {
|
||||
margin-left: auto; flex: none;
|
||||
background: none; border: 0; cursor: pointer; padding: 0;
|
||||
font-size: 13px; color: var(--accent);
|
||||
background: none; border: 0; padding: 0; font-size: 13px; color: var(--accent);
|
||||
}
|
||||
.reihe-kopf .mehr:hover { text-decoration: underline; }
|
||||
.strip {
|
||||
display: grid; grid-auto-flow: column; grid-auto-columns: var(--card-w);
|
||||
gap: var(--s-loose); overflow-x: auto; padding-bottom: var(--s-snug);
|
||||
scrollbar-width: thin; scroll-snap-type: x proximity;
|
||||
.reihe-pfeile { margin-left: auto; display: flex; gap: var(--s-tight); }
|
||||
.pfeil {
|
||||
width: 28px; height: 28px; display: grid; place-items: center;
|
||||
background: var(--elevated); border: 0; border-radius: 50%; color: var(--text-dim);
|
||||
}
|
||||
.pfeil:hover { background: var(--raised); color: var(--text); }
|
||||
.pfeil svg { width: 16px; height: 16px; }
|
||||
|
||||
.strip {
|
||||
display: grid; grid-auto-flow: column; grid-auto-columns: 150px;
|
||||
gap: var(--s-loose);
|
||||
overflow-x: auto; scroll-snap-type: x proximity;
|
||||
scrollbar-width: none; padding-bottom: var(--s-tight);
|
||||
}
|
||||
.strip::-webkit-scrollbar { display: none; }
|
||||
.strip > * { scroll-snap-align: start; }
|
||||
.strip::-webkit-scrollbar { height: 8px; }
|
||||
.strip::-webkit-scrollbar-thumb { background: var(--elevated); border-radius: 4px; }
|
||||
|
||||
/* ---------- Detailseite ---------- */
|
||||
|
||||
.detail-head {
|
||||
position: relative; margin: calc(var(--s-section) * -1) calc(var(--s-section) * -1) var(--s-section);
|
||||
padding: var(--s-section); overflow: hidden;
|
||||
.detail { position: relative; }
|
||||
|
||||
/* **Der Hintergrund füllt die Seite, nicht nur einen Streifen.** Bei Plex
|
||||
liegt er unscharf und abgedunkelt hinter allem und gibt der Seite die
|
||||
Farbe des Films. */
|
||||
.detail-hintergrund {
|
||||
position: fixed; top: var(--topbar-h); left: var(--sidebar-w); right: 0; bottom: 0;
|
||||
z-index: -1;
|
||||
background-size: cover; background-position: center top;
|
||||
opacity: .28; filter: blur(2px);
|
||||
mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,.45) 55%, transparent 92%);
|
||||
}
|
||||
/* Der unscharfe Hintergrund, der die Seite trägt — Plex' auffälligster Zug. */
|
||||
.detail-head::before {
|
||||
content: ''; position: absolute; inset: -40px;
|
||||
background-image: var(--backdrop); background-size: cover; background-position: center;
|
||||
filter: blur(28px) saturate(1.2); opacity: .35; z-index: 0;
|
||||
|
||||
.detail-kopf {
|
||||
display: flex; gap: var(--s-page); align-items: flex-start;
|
||||
margin-bottom: var(--s-page);
|
||||
}
|
||||
.detail-head::after {
|
||||
content: ''; position: absolute; inset: 0; z-index: 0;
|
||||
background: linear-gradient(to bottom, rgba(11,11,13,.3), var(--canvas));
|
||||
.detail-kopf .plakat {
|
||||
flex: none; width: 240px;
|
||||
box-shadow: 0 12px 40px rgba(0, 0, 0, .6);
|
||||
}
|
||||
.detail-head > * { position: relative; z-index: 1; }
|
||||
.detail-text { min-width: 0; flex: 1; padding-top: var(--s-snug); }
|
||||
|
||||
.detail-inner { display: flex; gap: var(--s-section); margin-top: var(--s-loose); align-items: flex-start; }
|
||||
.detail-inner .poster { width: 200px; flex: 0 0 200px; }
|
||||
.detail-text h1 { margin: 0 0 var(--s-snug); font-size: 30px; letter-spacing: -.02em; }
|
||||
.detail-text p { margin: 0; color: var(--text-dim); max-width: 60ch; }
|
||||
|
||||
.detail h2 { font-size: 17px; margin: var(--s-section) 0 var(--s-regular); }
|
||||
|
||||
/* ---------- Listen und Einstellungen ---------- */
|
||||
|
||||
.settings { display: flex; flex-direction: column; gap: var(--s-regular); }
|
||||
.setting {
|
||||
background: var(--surface); border: 1px solid var(--separator);
|
||||
border-radius: var(--r-panel); padding: var(--s-loose);
|
||||
display: flex; flex-direction: column; gap: var(--s-snug);
|
||||
/* Der Schriftzug des Films statt der Systemschrift — wenn es einen gibt. */
|
||||
.detail-text .schriftzug {
|
||||
max-width: 420px; max-height: 110px; margin-bottom: var(--s-regular);
|
||||
object-fit: contain; object-position: left bottom; display: block;
|
||||
}
|
||||
button.setting { cursor: pointer; text-align: left; width: 100%; }
|
||||
button.setting:hover { background: var(--elevated); }
|
||||
.detail-text h1 { margin: 0 0 var(--s-snug); font-size: 34px; font-weight: 700; letter-spacing: -.03em; }
|
||||
.detail-text .unter { margin: 0 0 var(--s-regular); font-size: 17px; color: var(--text-dim); }
|
||||
|
||||
.hint { color: var(--text-dim); font-size: 13px; }
|
||||
.tiny { color: var(--text-faint); font-size: 12px; }
|
||||
.note { color: var(--text-faint); font-size: 12px; }
|
||||
|
||||
.error {
|
||||
background: rgba(220, 60, 60, .14); border: 1px solid rgba(220, 60, 60, .4);
|
||||
color: #FF9A9A; border-radius: var(--r-control); padding: var(--s-regular);
|
||||
.eckdaten {
|
||||
display: flex; align-items: center; gap: var(--s-regular); flex-wrap: wrap;
|
||||
color: var(--text-dim); font-size: 13px; margin-bottom: var(--s-loose);
|
||||
}
|
||||
.empty { color: var(--text-faint); padding: var(--s-section) 0; grid-column: 1 / -1; }
|
||||
.freigabe {
|
||||
border: 1px solid var(--text-faint); border-radius: 3px;
|
||||
padding: 0 6px; font-size: 11px; font-weight: 700; letter-spacing: .04em;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
.bewertung { display: flex; align-items: center; gap: 5px; color: var(--text); font-weight: 600; }
|
||||
.bewertung svg { width: 15px; height: 15px; color: var(--accent); }
|
||||
|
||||
.werbezeile { color: var(--text-muted); font-style: italic; margin: 0 0 var(--s-loose); }
|
||||
.beschreibung { max-width: 70ch; margin: 0 0 var(--s-section); color: var(--text-dim); }
|
||||
|
||||
.aktionen { display: flex; align-items: center; gap: var(--s-regular); margin-bottom: var(--s-section); flex-wrap: wrap; }
|
||||
|
||||
.btn {
|
||||
display: inline-flex; align-items: center; gap: var(--s-snug);
|
||||
background: var(--elevated); border: 0; border-radius: var(--r-pill);
|
||||
padding: 9px var(--s-loose); color: var(--text);
|
||||
}
|
||||
.btn:hover { background: var(--raised); }
|
||||
.btn:disabled { opacity: .5; cursor: default; }
|
||||
.btn svg { width: 18px; height: 18px; }
|
||||
.btn-primary { background: var(--accent); color: #fff; font-weight: 600; }
|
||||
.btn-primary:hover { background: var(--accent-dim); }
|
||||
|
||||
/* Runde Knöpfe für alles ohne Beschriftung — wie Plex' Merkliste und Haken. */
|
||||
.rund {
|
||||
width: 38px; height: 38px; padding: 0; border-radius: 50%;
|
||||
display: grid; place-items: center;
|
||||
background: none; border: 1px solid var(--line); color: var(--text-dim);
|
||||
}
|
||||
.rund:hover { border-color: var(--text-muted); color: var(--text); }
|
||||
.rund.an { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||
.rund svg { width: 19px; height: 19px; }
|
||||
|
||||
/* Die Medienangaben als Tabelle — Plex' „Video / Ton / Untertitel". */
|
||||
.medientabelle { display: grid; grid-template-columns: auto 1fr; gap: var(--s-snug) var(--s-section); margin-bottom: var(--s-section); }
|
||||
.medientabelle dt { color: var(--text-muted); font-size: 13px; }
|
||||
.medientabelle dd { margin: 0; font-size: 13px; }
|
||||
|
||||
/* Besetzung: runde Porträts, wie bei Plex. */
|
||||
.besetzung { display: grid; grid-auto-flow: column; grid-auto-columns: 110px; gap: var(--s-loose); overflow-x: auto; scrollbar-width: none; }
|
||||
.besetzung::-webkit-scrollbar { display: none; }
|
||||
.kopf-kachel { display: flex; flex-direction: column; align-items: center; gap: var(--s-snug); text-align: center; }
|
||||
.kopf-kachel .portrait {
|
||||
width: 92px; height: 92px; border-radius: 50%; overflow: hidden;
|
||||
background: var(--placeholder); display: grid; place-items: center;
|
||||
color: var(--text-faint); font-size: 26px; font-weight: 600;
|
||||
}
|
||||
.kopf-kachel .portrait img { width: 100%; height: 100%; object-fit: cover; }
|
||||
.kopf-kachel strong { font-size: 12px; font-weight: 500; }
|
||||
.kopf-kachel span { font-size: 11px; color: var(--text-muted); }
|
||||
|
||||
/* Genre-Kacheln, Plex' „Kategorien". */
|
||||
.kategorien { display: grid; gap: var(--s-loose); grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }
|
||||
.kategorie {
|
||||
aspect-ratio: 16 / 9; border: 0; border-radius: var(--r-control);
|
||||
display: grid; place-items: center; color: #fff;
|
||||
font-size: 19px; font-weight: 700; letter-spacing: -.01em;
|
||||
position: relative; overflow: hidden;
|
||||
}
|
||||
.kategorie:hover { filter: brightness(1.15); }
|
||||
|
||||
/* ---------- Kleinteile ---------- */
|
||||
|
||||
h2 { font-size: 19px; font-weight: 700; letter-spacing: -.01em; margin: 0 0 var(--s-regular); }
|
||||
.seitentitel { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.02em; }
|
||||
|
||||
.einstellungen { display: flex; flex-direction: column; gap: var(--s-regular); margin-bottom: var(--s-page); }
|
||||
.einstellung {
|
||||
background: var(--surface); border: 1px solid var(--line);
|
||||
border-radius: var(--r-control); padding: var(--s-loose);
|
||||
display: flex; flex-direction: column; gap: var(--s-regular);
|
||||
}
|
||||
.einstellung.waehlbar { text-align: left; width: 100%; }
|
||||
.einstellung.waehlbar:hover { border-color: var(--accent); }
|
||||
|
||||
.zeile { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
|
||||
.zeile strong { font-weight: 600; }
|
||||
.winzig { font-size: 12px; color: var(--text-muted); }
|
||||
.hinweis { color: var(--text-dim); font-size: 13px; }
|
||||
|
||||
.feld {
|
||||
background: var(--elevated); border: 1px solid transparent;
|
||||
border-radius: var(--r-control); padding: 9px var(--s-regular);
|
||||
color: var(--text); outline: none; min-width: 0;
|
||||
}
|
||||
.feld:focus { border-color: var(--accent); }
|
||||
.knopfreihe { display: flex; gap: var(--s-snug); flex-wrap: wrap; align-items: center; }
|
||||
|
||||
.fehler {
|
||||
background: rgba(229, 72, 77, .12); border: 1px solid rgba(229, 72, 77, .35);
|
||||
border-radius: var(--r-control); padding: var(--s-regular); color: #FF9A9D; font-size: 13px;
|
||||
}
|
||||
.leer { color: var(--text-muted); padding: var(--s-section) 0; }
|
||||
|
||||
.spinner {
|
||||
width: 22px; height: 22px; margin: var(--s-section) auto;
|
||||
border: 2px solid var(--separator); border-top-color: var(--accent);
|
||||
border: 2px solid var(--line); border-top-color: var(--accent);
|
||||
border-radius: 50%; animation: dreh .7s linear infinite;
|
||||
}
|
||||
@keyframes dreh { to { transform: rotate(360deg); } }
|
||||
|
||||
/* ---------- Abspielen ---------- */
|
||||
|
||||
.pl-fill { position: fixed; inset: 0; background: #000; z-index: 50; }
|
||||
|
||||
/* ---------- Hinweis auf TMDB ---------- */
|
||||
|
||||
.attribution {
|
||||
margin-top: var(--s-section); padding-top: var(--s-loose);
|
||||
border-top: 1px solid var(--separator);
|
||||
color: var(--text-faint); font-size: 11px; display: flex; gap: var(--s-snug); align-items: center;
|
||||
display: flex; align-items: center; gap: var(--s-snug);
|
||||
margin-top: var(--s-page); padding-top: var(--s-loose);
|
||||
border-top: 1px solid var(--line);
|
||||
color: var(--text-faint); font-size: 12px;
|
||||
}
|
||||
.attribution img { height: 14px; opacity: .7; }
|
||||
|
||||
/* ---------- Schmale Fenster ---------- */
|
||||
/* Der Spieler über allem. */
|
||||
.pl-fill {
|
||||
position: fixed; inset: 0; z-index: 100; background: #000;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
/* ---------- Schmale Bildschirme ---------- */
|
||||
|
||||
@media (max-width: 860px) {
|
||||
#app { flex-direction: column; }
|
||||
#chrome {
|
||||
width: 100%; flex: none; height: auto; position: static;
|
||||
flex-direction: row; overflow-x: auto; padding: var(--s-snug);
|
||||
border-right: 0; border-bottom: 1px solid var(--separator);
|
||||
position: static; width: auto; flex-direction: row; overflow-x: auto;
|
||||
border-right: 0; border-bottom: 1px solid var(--line); padding: var(--s-snug);
|
||||
}
|
||||
.marke, .nav-gruppe { display: none; }
|
||||
#chrome button { border-left: 0; border-bottom: 3px solid transparent; white-space: nowrap; }
|
||||
#chrome button.check { border-left-color: transparent; border-bottom-color: var(--accent); background: none; }
|
||||
.nav-gruppe { display: none; }
|
||||
.nav-fuss { margin: 0; padding: 0; display: flex; }
|
||||
#content { padding: var(--s-loose); }
|
||||
.detail-inner { flex-direction: column; }
|
||||
.detail-inner .poster { width: 140px; flex: none; }
|
||||
#content { margin-left: 0; padding: var(--s-loose); }
|
||||
.detail-hintergrund { left: 0; }
|
||||
.detail-kopf { flex-direction: column; gap: var(--s-loose); }
|
||||
.detail-kopf .plakat { width: 160px; }
|
||||
.detail-text h1 { font-size: 26px; }
|
||||
#topbar .suchfeld { max-width: none; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user