feat: initial import of Jellyfin Aurora Noir theme and assets

This commit is contained in:
eldov
2026-08-30 05:16:43 +02:00
commit 2c39bc9cf4
5 changed files with 1285 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
# Jellyfin Container — Theme & Branding (Stand 2026-08-16)
## Aktuelles Theme: "Aurora Noir"
Cinematic Dark Theme (Aurora-Cyan -> Indigo auf #050810), ersetzt das alte
"Cyberpunk Neon"-Theme (das 2 MB Base64 inline im CSS transportierte).
## Dateien
| Pfad | Zweck |
|---|---|
| `web-assets/aurora_noir.css` | Quelldatei des Themes (SSOT zum Editieren) |
| `web-assets/custom_bg.webp` | Hintergrundbild 1920x1080, ~110 KB |
| `library/branding.xml` | Aktive Konfiguration (CSS XML-escaped eingebettet) |
| `library/branding.xml.bak-20260816` | Rollback des alten Themes |
## Deployment-Pfad
- docker-compose mountet `./web-assets` nach `/usr/share/jellyfin/web/custom-assets:ro`
- Assets sind erreichbar unter: `/web/custom-assets/<datei>` (nicht `/custom-assets/`!)
- CSS-Änderungen: `web-assets/aurora_noir.css` editieren -> XML-escape -> in
`<CustomCss>` von `library/branding.xml` schreiben -> `docker restart jellyfin`
Regeneration des branding.xml aus der CSS-Datei:
```bash
cd /opt/containers/jellyfin
python3 - <<'PYEOF'
import xml.sax.saxutils as sx
css = open('web-assets/aurora_noir.css').read()
out = ('<?xml version="1.0" encoding="utf-8"?>\n<BrandingOptions>\n'
' <LoginDisclaimer>Private media cloud. Authorized access only.</LoginDisclaimer>\n'
' <CustomCss>%s</CustomCss>\n'
' <SplashscreenEnabled>false</SplashscreenEnabled>\n'
'</BrandingOptions>\n') % sx.escape(css)
open('library/branding.xml', 'w').write(out)
print('written', len(out))
PYEOF
docker restart jellyfin
```
## Rollback auf altes Theme
```bash
cp /opt/containers/jellyfin/library/branding.xml.bak-20260816 /opt/containers/jellyfin/library/branding.xml
docker restart jellyfin
```
## Verifikation (2026-08-16)
6 UI-Pfade im Browser geprüft (Home, Bibliothek, Album-Detail, Wiedergabe,
Suche, Login): Theme aktiv, keine HTTP-Fehler, Container healthy.
Payload: 10.4 KB statt 2.02 MB (-99.5%).
## Admin-SPA-Theme-Fix (2026-08-16, final implementiert)
Jellyfin 10.11: Die React-Admin-Routen (#/dashboard, #/metadata) entfernen das
Custom-CSS beim Mount. Geloest via Traefik rewritebody-Plugin (router-scoped,
nur am jellyfin-Router, KEIN Eingriff in andere Services):
### Architektur
1. `traefik.yml`: Plugin `github.com/traefik/plugin-rewritebody v0.3.1` registriert
2. `dynamic_conf.yml`: Zwei Middlewares:
- `jf-no-compress`: stript Accept-Encoding (Plugin überspringt komprimierte Bodies)
- `jf-inject-theme`: injiziert Watcher-Script vor `</body>`
3. `docker-compose.yml` (jellyfin): Middlewares am Router `jellyfin` (nicht am Login-Router)
### Watcher-Script-Logik (bidirektionale Dedupe)
- Setzt `<link aurora_noir.css>`, wenn weder Link noch Inline-AURORA-style existieren (Admin-Routen)
- ENTFERNT den Link, sobald Legacy-Inline-style erscheint (Legacy-Routen wie Home)
- Re-Injection via MutationObserver + setInterval(1000ms) gegen React-Remounts
### CSS-Updates (wichtig)
Bei CSS-Aenderungen in `aurora_noir.css`:
1. Datei auf VPS aktualisieren + branding.xml regenerieren + `docker restart jellyfin`
2. Cache-Bust im Watcher erhoehen: in `dynamic_conf.yml` beim jf-inject-theme
Script `aurora_noir.css?v=2` -> `?v=3` setzen + `docker restart traefik`
(Browser-HTTP-Cache otherwise haelt alte CSS fest)
### MUI-Admin-Styling (2026-08-16, nachgeruestet)
Admin-SPA nutzt MUI-Komponenten - Legacy-Selektoren greifen dort nicht.
`aurora_noir.css` enthaelt eigene `.Mui*`-Override-Sektion (Papers, Cards,
Buttons, Inputs, Tables, Dialogs, Switches, Chips). Verifiziert: 25 MUI-Regeln
aktiv, Paper radius 14px + Aurora-Border, Buttons Aurora-Gradient.
### Verifikation (2026-08-16)
- Test A: Dashboard-Direktload -> Link aktiv, BG gestylt
- Test B: SPA Dashboard->Home -> deduped (nur Legacy-inline, 0 Links)
- Test C: SPA Home->Dashboard -> Link kehrt zurück, BG gestylt
- Test D: Login -> Legacy-Weg unberührt (blur 22px Panel)
- Link-Entfernungs-Angriff: Interval-Watcher stellt Link in <1.5s wieder her
- HTML-Overhead: +620B (Script), CSS nur auf Admin-Routen geladen
- Nachbar-Services: unberührt (gitea 200, home 302, traefik 302)
### Browser-Cache-Hinweis
Nach Änderungen am Watcher-Script: Browser-Cache UND Jellyfin-Service-Worker
leeren (about:reload genügt nicht immer), sonst altes HTML:
`caches.keys().then(ks=>ks.forEach(k=>caches.delete(k)))` + harte Reload-Nav
mit `?v=<timestamp>` Query.
### Rollback
```bash
# Theme-Injection entfernen:
cp /opt/containers/traefik3-crowdsec-stack/traefik/dynamic_conf.yml.bak-jftheme /opt/containers/traefik3-crowdsec-stack/traefik/dynamic_conf.yml
cp /opt/containers/traefik3-crowdsec-stack/traefik/traefik.yml.bak-jftheme /opt/containers/traefik3-crowdsec-stack/traefik/traefik.yml
# compose label zurücksetzen (middlewares-Zeile), dann:
docker restart traefik && cd /opt/containers/jellyfin && docker compose up -d
```
Executable
+588
View File
@@ -0,0 +1,588 @@
<?xml version="1.0" encoding="utf-8"?>
<BrandingOptions>
<LoginDisclaimer>Private media cloud. Authorized access only.</LoginDisclaimer>
<CustomCss>/* ============================================================
AURORA NOIR - cinematic theme for Stream Xtream
Accent: aurora cyan -&gt; indigo | Base: deep space #050810
Perf: single external bg asset, blur only on chrome surfaces
============================================================ */
:root {
--an-bg: #050810;
--an-surface: rgba(13, 18, 30, 0.62);
--an-surface-solid: #0b101c;
--an-border: rgba(148, 163, 184, 0.14);
--an-border-hover: rgba(34, 211, 238, 0.55);
--an-accent: #22d3ee;
--an-accent-2: #818cf8;
--an-text: #f1f5f9;
--an-text-dim: #94a3b8;
--an-radius: 14px;
--an-glow: 0 0 24px rgba(34, 211, 238, 0.30);
--an-shadow: 0 18px 48px rgba(0, 0, 0, 0.55);
}
html {
color-scheme: dark;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
scrollbar-color: rgba(34, 211, 238, 0.45) #070b14;
}
body {
background-color: var(--an-bg);
color: var(--an-text);
}
/* ---------------- Ambient background ---------------- */
.backgroundContainer {
background: #050810 url(/web/custom-assets/custom_bg.webp) center / cover no-repeat fixed !important;
}
/* Cinematic grade over fanart backdrops so text stays readable */
.backdropImage {
filter: saturate(1.05) brightness(0.45) !important;
}
.backgroundContainer::after {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
background: linear-gradient(180deg,
rgba(5, 8, 16, 0.66) 0%,
rgba(5, 8, 16, 0.18) 34%,
rgba(5, 8, 16, 0.30) 62%,
rgba(5, 8, 16, 0.78) 100%);
}
/* ---------------- Header ---------------- */
.skinHeader {
background: linear-gradient(180deg, rgba(5, 8, 16, 0.92), rgba(5, 8, 16, 0.55)) !important;
backdrop-filter: blur(18px) saturate(1.25);
-webkit-backdrop-filter: blur(18px) saturate(1.25);
border-bottom: 1px solid var(--an-border) !important;
}
.headerTop {
padding: 0.6em 0.9em;
}
.emby-tab-button {
color: var(--an-text-dim);
}
.emby-tab-button-active {
color: var(--an-accent) !important;
text-shadow: 0 0 18px rgba(34, 211, 238, 0.45);
}
.paper-icon-button-light:hover:not(:disabled) {
color: var(--an-accent);
background-color: rgba(34, 211, 238, 0.10);
border-radius: 8px;
}
.paper-icon-button-light:focus-visible {
outline: 2px solid var(--an-accent);
outline-offset: 2px;
border-radius: 8px;
}
.headerButton {
color: var(--an-text);
}
/* ---------------- Drawer / side menu ---------------- */
.mainDrawer {
background: rgba(7, 11, 20, 0.96) !important;
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border-right: 1px solid var(--an-border);
}
.navDrawerMask {
background: rgba(2, 4, 8, 0.55);
}
.navMenuOption {
border-radius: 10px;
margin: 0.25em 0.6em;
}
.navMenuOptionIcon {
color: var(--an-accent) !important;
text-shadow: 0 0 14px rgba(34, 211, 238, 0.55);
}
.navMenuOption:hover,
.navMenuOption.showFocus {
background: rgba(34, 211, 238, 0.12) !important;
}
.navMenuOptionText {
color: var(--an-text);
font-weight: 500;
}
/* ---------------- Cards ---------------- */
.cardBox {
border-radius: var(--an-radius);
border: 1px solid var(--an-border);
background: var(--an-surface);
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.3, 1),
box-shadow 0.28s ease, border-color 0.28s ease;
}
.card:hover .cardBox,
.card.showFocus .cardBox {
transform: translateY(-4px);
border-color: var(--an-border-hover);
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.60), var(--an-glow);
}
.cardImageContainer {
border-radius: calc(var(--an-radius) - 2px) calc(var(--an-radius) - 2px) 0 0;
background: #0b101c;
}
.cardText {
color: var(--an-text-dim);
}
.cardText:first-child {
color: var(--an-text);
}
.defaultCardBackground {
background: linear-gradient(135deg, #101b2e, #0a1120) !important;
}
/* Watched / unwatched indicators */
.playedIndicator {
background: rgba(52, 211, 153, 0.92) !important;
color: #052015 !important;
border-radius: 8px 0 0 0;
font-weight: 700;
box-shadow: 0 2px 12px rgba(52, 211, 153, 0.5);
}
.countIndicator {
background: linear-gradient(135deg, var(--an-accent), var(--an-accent-2)) !important;
border-radius: 999px;
font-weight: 700;
box-shadow: var(--an-glow);
}
/* Progress bars under cards */
.itemProgressBar {
height: 4px;
background: rgba(255, 255, 255, 0.10);
border-radius: 0 0 var(--an-radius) var(--an-radius);
}
.itemProgressBarForeground {
background: linear-gradient(90deg, var(--an-accent), var(--an-accent-2)) !important;
border-radius: 0 0 var(--an-radius) var(--an-radius);
}
/* ---------------- Buttons ---------------- */
.button-submit,
.btnPlay,
.fab.primary {
background: linear-gradient(135deg, #22d3ee 0%, #818cf8 100%) !important;
color: #ffffff !important;
font-weight: 600;
border-radius: 10px !important;
border: none !important;
box-shadow: 0 6px 18px rgba(34, 211, 238, 0.25);
transition: filter 0.2s ease, box-shadow 0.2s ease;
}
.button-submit:hover,
.button-submit:focus,
.btnPlay:hover,
.fab.primary:hover {
filter: brightness(1.1);
box-shadow: 0 8px 26px rgba(34, 211, 238, 0.45);
}
.emby-button:not(.raised):focus-visible,
.emby-button:not(.raised):hover {
color: var(--an-accent);
}
/* ---------------- Detail page ---------------- */
.itemDetailImage,
.detailImageContainer img {
border-radius: 12px;
border: 1px solid var(--an-border);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.65);
}
h1,
h2,
h3 {
color: var(--an-text) !important;
text-shadow: 0 2px 24px rgba(0, 0, 0, 0.85);
}
.nameContainer,
.itemName,
.itemMiscInfo {
text-shadow: 0 2px 24px rgba(0, 0, 0, 0.85);
}
.secondaryText,
.itemMiscInfo,
.mediaInfoText {
color: var(--an-text-dim) !important;
}
.mediaInfoText {
background: rgba(13, 18, 30, 0.72);
border: 1px solid var(--an-border);
border-radius: 8px;
padding: 0.25em 0.7em;
}
/* ---------------- Dialogs, sheets, menus ---------------- */
.dialog {
background: rgba(9, 13, 23, 0.97) !important;
border: 1px solid var(--an-border);
border-radius: 16px !important;
box-shadow: var(--an-shadow);
}
.actionSheet {
background: rgba(9, 13, 23, 0.97) !important;
border: 1px solid var(--an-border);
border-radius: 16px !important;
overflow: hidden;
box-shadow: var(--an-shadow);
}
.formDialogHeader {
border-bottom: 1px solid var(--an-border);
}
.formDialogFooter {
border-top: 1px solid var(--an-border);
}
.actionSheetMenuItem,
.listItem {
border-radius: 10px;
color: var(--an-text) !important;
}
.actionSheetMenuItem:hover,
.actionSheetMenuItem.showFocus,
.listItem:hover {
background: rgba(34, 211, 238, 0.10) !important;
}
.listItem:hover .listItemBody,
.listItem .secondary {
color: var(--an-text-dim);
}
.paperList {
background: rgba(9, 13, 23, 0.72);
border: 1px solid var(--an-border);
border-radius: 12px;
}
/* ---------------- Inputs ---------------- */
.emby-input,
.emby-select,
.emby-textarea {
background: rgba(10, 15, 26, 0.85) !important;
border: 1px solid var(--an-border) !important;
border-radius: 10px !important;
color: var(--an-text) !important;
}
.emby-input:focus,
.emby-select:focus,
.emby-textarea:focus {
border-color: var(--an-accent) !important;
box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.18);
}
.emby-select option {
background: #0b101c;
color: var(--an-text);
}
.checkboxOutline {
border-radius: 6px;
border-color: var(--an-border);
}
.emby-checkbox:checked + .checkboxOutline {
background: linear-gradient(135deg, var(--an-accent), var(--an-accent-2)) !important;
border-color: transparent !important;
}
/* Player sliders */
.mdl-slider-background-lower {
background: linear-gradient(90deg, var(--an-accent), var(--an-accent-2)) !important;
border-radius: 999px;
}
.mdl-slider-background-upper {
background: rgba(255, 255, 255, 0.15) !important;
border-radius: 999px;
}
/* ---------------- Player OSD ---------------- */
.videoOsdBottom {
background: linear-gradient(0deg, rgba(3, 6, 12, 0.94), rgba(3, 6, 12, 0.0));
}
.osdHeader {
background: linear-gradient(180deg, rgba(3, 6, 12, 0.85), rgba(3, 6, 12, 0.0));
padding-top: 1em;
}
/* ---------------- Login page ---------------- */
#loginPage .visualLoginForm {
background: rgba(7, 11, 20, 0.78);
backdrop-filter: blur(22px) saturate(1.25);
-webkit-backdrop-filter: blur(22px) saturate(1.25);
border: 1px solid var(--an-border);
border-radius: 20px;
box-shadow: var(--an-shadow);
max-width: 480px;
margin: 0 auto;
padding: 2.6em 2.8em !important;
}
#loginPage .visualLoginForm h1 {
text-align: center;
letter-spacing: 0.5px;
}
#loginPage .disclaimerContainer {
text-align: center;
color: var(--an-text-dim);
}
/* ---------------- Toasts &amp; misc ---------------- */
.toast {
background: rgba(9, 13, 23, 0.95) !important;
border: 1px solid var(--an-border);
border-radius: 12px;
box-shadow: var(--an-shadow);
color: var(--an-text) !important;
}
.itemSelectionPanel {
background: rgba(34, 211, 238, 0.85) !important;
}
.sectionTitle,
.sectionTitleText {
color: var(--an-text) !important;
letter-spacing: 0.2px;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: #070b14;
}
::-webkit-scrollbar-thumb {
background: rgba(34, 211, 238, 0.35);
border-radius: 8px;
border: 2px solid #070b14;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(34, 211, 238, 0.6);
}
/* ---------------- Motion safety ---------------- */
@media (prefers-reduced-motion: reduce) {
.cardBox,
.button-submit,
.btnPlay,
.fab.primary {
transition: none !important;
}
.card:hover .cardBox,
.card.showFocus .cardBox {
transform: none !important;
}
}
/* ---------------- Admin-SPA (MUI) Overrides ---------------- */
.MuiPaper-root,
.MuiCard-root,
.MuiAccordion-root,
.MuiDrawer-paper {
background-color: var(--an-surface-solid) !important;
background-image: linear-gradient(160deg, rgba(13, 18, 30, 0.92), rgba(8, 12, 22, 0.97)) !important;
border: 1px solid var(--an-border) !important;
border-radius: 14px !important;
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.5) !important;
color: var(--an-text) !important;
}
.MuiCard-root:hover {
border-color: var(--an-border-hover);
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.6), var(--an-glow) !important;
}
.MuiAppBar-root,
.MuiToolbar-root {
background: linear-gradient(180deg, rgba(5, 8, 16, 0.95), rgba(5, 8, 16, 0.72)) !important;
backdrop-filter: blur(18px) saturate(1.25);
-webkit-backdrop-filter: blur(18px) saturate(1.25);
border-bottom: 1px solid var(--an-border) !important;
color: var(--an-text) !important;
}
.MuiTypography-root,
.MuiListItemText-primary,
.MuiListItemText-secondary,
.MuiTableCell-root {
color: var(--an-text) !important;
}
.MuiListItemText-secondary,
.MuiTypography-colorTextSecondary {
color: var(--an-text-dim) !important;
}
.MuiButton-containedPrimary,
.MuiButton-contained {
background: linear-gradient(135deg, #22d3ee 0%, #818cf8 100%) !important;
color: #ffffff !important;
border-radius: 10px !important;
font-weight: 600;
box-shadow: 0 6px 18px rgba(34, 211, 238, 0.25);
}
.MuiButton-contained:hover {
filter: brightness(1.1);
box-shadow: 0 8px 26px rgba(34, 211, 238, 0.45);
}
.MuiButton-outlined,
.MuiButton-text {
color: var(--an-accent) !important;
border-color: var(--an-border-hover) !important;
border-radius: 10px !important;
}
.MuiListItem-root:hover,
.MuiListItem-button:hover {
background: rgba(34, 211, 238, 0.10) !important;
}
.MuiListItemButton-root:hover {
background: rgba(34, 211, 238, 0.10) !important;
}
.Mui-selected,
.Mui-selected:hover {
background: rgba(34, 211, 238, 0.16) !important;
}
.MuiInputBase-root,
.MuiOutlinedInput-root,
.MuiFilledInput-root {
background: rgba(10, 15, 26, 0.85) !important;
border-radius: 10px !important;
}
.MuiOutlinedInput-notchedOutline {
border-color: var(--an-border) !important;
}
.MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline {
border-color: var(--an-accent) !important;
}
.MuiSwitch-switchBase.Mui-checked {
color: var(--an-accent) !important;
}
.MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track {
background: linear-gradient(90deg, var(--an-accent), var(--an-accent-2)) !important;
}
.MuiChip-root {
background: rgba(13, 18, 30, 0.85) !important;
border: 1px solid var(--an-border) !important;
color: var(--an-text) !important;
border-radius: 999px !important;
}
.MuiChip-root.MuiChip-colorPrimary {
background: linear-gradient(135deg, rgba(34, 211, 238, 0.2), rgba(129, 140, 248, 0.2)) !important;
color: var(--an-accent) !important;
}
.MuiTableCell-root {
border-bottom: 1px solid var(--an-border) !important;
}
.MuiTableHead-root .MuiTableCell-root {
color: var(--an-accent) !important;
font-weight: 600;
}
.MuiDivider-root {
border-color: var(--an-border) !important;
}
.MuiDialog-paper,
.MuiMenu-paper,
.MuiPopover-paper {
background: rgba(9, 13, 23, 0.97) !important;
border: 1px solid var(--an-border) !important;
border-radius: 16px !important;
box-shadow: var(--an-shadow) !important;
}
.MuiLinearProgress-bar {
background: linear-gradient(90deg, var(--an-accent), var(--an-accent-2)) !important;
}
.MuiCircularProgress-root {
color: var(--an-accent) !important;
}
.MuiAlert-root {
border-radius: 12px !important;
border: 1px solid var(--an-border) !important;
}
</CustomCss>
<SplashscreenEnabled>false</SplashscreenEnabled>
</BrandingOptions>
+582
View File
@@ -0,0 +1,582 @@
/* ============================================================
AURORA NOIR - cinematic theme for Stream Xtream
Accent: aurora cyan -> indigo | Base: deep space #050810
Perf: single external bg asset, blur only on chrome surfaces
============================================================ */
:root {
--an-bg: #050810;
--an-surface: rgba(13, 18, 30, 0.62);
--an-surface-solid: #0b101c;
--an-border: rgba(148, 163, 184, 0.14);
--an-border-hover: rgba(34, 211, 238, 0.55);
--an-accent: #22d3ee;
--an-accent-2: #818cf8;
--an-text: #f1f5f9;
--an-text-dim: #94a3b8;
--an-radius: 14px;
--an-glow: 0 0 24px rgba(34, 211, 238, 0.30);
--an-shadow: 0 18px 48px rgba(0, 0, 0, 0.55);
}
html {
color-scheme: dark;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
scrollbar-color: rgba(34, 211, 238, 0.45) #070b14;
}
body {
background-color: var(--an-bg);
color: var(--an-text);
}
/* ---------------- Ambient background ---------------- */
.backgroundContainer {
background: #050810 url(/web/custom-assets/custom_bg.webp) center / cover no-repeat fixed !important;
}
/* Cinematic grade over fanart backdrops so text stays readable */
.backdropImage {
filter: saturate(1.05) brightness(0.45) !important;
}
.backgroundContainer::after {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
background: linear-gradient(180deg,
rgba(5, 8, 16, 0.66) 0%,
rgba(5, 8, 16, 0.18) 34%,
rgba(5, 8, 16, 0.30) 62%,
rgba(5, 8, 16, 0.78) 100%);
}
/* ---------------- Header ---------------- */
.skinHeader {
background: linear-gradient(180deg, rgba(5, 8, 16, 0.92), rgba(5, 8, 16, 0.55)) !important;
backdrop-filter: blur(18px) saturate(1.25);
-webkit-backdrop-filter: blur(18px) saturate(1.25);
border-bottom: 1px solid var(--an-border) !important;
}
.headerTop {
padding: 0.6em 0.9em;
}
.emby-tab-button {
color: var(--an-text-dim);
}
.emby-tab-button-active {
color: var(--an-accent) !important;
text-shadow: 0 0 18px rgba(34, 211, 238, 0.45);
}
.paper-icon-button-light:hover:not(:disabled) {
color: var(--an-accent);
background-color: rgba(34, 211, 238, 0.10);
border-radius: 8px;
}
.paper-icon-button-light:focus-visible {
outline: 2px solid var(--an-accent);
outline-offset: 2px;
border-radius: 8px;
}
.headerButton {
color: var(--an-text);
}
/* ---------------- Drawer / side menu ---------------- */
.mainDrawer {
background: rgba(7, 11, 20, 0.96) !important;
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border-right: 1px solid var(--an-border);
}
.navDrawerMask {
background: rgba(2, 4, 8, 0.55);
}
.navMenuOption {
border-radius: 10px;
margin: 0.25em 0.6em;
}
.navMenuOptionIcon {
color: var(--an-accent) !important;
text-shadow: 0 0 14px rgba(34, 211, 238, 0.55);
}
.navMenuOption:hover,
.navMenuOption.showFocus {
background: rgba(34, 211, 238, 0.12) !important;
}
.navMenuOptionText {
color: var(--an-text);
font-weight: 500;
}
/* ---------------- Cards ---------------- */
.cardBox {
border-radius: var(--an-radius);
border: 1px solid var(--an-border);
background: var(--an-surface);
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.3, 1),
box-shadow 0.28s ease, border-color 0.28s ease;
}
.card:hover .cardBox,
.card.showFocus .cardBox {
transform: translateY(-4px);
border-color: var(--an-border-hover);
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.60), var(--an-glow);
}
.cardImageContainer {
border-radius: calc(var(--an-radius) - 2px) calc(var(--an-radius) - 2px) 0 0;
background: #0b101c;
}
.cardText {
color: var(--an-text-dim);
}
.cardText:first-child {
color: var(--an-text);
}
.defaultCardBackground {
background: linear-gradient(135deg, #101b2e, #0a1120) !important;
}
/* Watched / unwatched indicators */
.playedIndicator {
background: rgba(52, 211, 153, 0.92) !important;
color: #052015 !important;
border-radius: 8px 0 0 0;
font-weight: 700;
box-shadow: 0 2px 12px rgba(52, 211, 153, 0.5);
}
.countIndicator {
background: linear-gradient(135deg, var(--an-accent), var(--an-accent-2)) !important;
border-radius: 999px;
font-weight: 700;
box-shadow: var(--an-glow);
}
/* Progress bars under cards */
.itemProgressBar {
height: 4px;
background: rgba(255, 255, 255, 0.10);
border-radius: 0 0 var(--an-radius) var(--an-radius);
}
.itemProgressBarForeground {
background: linear-gradient(90deg, var(--an-accent), var(--an-accent-2)) !important;
border-radius: 0 0 var(--an-radius) var(--an-radius);
}
/* ---------------- Buttons ---------------- */
.button-submit,
.btnPlay,
.fab.primary {
background: linear-gradient(135deg, #22d3ee 0%, #818cf8 100%) !important;
color: #ffffff !important;
font-weight: 600;
border-radius: 10px !important;
border: none !important;
box-shadow: 0 6px 18px rgba(34, 211, 238, 0.25);
transition: filter 0.2s ease, box-shadow 0.2s ease;
}
.button-submit:hover,
.button-submit:focus,
.btnPlay:hover,
.fab.primary:hover {
filter: brightness(1.1);
box-shadow: 0 8px 26px rgba(34, 211, 238, 0.45);
}
.emby-button:not(.raised):focus-visible,
.emby-button:not(.raised):hover {
color: var(--an-accent);
}
/* ---------------- Detail page ---------------- */
.itemDetailImage,
.detailImageContainer img {
border-radius: 12px;
border: 1px solid var(--an-border);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.65);
}
h1,
h2,
h3 {
color: var(--an-text) !important;
text-shadow: 0 2px 24px rgba(0, 0, 0, 0.85);
}
.nameContainer,
.itemName,
.itemMiscInfo {
text-shadow: 0 2px 24px rgba(0, 0, 0, 0.85);
}
.secondaryText,
.itemMiscInfo,
.mediaInfoText {
color: var(--an-text-dim) !important;
}
.mediaInfoText {
background: rgba(13, 18, 30, 0.72);
border: 1px solid var(--an-border);
border-radius: 8px;
padding: 0.25em 0.7em;
}
/* ---------------- Dialogs, sheets, menus ---------------- */
.dialog {
background: rgba(9, 13, 23, 0.97) !important;
border: 1px solid var(--an-border);
border-radius: 16px !important;
box-shadow: var(--an-shadow);
}
.actionSheet {
background: rgba(9, 13, 23, 0.97) !important;
border: 1px solid var(--an-border);
border-radius: 16px !important;
overflow: hidden;
box-shadow: var(--an-shadow);
}
.formDialogHeader {
border-bottom: 1px solid var(--an-border);
}
.formDialogFooter {
border-top: 1px solid var(--an-border);
}
.actionSheetMenuItem,
.listItem {
border-radius: 10px;
color: var(--an-text) !important;
}
.actionSheetMenuItem:hover,
.actionSheetMenuItem.showFocus,
.listItem:hover {
background: rgba(34, 211, 238, 0.10) !important;
}
.listItem:hover .listItemBody,
.listItem .secondary {
color: var(--an-text-dim);
}
.paperList {
background: rgba(9, 13, 23, 0.72);
border: 1px solid var(--an-border);
border-radius: 12px;
}
/* ---------------- Inputs ---------------- */
.emby-input,
.emby-select,
.emby-textarea {
background: rgba(10, 15, 26, 0.85) !important;
border: 1px solid var(--an-border) !important;
border-radius: 10px !important;
color: var(--an-text) !important;
}
.emby-input:focus,
.emby-select:focus,
.emby-textarea:focus {
border-color: var(--an-accent) !important;
box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.18);
}
.emby-select option {
background: #0b101c;
color: var(--an-text);
}
.checkboxOutline {
border-radius: 6px;
border-color: var(--an-border);
}
.emby-checkbox:checked + .checkboxOutline {
background: linear-gradient(135deg, var(--an-accent), var(--an-accent-2)) !important;
border-color: transparent !important;
}
/* Player sliders */
.mdl-slider-background-lower {
background: linear-gradient(90deg, var(--an-accent), var(--an-accent-2)) !important;
border-radius: 999px;
}
.mdl-slider-background-upper {
background: rgba(255, 255, 255, 0.15) !important;
border-radius: 999px;
}
/* ---------------- Player OSD ---------------- */
.videoOsdBottom {
background: linear-gradient(0deg, rgba(3, 6, 12, 0.94), rgba(3, 6, 12, 0.0));
}
.osdHeader {
background: linear-gradient(180deg, rgba(3, 6, 12, 0.85), rgba(3, 6, 12, 0.0));
padding-top: 1em;
}
/* ---------------- Login page ---------------- */
#loginPage .visualLoginForm {
background: rgba(7, 11, 20, 0.78);
backdrop-filter: blur(22px) saturate(1.25);
-webkit-backdrop-filter: blur(22px) saturate(1.25);
border: 1px solid var(--an-border);
border-radius: 20px;
box-shadow: var(--an-shadow);
max-width: 480px;
margin: 0 auto;
padding: 2.6em 2.8em !important;
}
#loginPage .visualLoginForm h1 {
text-align: center;
letter-spacing: 0.5px;
}
#loginPage .disclaimerContainer {
text-align: center;
color: var(--an-text-dim);
}
/* ---------------- Toasts & misc ---------------- */
.toast {
background: rgba(9, 13, 23, 0.95) !important;
border: 1px solid var(--an-border);
border-radius: 12px;
box-shadow: var(--an-shadow);
color: var(--an-text) !important;
}
.itemSelectionPanel {
background: rgba(34, 211, 238, 0.85) !important;
}
.sectionTitle,
.sectionTitleText {
color: var(--an-text) !important;
letter-spacing: 0.2px;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: #070b14;
}
::-webkit-scrollbar-thumb {
background: rgba(34, 211, 238, 0.35);
border-radius: 8px;
border: 2px solid #070b14;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(34, 211, 238, 0.6);
}
/* ---------------- Motion safety ---------------- */
@media (prefers-reduced-motion: reduce) {
.cardBox,
.button-submit,
.btnPlay,
.fab.primary {
transition: none !important;
}
.card:hover .cardBox,
.card.showFocus .cardBox {
transform: none !important;
}
}
/* ---------------- Admin-SPA (MUI) Overrides ---------------- */
.MuiPaper-root,
.MuiCard-root,
.MuiAccordion-root,
.MuiDrawer-paper {
background-color: var(--an-surface-solid) !important;
background-image: linear-gradient(160deg, rgba(13, 18, 30, 0.92), rgba(8, 12, 22, 0.97)) !important;
border: 1px solid var(--an-border) !important;
border-radius: 14px !important;
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.5) !important;
color: var(--an-text) !important;
}
.MuiCard-root:hover {
border-color: var(--an-border-hover);
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.6), var(--an-glow) !important;
}
.MuiAppBar-root,
.MuiToolbar-root {
background: linear-gradient(180deg, rgba(5, 8, 16, 0.95), rgba(5, 8, 16, 0.72)) !important;
backdrop-filter: blur(18px) saturate(1.25);
-webkit-backdrop-filter: blur(18px) saturate(1.25);
border-bottom: 1px solid var(--an-border) !important;
color: var(--an-text) !important;
}
.MuiTypography-root,
.MuiListItemText-primary,
.MuiListItemText-secondary,
.MuiTableCell-root {
color: var(--an-text) !important;
}
.MuiListItemText-secondary,
.MuiTypography-colorTextSecondary {
color: var(--an-text-dim) !important;
}
.MuiButton-containedPrimary,
.MuiButton-contained {
background: linear-gradient(135deg, #22d3ee 0%, #818cf8 100%) !important;
color: #ffffff !important;
border-radius: 10px !important;
font-weight: 600;
box-shadow: 0 6px 18px rgba(34, 211, 238, 0.25);
}
.MuiButton-contained:hover {
filter: brightness(1.1);
box-shadow: 0 8px 26px rgba(34, 211, 238, 0.45);
}
.MuiButton-outlined,
.MuiButton-text {
color: var(--an-accent) !important;
border-color: var(--an-border-hover) !important;
border-radius: 10px !important;
}
.MuiListItem-root:hover,
.MuiListItem-button:hover {
background: rgba(34, 211, 238, 0.10) !important;
}
.MuiListItemButton-root:hover {
background: rgba(34, 211, 238, 0.10) !important;
}
.Mui-selected,
.Mui-selected:hover {
background: rgba(34, 211, 238, 0.16) !important;
}
.MuiInputBase-root,
.MuiOutlinedInput-root,
.MuiFilledInput-root {
background: rgba(10, 15, 26, 0.85) !important;
border-radius: 10px !important;
}
.MuiOutlinedInput-notchedOutline {
border-color: var(--an-border) !important;
}
.MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline {
border-color: var(--an-accent) !important;
}
.MuiSwitch-switchBase.Mui-checked {
color: var(--an-accent) !important;
}
.MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track {
background: linear-gradient(90deg, var(--an-accent), var(--an-accent-2)) !important;
}
.MuiChip-root {
background: rgba(13, 18, 30, 0.85) !important;
border: 1px solid var(--an-border) !important;
color: var(--an-text) !important;
border-radius: 999px !important;
}
.MuiChip-root.MuiChip-colorPrimary {
background: linear-gradient(135deg, rgba(34, 211, 238, 0.2), rgba(129, 140, 248, 0.2)) !important;
color: var(--an-accent) !important;
}
.MuiTableCell-root {
border-bottom: 1px solid var(--an-border) !important;
}
.MuiTableHead-root .MuiTableCell-root {
color: var(--an-accent) !important;
font-weight: 600;
}
.MuiDivider-root {
border-color: var(--an-border) !important;
}
.MuiDialog-paper,
.MuiMenu-paper,
.MuiPopover-paper {
background: rgba(9, 13, 23, 0.97) !important;
border: 1px solid var(--an-border) !important;
border-radius: 16px !important;
box-shadow: var(--an-shadow) !important;
}
.MuiLinearProgress-bar {
background: linear-gradient(90deg, var(--an-accent), var(--an-accent-2)) !important;
}
.MuiCircularProgress-root {
color: var(--an-accent) !important;
}
.MuiAlert-root {
border-radius: 12px !important;
border: 1px solid var(--an-border) !important;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB