/* views.css — Styles für die gemeinsamen Medien-Ansichten (views.js).
   Genutzt von deliveries.html (Portal) und share.html (Kundensicht). */

/* ===== Player: Glasleiste (Variante B, gewaehlt 2026-07-31) =====
   Die Steuerung sitzt in einer schwebenden Pille mit Milchglas, abgesetzt vom
   Rand, statt unter einem Verlauf ueber dem Bild. Sie bringt ihren eigenen Grund
   mit und traegt deshalb auf hellen wie dunklen Frames gleich gut. Genutzt von
   deliveries.html (Portal) und share.html (Kundensicht), damit sich beide gleich
   anfuehlen. Die Farben sind hier absichtlich fest und laufen NICHT ueber Tokens:
   der Player liegt in beiden Themes auf dem Video. */
.vl-pill {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 12px; border-radius: 999px;
  background: rgba(18,14,16,.55);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  border: 1px solid rgba(255,255,255,.14);
  box-shadow: 0 8px 32px rgba(0,0,0,.45);
}
.vl-pill button { background: none; border: 0; padding: 0; cursor: pointer; color: #fff;
  display: flex; align-items: center; justify-content: center; flex: none; }
.vl-pill .material-symbols-outlined { font-size: 22px; color: #fff !important; transition: color .15s; }
.vl-pill button:hover .material-symbols-outlined { color: #F20D46 !important; }
/* Zeitanzeige laeuft in der Fliesstext-Schrift, nicht in der Display-Schrift:
   Unbounded ist als Headline-Schrift gebaut, ihre Ziffern tragen zu viel
   Charakter fuer eine Zahl, die sich sekuendlich aendert. Gilt fuer alle
   Wiedergabe-Zahlen (Zeitanzeige, Hover-Zeit, Timecode-Chips). */
.vl-pill .vl-p-time { font-family: 'Funnel Display', sans-serif; font-weight: 600; font-size: 11.5px;
  font-variant-numeric: tabular-nums; letter-spacing: .01em; color: rgba(255,255,255,.9) !important;
  white-space: nowrap; flex: none; }
.vl-pill .vl-p-q { font-family: 'Unbounded'; font-weight: 900; font-size: 9px; letter-spacing: .1em;
  text-transform: uppercase; color: rgba(255,255,255,.75) !important; background: none;
  padding: 5px 9px; border-radius: 999px; border: 1px solid rgba(255,255,255,.18); flex: none; }
.vl-pill .vl-p-q:hover { color: #fff !important; border-color: rgba(255,255,255,.35); }
/* Zeitleiste in der Pille: duenn, waechst unter der Maus */
.vl-pill .vl-p-bar { position: relative; flex: 1 1 auto; min-width: 60px; height: 14px;
  cursor: pointer; touch-action: none; }
.vl-pill .vl-p-bar .tl-track,
.vl-pill .vl-p-bar .tl-buf,
.vl-pill .vl-p-bar .tl-prog { position: absolute; top: 6px; height: 3px; border-radius: 3px;
  transition: height .15s, top .15s; }
.vl-pill .vl-p-bar .tl-track { left: 0; right: 0; background: rgba(255,255,255,.22); }
.vl-pill .vl-p-bar .tl-buf { left: 0; width: 0%; background: rgba(255,255,255,.34); }
.vl-pill .vl-p-bar .tl-prog { left: 0; width: 0%; background: #F20D46; }
.vl-pill .vl-p-bar:hover .tl-track,
.vl-pill .vl-p-bar:hover .tl-buf,
.vl-pill .vl-p-bar:hover .tl-prog { height: 5px; top: 5px; }
.vl-pill .tl-prog::after { content: ''; position: absolute; right: -5px; top: 50%;
  width: 10px; height: 10px; border-radius: 50%; background: #fff;
  transform: translateY(-50%); box-shadow: 0 1px 4px rgba(0,0,0,.5); }
@media (max-width: 560px) {
  .vl-pill { gap: 8px; padding: 8px 10px; }
  .vl-pill .vl-p-time { font-size: 10px; }
}

/* ===== Player: Steuerung blendet aus, wenn die Maus weg ist =====
   Sichtbar bleibt sie bei Pause (sonst verliert man den Player aus dem Blick)
   und sobald etwas darin den Tastaturfokus hat (sonst waere sie nicht bedienbar
   ohne Maus). Animiert werden nur opacity und transform. */
.vl-ctl-auto {
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity .22s cubic-bezier(.16,1,.30,1), transform .22s cubic-bezier(.16,1,.30,1);
}
#video-container:hover .vl-ctl-auto,
#video-container:focus-within .vl-ctl-auto,
#video-container.vl-paused .vl-ctl-auto,
.vl-stage:hover .vl-ctl-auto,
.vl-stage:focus-within .vl-ctl-auto,
.vl-stage.vl-paused .vl-ctl-auto {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
/* Ohne Maus (Touch) gibt es kein Hover, dort bleibt die Steuerung stehen. */
@media (hover: none) {
  .vl-ctl-auto { opacity: 1; transform: none; pointer-events: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .vl-ctl-auto { transition: none; }
}

/* ===== Ansichten (views.js): Toolbar, Raster, Kompakt, Liste ===== */
.vl-toolbar { display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
.vl-seg { display:flex; gap:2px; padding:3px; border-radius:9999px; background:var(--surf-a040, rgba(255,255,255,0.04)); border:1px solid var(--line-a070, rgba(255,255,255,0.07)); }
.vl-seg-btn { width:30px; height:28px; border-radius:9999px; display:flex; align-items:center; justify-content:center;
  color:var(--fg-a400, rgba(255,255,255,0.4)); background:transparent; border:0; cursor:pointer; transition:background .15s, color .15s; }
.vl-seg-btn:hover { color:var(--fg-1, #fff); }
/* Weiss, nicht --fg-1: das Token kippt im Light-Theme auf Tinte, und dann sitzt
   ein schwarzes Symbol auf Marken-Rot. Genau derselbe Fehler wie beim Haekchen
   weiter unten, dort steht die Begruendung schon seit einer Weile.
   Die Fuellung laeuft ueber --accent-ink (im Dunkeln nicht gesetzt, dort also
   das Marken-Rot), weil Weiss auf #F20D46 nur 4,27:1 traegt.
   Das !important muss sein: theme.js faerbt im Hellen JEDES
   .material-symbols-outlined auf die Sekundaerfarbe, ebenfalls mit !important. */
.vl-seg-btn.on { background:var(--btn-primary-bg, #fff); color:var(--btn-primary-fg, #0A0708); }
.vl-seg-btn.on .material-symbols-outlined { color:var(--btn-primary-fg, #0A0708) !important; }
.vl-all-btn { display:inline-flex; align-items:center; gap:6px; height:28px; padding:0 12px; border-radius:9999px; cursor:pointer;
  font:inherit; font-size:12px; color:var(--fg-a500, rgba(255,255,255,0.5)); background:var(--surf-a040, rgba(255,255,255,0.04));
  border:1px solid var(--line-a070, rgba(255,255,255,0.07)); transition:transform .15s cubic-bezier(.22,1,.36,1); }
.vl-all-btn:hover { color:var(--fg-1, #fff); background:var(--surf-a080, rgba(255,255,255,0.08)); }
.vl-all-btn:focus-visible { outline:2px solid var(--fg-1, #fff); outline-offset:2px; }
.vl-all-btn:active { transform:scale(0.96); }
.vl-size { display:flex; align-items:center; gap:8px; }
/* Kachelgroesse: kein Marken-Rot mehr, Rot steht nur fuer Warnungen (Moritz,
   2026-10-08). Selbst gezeichnet statt accent-color, weil die Browser den Regler
   im hellen Standard-Schema malen: ein weisser accent-color hebt sich im Dunkeln
   dann kaum von der Spur ab. Knopf = Primaer-Farbe (dunkel weiss, hell Tinte).
   Das !important beim Grund muss sein: theme.js gibt im Hellen jedem input
   --input-bg mit !important, und ohne native Optik malt der Regler ihn als
   weissen Kasten. */
.vl-size input[type=range] { -webkit-appearance:none; appearance:none; width:96px; height:24px; margin:0; background:transparent !important; cursor:pointer; }
.vl-size input[type=range]::-webkit-slider-runnable-track { height:4px; border-radius:9999px; background:var(--line-a350, rgba(255,255,255,0.35)); }
.vl-size input[type=range]::-moz-range-track { height:4px; border-radius:9999px; background:var(--line-a350, rgba(255,255,255,0.35)); }
.vl-size input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; width:14px; height:14px; margin-top:-5px; border:0; border-radius:50%;
  background:var(--btn-primary-bg, #fff); box-shadow:0 1px 4px rgba(0,0,0,0.3); transition:transform .15s cubic-bezier(.22,1,.36,1); }
.vl-size input[type=range]::-moz-range-thumb { width:14px; height:14px; border:0; border-radius:50%;
  background:var(--btn-primary-bg, #fff); box-shadow:0 1px 4px rgba(0,0,0,0.3); transition:transform .15s cubic-bezier(.22,1,.36,1); }
.vl-size input[type=range]:hover::-webkit-slider-thumb { transform:scale(1.15); }
.vl-size input[type=range]:hover::-moz-range-thumb { transform:scale(1.15); }
.vl-size input[type=range]:active::-webkit-slider-thumb { transform:scale(0.92); }
.vl-size input[type=range]:active::-moz-range-thumb { transform:scale(0.92); }
/* Sortierung gehoert zur Steuerung und steht bei den anderen Bedienelementen.
   Vorher stand hier margin-left:auto, das hat sie auf breiten Schirmen ans
   andere Zeilenende geschoben und wie ein verirrtes Element wirken lassen. */
.vl-sort { display:flex; align-items:center; gap:6px; }
.vl-sort select { background:var(--bg-ctl, #1a1618); border:1px solid var(--line-a080, rgba(255,255,255,0.08)); border-radius:9999px; color:var(--fg-1, #fff);
  font-family:'Unbounded'; font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.06em;
  padding:7px 12px; outline:none; cursor:pointer; }
.vl-sort button { width:30px; height:30px; border-radius:50%; background:var(--bg-ctl, #1a1618); border:1px solid var(--line-a080, rgba(255,255,255,0.08));
  color:var(--fg-a600, rgba(255,255,255,0.6)); cursor:pointer; display:flex; align-items:center; justify-content:center; }
.vl-sort button:hover { color:var(--fg-1, #fff); }

/* Der Schalter fuer die Vorauswahl. Sitzt links in der Leiste und sieht anders
   aus als die Filter-Chips daneben: er filtert nicht, er schaltet die ganze
   Funktion. Im Aus-Zustand bewusst leise, damit eine ruhige Ablage auch ruhig
   aussieht; im An-Zustand traegt er die Marken-Farbe. */
.vl-rvswitch { gap:5px; opacity:.6; margin-right:14px; }
.vl-rvswitch:hover { opacity:1; }
/* An: umrandet und mit rotem Auge, NICHT vollflaechig rot. Vollflaechig rot ist
   die Sprache der aktiven Filter-Chips daneben, und der Schalter ist kein
   Filter. Wer ihn faelschlich fuer einen haelt, sucht danach, was er filtert. */
.vl-rvswitch.is-an { opacity:1; border-color:rgba(242,13,70,.5); background:rgba(242,13,70,.10); }
.vl-rvswitch.is-an .material-symbols-outlined { color:#F20D46 !important; }
/* Trennstrich zu den Chips: er gehoert nicht zu ihnen, er schaltet sie. */
.vl-rvbar .vl-rvswitch { position:relative; }
.vl-rvbar .vl-rvswitch.is-an::after { content:''; position:absolute; right:-8px; top:20%; bottom:20%;
  width:1px; background:var(--line-a100, rgba(255,255,255,0.10)); }

.vl-grid { display:grid; gap:16px; align-items:start; }
/* Ein Shooting-Link traegt sechs- bis siebentausend Kacheln. Die stehen alle im
   Dokument (das haelt Blaettern, Filter und Nachziehen einfach), aber der
   Browser muss sie nicht alle rechnen: content-visibility ueberspringt Layout,
   Stil und Zeichnen fuer alles, was gerade nicht in der Naehe des Sichtfensters
   liegt.
   contain-intrinsic-size gibt die Platzhaltergroesse, damit die Bildlaufleiste
   nicht springt; mit dem Schluesselwort auto merkt sich der Browser die einmal
   gemessene echte Groesse und benutzt sie danach.
   Browser ohne Unterstuetzung (Safari vor 18) ignorieren beide Zeilen und
   verhalten sich wie bisher. */
.vl-grid > * { content-visibility:auto; contain-intrinsic-size:auto var(--vl-kachel-h, 300px); }
/* Aber: ein neu eingefuegtes Element mit content-visibility:auto steht im ersten
   Frame IMMER in Platzhaltergroesse da, auch wenn es mitten im Sichtfenster
   liegt; seine echte Hoehe bekommt es erst einen Frame spaeter. Bei jedem
   Ordnerwechsel sprangen dadurch alle Kacheln von 302 auf ihre echte Hoehe
   (216 px bei "Mittel") und alles darunter rutschte hoch. Die ersten 48 Kacheln
   (mehr passt auf keinen Bildschirm) rechnen deshalb immer, und fuer alle
   weiteren misst views.js die echte Kachelhoehe und gibt sie als Platzhalter
   vor (--vl-kachel-h), damit auch tiefe Scrollstaende stimmen. */
.vl-grid > :nth-child(-n+48) { content-visibility:visible; }
/* Die Marke, an der die Nachlieferung haengt. Sie braucht Hoehe, sonst meldet
   der Beobachter sie nie als sichtbar. */
.vl-nachschub { height:1px; }
.vl-folder-thumb { width:100%; height:100%; display:flex; align-items:center; justify-content:center;
  background:linear-gradient(135deg,var(--bg-s1b,#1a1a1a),var(--bg-dim,#111)); }
/* Sobald ein Ordner ein Vorschaubild aus seinem Inhalt zeigt, ist er von einem Video
   oder Bild nicht mehr zu unterscheiden. Diese kleine Marke unten links sagt weiter
   "das ist ein Ordner", ohne das Bild zuzudecken. */
.vl-folder-mark { position:absolute; left:8px; bottom:8px; z-index:10; display:flex;
  align-items:center; justify-content:center; width:24px; height:24px; border-radius:7px;
  background:rgba(0,0,0,0.55); backdrop-filter:blur(6px); pointer-events:none; }
.vl-folder-mark .material-symbols-outlined { font-size:15px; color:rgba(255,255,255,0.85); }
/* Im Mosaik steht der Ordnername dauerhaft unten, dort waere die Marke im Weg.
   Ordner haben keine Auswahl-Box, also ist oben links frei. */
.vl-folder-mark.sm { left:5px; top:5px; bottom:auto; width:19px; height:19px; border-radius:6px; }
.vl-folder-mark.sm .material-symbols-outlined { font-size:12px; }

/* Shine: ein Lichtstreifen wandert beim Darueberfahren einmal schraeg ueber die
   Ordner-Kachel. Nur auf Ordnern, damit die Geste etwas bedeutet und nicht jede
   Kachel glitzert. Animiert werden ausschliesslich transform und opacity.
   Der Streifen liegt ueber dem Vorschaubild (z-index 6), aber unter Play-Knopf,
   Haekchen und Ordner-Marke, die alle hoeher sitzen.
   Im Light-Theme traegt Weiss auf Weiss nicht, dort glaenzt es warm rot. */
.folder-cover::before {
  content:''; position:absolute; top:-30%; bottom:-30%; left:-40%; width:45%;
  z-index:6; pointer-events:none; opacity:0;
  background:linear-gradient(100deg, transparent, rgba(255,255,255,0.42), transparent);
  transform:translateX(0) rotate(8deg);
  transition:transform .85s cubic-bezier(.22,1,.36,1), opacity .3s ease;
}
[data-theme="light"] .folder-cover::before {
  background:linear-gradient(100deg, transparent, rgba(242,13,70,0.20), transparent);
}
.film-card:hover .folder-cover::before,
.vl-tile:hover.folder-cover::before {
  opacity:1; transform:translateX(320%) rotate(8deg);
}
@media (prefers-reduced-motion: reduce) {
  .folder-cover::before { transition:none; }
  .film-card:hover .folder-cover::before,
  .vl-tile:hover.folder-cover::before { opacity:0; transform:none; }
}

/* Dauer-Badge auf der Kachel ist ebenfalls eine Wiedergabe-Zahl → Fliesstext-Schrift. */
.vl-badge { position:absolute; top:8px; right:8px; z-index:10; padding:2px 8px; border-radius:9999px;
  font-family:'Funnel Display', sans-serif; font-size:10px; font-weight:600; font-variant-numeric:tabular-nums;
  background:rgba(0,0,0,0.7); color:#ffd000; border:1px solid rgba(255,208,0,0.3); }

.vl-group { font-family:'Unbounded'; font-size:11px; font-weight:700; text-transform:uppercase;
  letter-spacing:.12em; color:var(--fg-a450, rgba(255,255,255,0.45)); margin:22px 0 10px; }
.vl-group:first-child { margin-top:0; }
.vl-compact { display:grid; grid-template-columns:repeat(auto-fill,minmax(var(--tile,150px),1fr)); gap:3px; }
.vl-compact .vl-tile { position:relative; aspect-ratio:1; overflow:hidden; border-radius:4px; background:var(--bg-dim, #111);
  cursor:pointer; transition:transform .18s cubic-bezier(.34,1.56,.64,1); }
.vl-compact .vl-tile:hover { transform:scale(1.03); z-index:2; }
/* Ordner im Mosaik: braucht eigene Regel, weil `.vl-compact .vl-tile` mit zwei Klassen
   die einfache .folder-cover-Regel weiter unten ueberschreiben wuerde. Kachel ist
   quadratisch, darum der 4:3-Zuschnitt statt 16:9, der beschneidet weniger. */
.vl-compact .vl-tile.folder-cover {
  background: var(--bg-dim, #111) url('Assets/folder-cover-dark-4x3.v3.webp') center / cover no-repeat;
}
[data-theme="light"] .vl-compact .vl-tile.folder-cover {
  /* Der Papierton des Bildes selbst, nicht --fg-1. Das ist im Light-Theme die
     Vordergrundfarbe (#0A0708), da blitzte beim Laden Schwarz auf. */
  background-color: #DCCEBD;
  background-image: url('Assets/folder-cover-light-4x3.v5.webp');
}
/* Im Mosaik zeigen alle Bilder volle Helligkeit, auch Entwuerfe. Der Entwurfsstatus
   haengt stattdessen als kleiner Punkt oben rechts an der Kachel. */
.vl-compact .vl-tile.draft img { opacity:1; }
.vl-compact .vl-tile.draft::after {
  content:''; position:absolute; top:6px; right:6px; width:8px; height:8px; border-radius:50%;
  background:#ffd000; box-shadow:0 0 0 2px rgba(0,0,0,.55); pointer-events:none; z-index:3;
}
.vl-compact .vl-tile img { width:100%; height:100%; object-fit:cover; display:block; }
.vl-compact .vl-play { position:absolute; top:6px; left:6px; font-size:16px; color:var(--fg-1, #fff);
  text-shadow:0 2px 8px rgba(0,0,0,.7); font-variation-settings:'FILL' 1; }
.vl-compact .vl-name { position:absolute; left:0; right:0; bottom:0; padding:14px 8px 6px; font-size:10px;
  color:var(--fg-1, #fff); background:linear-gradient(to top,rgba(0,0,0,.85),transparent); opacity:0; transition:opacity .15s;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.vl-compact .vl-tile:hover .vl-name, .vl-compact .vl-name.always { opacity:1; }

/* Auswahl: gleiches Häkchen in allen drei Modi */
.vl-check { position:absolute; top:8px; left:8px; z-index:12; width:24px; height:24px; border-radius:7px;
  background:rgba(0,0,0,0.55); border:1px solid var(--line-a350, rgba(255,255,255,0.35)); display:flex; align-items:center;
  justify-content:center; cursor:pointer; opacity:0; transition:opacity .15s;
  padding:0; margin:0; -webkit-appearance:none; appearance:none; }
.vl-check .material-symbols-outlined { color:transparent; }
.film-card:hover .vl-check, .vl-tile:hover .vl-check, .vl-row:hover .vl-check { opacity:1; }
/* Ohne Maus gibt es kein Drueberfahren. Auf dem Handy war das Haekchen deshalb
   unsichtbar UND unerreichbar, und mit ihm die ganze Mehrfachauswahl samt
   Sammel-Download. Dort steht es dauerhaft da, etwas zurueckgenommen, damit es
   das Foto nicht erschlaegt. */
@media (hover:none){ .vl-check { opacity:.75; } }
/* Auswahlmodus (Freigabe-Link am Handy): Haekchen immer sichtbar, Kachel als Ziel. */
.vl-waehlen .vl-check { opacity:1; }
.vl-waehlen [data-id] { cursor:pointer; }
#vl-actionbar button[disabled] { opacity:.55; cursor:default; }
#vl-actionbar button[disabled]:hover, #vl-actionbar button[disabled]:active { transform:none; }
/* Per Tastatur erreichbar: sichtbar werden und sich zeigen, sobald der Fokus draufliegt */
.vl-check:focus-visible { opacity:1; outline:2px solid #F20D46; outline-offset:2px; }
.vl-check:active { transform:scale(.92); }
.vl-check.on { opacity:1; background:#F20D46; border-color:#F20D46; }
/* Der Chip ist in beiden Themes derselbe rote Fleck, also bleibt das Häkchen weiss.
   Mit --fg-1 wurde es im Light-Theme dunkel auf Rot und war kaum zu erkennen.
   Das !important kam nach: ohne es gewann theme.js, das im Hellen JEDEM
   .material-symbols-outlined die Sekundaerfarbe aufzwingt, ebenfalls mit
   !important. Die Regel hier stand also da und wirkte nicht, das Haekchen war
   weiter grau auf Rot (gemessen rgb(74,67,70)). */
.vl-check.on .material-symbols-outlined { color:#fff !important; }
.film-card.sel, .vl-tile.sel { outline:2px solid #F20D46; outline-offset:-2px; }
.vl-row.sel { background:rgba(242,13,70,0.09); }
/* In der Liste sitzt das Häkchen in der Zeile, nicht absolut */
.vl-c-name .vl-check { position:static; opacity:1; width:20px; height:20px; border-radius:6px;
  background:transparent; border-color:var(--fg-a220, var(--line-a220, rgba(255,255,255,0.22))); flex-shrink:0; }
.vl-c-name .vl-check.on { background:#F20D46; border-color:#F20D46; }

#vl-actionbar { position:fixed; left:50%; bottom:24px; transform:translateX(-50%); z-index:200;
  display:flex; align-items:center; gap:12px; background:var(--bg-s1, #161616); border:1px solid var(--line-a120, rgba(255,255,255,0.12));
  border-radius:9999px; padding:10px 14px 10px 20px; box-shadow:0 14px 44px rgba(0,0,0,0.55); }
.vl-ab-count { font-family:'Unbounded'; font-size:12px; font-weight:700; color:var(--fg-1, #fff); white-space:nowrap; }
#vl-actionbar button { font-family:'Unbounded'; font-size:11px; font-weight:700; text-transform:uppercase;
  letter-spacing:.05em; border:0; border-radius:9999px; padding:9px 16px; cursor:pointer;
  transition:opacity .15s, transform .1s; white-space:nowrap; }
#vl-actionbar button:active { transform:scale(.96); }
#vl-actionbar button:focus-visible { outline:2px solid var(--fg-1, #fff); outline-offset:2px; }
.vl-ab-ghost { background:transparent; color:var(--fg-a500, rgba(255,255,255,0.5)); }
.vl-ab-ghost:hover { color:var(--fg-1, #fff); }
.vl-ab-main { background:var(--btn-primary-bg, #fff); color:var(--btn-primary-fg, #0A0708); }
/* Nur ein Primaer-Knopf pro Leiste (CI): Share-Link ist die zweite Stufe, dunkle Pille. */
.vl-ab-second { background:var(--bg-s3, #2a2528); color:var(--fg-1, #fff); box-shadow:inset 0 0 0 1px var(--line-a120, rgba(255,255,255,0.12)); }
.vl-ab-second:hover { opacity:1; box-shadow:inset 0 0 0 1px var(--line-a350, rgba(255,255,255,0.35)); }
.vl-ab-danger { background:var(--bg-s3, #2a2528); color:#ff453a; }
/* Freigeben ist die Hauptaktion und traegt darum die Primaer-Pille (weiss im Dunkeln).
   Gruen gibt es im CI nur als Status-Badge, nicht als Knopf. */
.vl-ab-go { display:inline-flex; align-items:center; gap:6px; color:var(--btn-primary-fg, #0A0708);
  background:var(--btn-primary-bg, #fff); box-shadow:var(--btn-primary-shadow, 0 4px 20px rgba(0,0,0,0.35)); }
.vl-ab-go .material-symbols-outlined { color:var(--btn-primary-fg, #0A0708) !important; }
/* Steht Freigeben in der Leiste, ist es der einzige Primaer-Knopf; Herunterladen rueckt auf die zweite Stufe. */
.vl-ab-go ~ .vl-ab-main { background:var(--bg-s3, #2a2528); color:var(--fg-1, #fff); box-shadow:inset 0 0 0 1px var(--line-a120, rgba(255,255,255,0.12)); }
.vl-ab-go .material-symbols-outlined { font-size:15px; }
/* In Fotos sichern (Freigabe-Link): Symbol in Textgroesse neben dem Text, wie bei Freigeben,
   sonst blaeht das 24px-Symbol den Knopf gegenueber seinen Nachbarn auf. */
#vl-actionbar [data-act="save"] { display:inline-flex; align-items:center; gap:6px; }
/* Negativer Rand: das Symbol bestimmt nicht die Zeilenhoehe, alle Knoepfe bleiben gleich hoch. */
#vl-actionbar [data-act="save"] .material-symbols-outlined { font-size:15px; margin:-3px 0; }
#vl-actionbar [data-act="save"] .material-symbols-outlined { color:var(--btn-primary-fg, #0A0708) !important; }
/* Handy: die Leiste bleibt im Bild und bricht um, statt an beiden Raendern abgeschnitten
   zu werden (sie ist per left:50% + translateX(-50%) mittig, nowrap-Knoepfe waren breiter
   als der Bildschirm). Ab 641px aendert sich nichts. */
@media (max-width: 640px) {
  #vl-actionbar { box-sizing:border-box; width:max-content; max-width:calc(100% - 24px); flex-wrap:wrap; justify-content:center;
    gap:8px; padding:10px 12px; border-radius:26px; }
  #vl-actionbar button { padding:9px 12px; letter-spacing:.03em; }
}
.vl-ab-main:hover, .vl-ab-go:hover, .vl-ab-danger:hover { opacity:.88; }

.vl-list { border:1px solid var(--line-a060, rgba(255,255,255,0.06)); border-radius:14px; overflow:hidden; }
.vl-row { display:grid; grid-template-columns:minmax(0,1fr) 90px 90px 120px 150px 32px; align-items:center;
  gap:12px; padding:9px 14px; cursor:pointer; border-bottom:1px solid var(--line-a040, rgba(255,255,255,0.04)); }
.vl-row:last-child { border-bottom:0; }
.vl-row:hover { background:var(--surf-a035, rgba(255,255,255,0.035)); }
.vl-row.vl-head { cursor:default; background:var(--surf-a030, rgba(255,255,255,0.03)); font-family:'Unbounded'; font-size:9px;
  font-weight:700; text-transform:uppercase; letter-spacing:.1em; color:var(--fg-a400, rgba(255,255,255,0.4)); }
.vl-row.vl-head .sortable { cursor:pointer; display:flex; align-items:center; gap:4px; }
.vl-row.vl-head .sortable:hover, .vl-row.vl-head .active { color:var(--fg-1, #fff); }
.vl-c-name { display:flex; align-items:center; gap:10px; min-width:0; }
.vl-row-thumb { width:40px; height:28px; object-fit:cover; border-radius:5px; flex-shrink:0; background:var(--bg-s1b, #1a1a1a); }
.vl-row-ico { font-size:22px; color:var(--fg-a350, rgba(255,255,255,0.35)); width:40px; text-align:center; flex-shrink:0; }
.vl-row-title { font-size:13px; color:var(--fg-1, #fff); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.vl-row-draft { font-family:'Unbounded'; font-size:8px; font-weight:700; text-transform:uppercase;
  letter-spacing:.1em; padding:2px 7px; border-radius:9999px; background:var(--surf-a100, rgba(255,255,255,0.1));
  color:var(--fg-a750, rgba(255,255,255,0.75)); flex-shrink:1; min-width:0;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* Der Titel bekommt Vorrang vor dem Schild ("V3 Entwurf"), sonst blieb er in
   schmalen Spalten bei 0 px stehen. Der volle Text steht im Tooltip. */
.vl-c-name .vl-row-title { flex-shrink:1; min-width:4em; }
.vl-c-type, .vl-c-size, .vl-c-dim, .vl-c-date { font-size:12px; color:var(--fg-a450, rgba(255,255,255,0.45));
  font-variant-numeric:tabular-nums; }
@media (max-width: 720px) {
  .vl-row { grid-template-columns:minmax(0,1fr) 80px 32px; }
  .vl-c-type, .vl-c-dim, .vl-c-date { display:none; }
  /* Ohne Maus gibt es kein Hover: der Knopf bleibt leicht sichtbar. */
  .vl-c-ctx .ctx-trigger { opacity:.55; }
}

/* ===== Kunden-Freigabe (review-core.js) ===== */
/* Grün und Gelb tragen auf dem Foto, auf hellen Theme-Flaechen (Chips, Liste,
   Aktionsleiste) sind sie zu blass. Deshalb je Zustand eine zweite, dunklere
   Fassung fuer Schrift und Rahmen, genau wie --accent-ink das fuer Rot macht. */
:root, [data-theme="dark"] {
  --rv-ok-ink: #30d158;
  --rv-warn-ink: #ffd000;
}
[data-theme="light"] {
  --rv-ok-ink: #1B7F3B;
  --rv-warn-ink: #8A5A00;
}
/* Immer-dunkle Flaechen (Lightbox, Wisch-Modus) holen die hellen Toene zurueck.
   .vl-on-dark in theme.js stellt nur die allgemeinen Dark-Tokens her, diese
   beiden kennt es nicht: ohne die Zeile stand "Bearbeiten" aktiv mit 2,2:1 da. */
[data-theme="light"] .vl-on-dark {
  --rv-ok-ink: #30d158;
  --rv-warn-ink: #ffd000;
}
/* Der Zustandspunkt sitzt oben rechts, das Auswahl-Haekchen oben links: beide
   sind damit gleichzeitig sichtbar und stossen sich nie. Die Farbe kommt ueber
   --rv aus review-core.js, damit alle drei Zustaende eine Regel teilen. */
.vl-rv { position:absolute; top:8px; right:8px; z-index:12; width:22px; height:22px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; background:var(--rv, #fff);
  box-shadow:0 2px 8px rgba(0,0,0,0.35); }
.vl-rv .material-symbols-outlined { font-size:14px; color:#0d0d0d; }
/* "raus" traegt keinen hellen Punkt: auf einem hellen Foto verschwaende ein
   weisses Kreuz auf hellem Grund. Dunkler Grund, helles Zeichen, klar lesbar. */
.vl-rv.vl-rv-out { background:rgba(18,16,17,0.78); border:1px solid rgba(255,255,255,0.25); }
.vl-rv.vl-rv-out .material-symbols-outlined { color:#fff; }
/* Steht schon eine Marke (Versionen, Kommentare) oben rechts, rueckt sie nach
   links weg. Reihenfolge im Markup: erst Punkt, dann Marke. */
.vl-rv + .vl-badge { right:36px; }
.vl-compact .vl-rv { top:5px; right:5px; width:17px; height:17px; }
.vl-compact .vl-rv .material-symbols-outlined { font-size:11px; }
/* Im Mosaik sitzt die Entwurfs-Marke ebenfalls oben rechts. Der Freigabe-Punkt
   liegt darueber, also rueckt er zur Seite statt sie zu verdecken. */
.vl-compact .vl-tile.draft .vl-rv { right:26px; }
/* "raus" bleibt sichtbar, tritt aber zurueck: der Blick soll an dem haengen,
   was noch Arbeit macht. */
.film-card.vl-rv-out .film-thumb img, .vl-compact .vl-tile.vl-rv-out img { opacity:0.32; }
/* Liste: eigene Spalte, deshalb ein Raster mehr. */
.vl-list.vl-with-rv .vl-row { grid-template-columns:minmax(0,1fr) 90px 90px 110px 170px 150px 32px; }
/* Drei-Punkte-Menue in der Listenzeile: im Fluss statt absolut auf der Kachel,
   sichtbar beim Hover der Zeile und solange das Menue offen ist. */
.vl-c-ctx { display:flex; justify-content:flex-end; align-items:center; }
.vl-c-ctx .ctx-menu { position:static; }
.vl-row:hover .ctx-trigger, .vl-row.ctx-open .ctx-trigger { opacity:1; }
.vl-c-rv { display:flex; align-items:center; gap:6px; font-size:12px; min-width:0;
  color:var(--fg-a450, rgba(255,255,255,0.45)); }
.vl-c-rv .dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
.vl-c-rv .rv-txt { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
@media (max-width: 720px) {
  .vl-list.vl-with-rv .vl-row { grid-template-columns:minmax(0,1fr) 80px 32px; }
  .vl-c-rv { display:none; }
}

/* Drei Schnellknoepfe auf der Kachel (nur Raster). Sie liegen unten im Bild und
   erscheinen beim Drueberfahren, damit sie die Vorschau nicht dauerhaft zustellen.
   Ohne Maus (Touch) stehen sie fest, sonst waeren sie unerreichbar. */
.vl-rvquick { position:absolute; left:0; right:0; bottom:0; z-index:11; display:flex; gap:6px;
  justify-content:center; padding:8px; background:linear-gradient(to top, rgba(8,6,7,.72), transparent);
  opacity:0; transition:opacity .15s; }
.film-card:hover .vl-rvquick, .film-card:focus-within .vl-rvquick { opacity:1; }
.vl-rvq { width:30px; height:30px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  background:rgba(18,16,17,.82); border:1px solid rgba(255,255,255,.18); color:#fff; cursor:pointer;
  transition:transform .15s, opacity .15s; }
.vl-rvq .material-symbols-outlined { font-size:16px; color:#fff; }
.vl-rvq:hover { transform:scale(1.08); }
.vl-rvq:active { transform:scale(.92); }
.vl-rvq:focus-visible { outline:2px solid #F20D46; outline-offset:2px; opacity:1; }
.vl-rvq.on[data-rvq="approved"] { background:#30d158; border-color:#30d158; }
.vl-rvq.on[data-rvq="approved"] .material-symbols-outlined { color:#0d0d0d; }
.vl-rvq.on[data-rvq="edit"] { background:#ffd000; border-color:#ffd000; }
.vl-rvq.on[data-rvq="edit"] .material-symbols-outlined { color:#0d0d0d; }
.vl-rvq.on[data-rvq="out"] { background:rgba(255,255,255,.9); border-color:#fff; }
.vl-rvq.on[data-rvq="out"] .material-symbols-outlined { color:#0d0d0d; }
@media (hover:none) { .vl-rvquick { opacity:1; } }
@media (prefers-reduced-motion: reduce) {
  .vl-rvquick { transition:none; }
  .vl-rvq { transition:none; }
  .vl-rvq:hover { transform:none; }
}

/* Zaehler- und Filterzeile ueber dem Raster */
.vl-rvbar { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.vl-rvchip { display:inline-flex; align-items:center; gap:6px; padding:8px 14px; min-height:38px; border-radius:9999px;
  background:var(--surf-a040, rgba(255,255,255,0.04)); border:1px solid var(--line-a070, rgba(255,255,255,0.07));
  color:var(--fg-a600, rgba(255,255,255,0.6)); font-family:'Funnel Display',sans-serif; font-size:12px;
  cursor:pointer; transition:transform .15s, opacity .15s; }
.vl-rvchip:hover { transform:translateY(-1px); color:var(--fg-1, #fff); }
.vl-rvchip:active { transform:scale(.97); }
.vl-rvchip:focus-visible { outline:2px solid #F20D46; outline-offset:2px; }
/* Aktiver Filter: im Light-Theme das dunklere Marken-Rot (--accent-ink), sonst
   steht weisse Schrift bei 12px unter dem Lesbarkeitsminimum. */
.vl-rvchip.on { background:var(--btn-primary-bg, #fff); border-color:transparent; color:var(--btn-primary-fg, #0A0708); }
.vl-rvchip .dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
.vl-rvchip .num { font-variant-numeric:tabular-nums; opacity:.75; }
.vl-rvchip.go { background:var(--btn-primary-bg, #fff); border-color:transparent; color:var(--btn-primary-fg, #0A0708); }
/* Solange noch etwas offen ist, ist der Abschluss kein Angebot: dann faellt auch
   die Farbe weg, sonst sieht der Knopf klickbar aus und ist es nicht. */
.vl-rvchip[disabled] { background:var(--surf-a040, rgba(255,255,255,0.04));
  border-color:var(--line-a070, rgba(255,255,255,0.07)); color:var(--fg-a350, rgba(255,255,255,0.35));
  cursor:default; }
.vl-rvchip[disabled]:hover { transform:none; color:var(--fg-a350, rgba(255,255,255,0.35)); }

/* Knoepfe in der Aktionsleiste (Mehrfachauswahl) */
.vl-ab-sep { width:1px; height:18px; background:var(--line-a120, rgba(255,255,255,0.12)); flex:none; }
#vl-actionbar .vl-ab-rv { border:1px solid var(--line-a140, rgba(255,255,255,0.14)); background:transparent;
  color:var(--fg-1, #fff); }
#vl-actionbar .vl-ab-rv:hover { opacity:.85; }
/* Schrift und Rahmen in der Ink-Fassung: die Leiste steht im Light-Theme auf
   Weiss, dort waeren die hellen Marken-Toene nicht mehr zu lesen. */
#vl-actionbar .vl-ab-rv.approved { border-color:var(--rv-ok-ink, #30d158); color:var(--rv-ok-ink, #30d158); }
#vl-actionbar .vl-ab-rv.edit { border-color:var(--rv-warn-ink, #ffd000); color:var(--rv-warn-ink, #ffd000); }
#vl-actionbar .vl-ab-rv.out { border-color:var(--line-a180, rgba(255,255,255,0.18)); color:var(--fg-a700, rgba(255,255,255,0.7)); }

/* Fussleiste in der Grossansicht (Lightbox und Player) */
.vl-rvfoot { display:flex; align-items:center; justify-content:center; gap:10px; flex-wrap:wrap;
  padding:12px 16px 16px; }
.vl-rvbtn { display:inline-flex; align-items:center; gap:8px; padding:11px 20px; border-radius:9999px;
  border:1px solid var(--line-a140, rgba(255,255,255,0.14)); background:var(--surf-a050, rgba(255,255,255,0.05));
  color:var(--fg-1, #fff); font-family:'Funnel Display',sans-serif; font-size:13px; cursor:pointer;
  transition:transform .15s, opacity .15s; }
.vl-rvbtn:hover { transform:translateY(-1px); }
.vl-rvbtn:active { transform:scale(.96); }
.vl-rvbtn:focus-visible { outline:2px solid #F20D46; outline-offset:2px; }
.vl-rvbtn kbd { font-family:'Funnel Display',sans-serif; font-size:10px; opacity:.6; line-height:1;
  border:1px solid currentColor; border-radius:4px; padding:2px 5px; }
.vl-rvbtn.approved.on { background:rgba(48,209,88,0.16); border-color:var(--rv-ok-ink, #30d158); color:var(--rv-ok-ink, #30d158); }
.vl-rvbtn.edit.on { background:rgba(255,208,0,0.16); border-color:var(--rv-warn-ink, #ffd000); color:var(--rv-warn-ink, #ffd000); }
.vl-rvbtn.out.on { background:var(--surf-a120, rgba(255,255,255,0.12));
  border-color:var(--fg-a400, rgba(255,255,255,0.45)); color:var(--fg-1, #fff); }
.vl-rvfoot .vl-rvhint { font-size:11px; color:var(--fg-a350, rgba(255,255,255,0.35)); }
/* Die Lightbox bringt ihren dunklen Grund selbst mit (Inline-Style, den das Theme
   nicht anfasst), ist also in BEIDEN Themes dunkel. Sie traegt deshalb die
   Bestandsklasse .vl-on-dark (theme.js), die dort die Dark-Tokens wieder
   herstellt: Rahmen, Flaechen und die Ink-Faelle stimmen damit von allein.
   Die GEERBTE Textfarbe repariert .vl-on-dark aber nicht: color wird vom body
   als fertiger Wert vererbt, ein neu gesetztes --fg-1 loest ihn nicht neu auf.
   Deshalb hier einmal ausdruecklich, sonst stand der Dateiname im Light-Theme
   dunkel auf dunklem Grund (galt schon vor der Freigabe-Leiste). */
#vl-lightbox, #vl-lb { color: var(--fg-1, #fff); }
@media (max-width: 640px) {
  .vl-rvfoot .vl-rvbtn { flex:1 1 28%; justify-content:center; padding:13px 10px; }
  .vl-rvfoot .vl-rvhint { display:none; }
  .vl-rvchip { min-height:44px; padding:10px 15px; }
}

/* Kurzer Hinweis unten rechts (gespeichert, zurueckgerollt, Link inaktiv) */
.vl-rvtoast { position:fixed; right:20px; bottom:20px; z-index:900; display:flex; align-items:center; gap:12px;
  background:var(--bg-s1, #161616); border:1px solid var(--line-a120, rgba(255,255,255,0.12)); border-radius:12px;
  padding:11px 15px; box-shadow:0 14px 44px rgba(0,0,0,0.5); font-family:'Funnel Display',sans-serif; font-size:13px;
  color:var(--fg-1, #fff); opacity:0; transform:translateY(8px); transition:opacity .18s, transform .18s; }
.vl-rvtoast.on { opacity:1; transform:translateY(0); }
.vl-rvtoast button { background:none; border:0; color:#F20D46; cursor:pointer; font-size:12px;
  font-family:'Funnel Display',sans-serif; text-decoration:underline; padding:0; }
.vl-rvtoast button:hover { opacity:.8; }
.vl-rvtoast button:active { transform:scale(.96); }
.vl-rvtoast button:focus-visible { outline:2px solid #F20D46; outline-offset:2px; }
/* Auf schmalen Schirmen sitzt die Aktionsleiste unten mittig. Der Hinweis rueckt
   darueber und nimmt die volle Breite, sonst laufen lange Meldungen ueber den
   Rand oder liegen auf der Leiste. */
@media (max-width: 560px) {
  .vl-rvtoast { left:12px; right:12px; bottom:88px; }
}
@media (prefers-reduced-motion: reduce) {
  .vl-rvtoast, .vl-rvchip, .vl-rvbtn { transition:none; }
  .vl-rvchip:hover, .vl-rvbtn:hover { transform:none; }
}


/* ===== Kachel-Optik: Markup stammt aus views.js ===== */

/* ===== Film-poster video cards ===== */
.film-card {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  cursor: pointer;
  background: var(--bg-dim, #111);
  border: 1px solid var(--line-a050, rgba(255,255,255,0.05));
  transition: transform 0.4s cubic-bezier(.34,1.56,.64,1), box-shadow 0.4s ease;
}
.film-card:hover {
  transform: translateY(-3px) scale(1.01);
  box-shadow:
    0 20px 60px rgba(0,0,0,0.5),
    0 8px 24px rgba(242,13,70,0.08);
}
.film-card:active { transform: translateY(-2px) scale(0.99); }

/* Solange ein Drei-Punkte-Menue offen ist, darf die Karte NICHT transformiert
   sein. Grund: ein transform macht das Element zum Bezugsrahmen fuer
   position:fixed. Das Menue haengt sich aber bewusst per fixed an den Viewport,
   um dem overflow:hidden der Karte zu entkommen. Mit aktivem Hover-Transform
   greift das nicht mehr, das Menue wird relativ zur Karte platziert und
   weggeschnitten. Es tauchte deshalb erst auf, wenn man die Maus zur Seite
   bewegt hat und der Hover wegfiel.
   transition:none ist dabei kein Schoenheitsfehler, sondern Teil des Fixes: mit
   Transition faehrt der Transform ueber 0.4s zurueck und bleibt in dieser Zeit
   weiter Bezugsrahmen. Die Position wird aber sofort nach dem Klick gemessen. */
.film-card.ctx-open,
.film-card.ctx-open:hover,
.folder-tile.ctx-open,
.folder-tile.ctx-open:hover,
.vl-tile.ctx-open,
.vl-tile.ctx-open:hover {
  transform: none !important;
  transition: none !important;
}

/* Play button pulse on card hover */
.film-play {
  width: 42px; height: 42px;
  border-radius: 50%;
  background: rgba(242,13,70,0.85);
  backdrop-filter: blur(12px);
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.35s cubic-bezier(.34,1.56,.64,1), opacity 0.3s;
  opacity: 0;
  transform: scale(0.7);
  box-shadow: 0 4px 24px rgba(242,13,70,0.4);
}
.film-card:hover .film-play {
  opacity: 1;
  transform: scale(1);
}

/* Image treatment — gradient overlay + color tint */
.film-thumb {
  position: relative;
  aspect-ratio: var(--thumb-ratio, 16/9);
  overflow: hidden;
}
.film-thumb img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.6s cubic-bezier(0.16,1,0.3,1);
}
/* Vorschaubilder blenden weich ein, sobald sie geladen sind, statt hart
   aufzuploppen (views.js setzt .vl-da beim Laden). Was schon im Speicher liegt,
   bekommt die Klasse vor dem ersten Zeichnen und steht sofort. Nur opacity.
   Gilt nur fuer Bilder aus views.js (.vl-fade), andere img auf der Seite nicht. */
img.vl-fade { opacity: 0; transition: opacity .22s cubic-bezier(.2,.8,.2,1), transform 0.6s cubic-bezier(0.16,1,0.3,1); }
img.vl-fade.vl-da { opacity: 1; }
@media (prefers-reduced-motion: reduce) { img.vl-fade { transition: none; } }

/* Vorschaubild noch nicht da: Kachel sagt es, statt leer zu bleiben. Klasse
   setzt und loest views.js thumbFehlt(). Abspielen geht meist schon, deshalb
   nur "Vorschaubild folgt" (nicht "wird verarbeitet", das verwirrte Kunden)
   und der Play-Knopf bleibt sichtbar. */
.film-thumb.vl-encoding:not(.folder-cover)::before, .vl-tile.vl-encoding:not(.folder-cover)::before {
  content: 'Vorschaubild folgt';
  position: absolute; inset: 0; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Funnel Display', sans-serif; font-weight: 700; font-size: 10px;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-a300, rgba(255,255,255,0.35));
  background: var(--surf-a050, rgba(255,255,255,0.05));
}
.film-thumb.vl-encoding .film-play { z-index: 2; }
/* Ordner-Startbild: liegt als Ebene unter dem echten Cover und trägt,
   wenn keins da ist oder es nicht lädt. Theme-Wechsel per CSS, kein JS.

   ⚠️ Der Dateiname trägt eine Version (.v3.). Netlify liefert Assets mit
   `cache-control: max-age=31536000, immutable` aus. `immutable` heißt, der
   Browser fragt NIE nach, bis sich die URL ändert. Ein neues Bild unter dem
   alten Namen kommt bei niemandem an, der die Seite schon einmal geladen hat,
   auch nicht nach hartem Neuladen. Wer das Bild tauscht, zählt die Version
   hoch und passt die vier Stellen hier plus die zwei in admin.html an. */
.folder-cover {
  background: var(--bg-dim, #111) url('Assets/folder-cover-dark.v3.webp') center / cover no-repeat;
}
[data-theme="light"] .folder-cover {
  background-color: #DCCEBD;
  background-image: url('Assets/folder-cover-light.v5.webp');
}
.film-card:hover .film-thumb img {
  transform: scale(1.05);
}
.film-thumb::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(to top,
    #0d0d0d 0%,
    rgba(13,13,13,0.7) 35%,
    rgba(13,13,13,0.1) 60%,
    transparent 100%
  );
}
/* Der Verlauf blendet das Cover in die Karte darunter und endet deshalb auf deren
   Farbe. Ohne diesen Gegenpart lief im Light-Theme jedes Cover unten nach #0d0d0d,
   also ins Schwarze. Betrifft alle Kacheln, nicht nur Ordner. */
/* Im Dark-Modus darf der Verlauf tief greifen, dort blendet dunkel in dunkel und
   man sieht es kaum. Auf Weiss ist derselbe Weg brutal: er hat die untere Haelfte
   jeder Kachel ausgebleicht und aus dem Papier-Icon eine weisse Flaeche gemacht.
   Hier reicht ein kurzer Saum ganz unten, nur damit die Kante nicht hart bricht. */
[data-theme="light"] .film-thumb::after {
  background: linear-gradient(to top,
    rgba(255,255,255,0.8) 0%,
    rgba(255,255,255,0.25) 10%,
    transparent 26%
  );
}

/* Hover video preview scrubber */
.film-thumb .hover-preview {
  position: absolute; inset: 0; z-index: 5;
  object-fit: cover; width: 100%; height: 100%;
  opacity: 0; transition: opacity 0.3s ease;
  pointer-events: none;
}
.film-card:hover .hover-preview.loaded { opacity: 1; }
.film-thumb .scrub-bar {
  position: absolute; bottom: 0; left: 0; height: 3px; z-index: 6;
  background: #F20D46; width: 0%; transition: width 0.05s linear;
  pointer-events: none;
}
.film-card:hover .scrub-bar { opacity: 1; }

/* Draft tiles — nur das Thumbnail dimmen, der Name bleibt hell und lesbar */
.film-card.draft .film-thumb { opacity: 0.45; transition: opacity .25s ease; }
.film-card.draft:hover .film-thumb { opacity: 0.75; }
/* Nur eine Fassung ist Entwurf (V1 ist veroeffentlicht): der Kunde sieht das Video,
   also nicht dimmen. Das Schild "V3 Entwurf" sagt, was fehlt. */
.film-card.draft.draft-teil .film-thumb { opacity: 1; }
.draft-badge {
  position: absolute; top: 8px; left: 8px; z-index: 10;
  padding: 3px 10px; border-radius: 999px;
  font-size: 9px; font-family: 'Unbounded'; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.1em;
  background: var(--surf-a140, rgba(255,255,255,0.14)); color: var(--fg-a850, rgba(255,255,255,0.85));
  backdrop-filter: blur(8px); border: 1px solid var(--line-a140, rgba(255,255,255,0.14));
  transition: transform .15s ease;
}
/* Das Häkchen sitzt an derselben Ecke. Sobald es auftaucht, ruecht "Entwurf"
   daneben, statt sich davon zur Haelfte verdecken zu lassen. */
.film-card:hover .draft-badge, .film-card.sel .draft-badge { transform: translateX(32px); }
@media (prefers-reduced-motion: reduce) { .draft-badge { transition: none; } }
/* Kachel-Namen sind IMMER hell und lesbar */
.film-card h3 { color: var(--fg-1, #fff) !important; opacity: 1 !important; }
.film-card .film-meta { color: var(--fg-a500, rgba(255,255,255,0.5)); }

/* Laufende Uploads — Kachel im Werden.
   Sie sitzt im selben Grid wie die fertigen Medien, damit im Ordner sichtbar
   bleibt, was gerade hochlaedt. Das Upload-Symbol unten rechts zeigt denselben
   Vorgang global, ersetzt die Kachel hier aber nicht: wer den Ordner ansieht,
   soll die Datei im Ordner sehen. */
.vl-up-card { cursor: default; }
.vl-up-card:hover { transform: none; box-shadow: none; }
.vl-up-thumb {
  display: flex; align-items: center; justify-content: center;
  background: var(--surf-a050, rgba(255,255,255,0.05));
  border-bottom: 1px solid var(--line-a080, rgba(255,255,255,0.08));
}
.vl-up-thumb::after { content: none; }   /* kein Verlauf, es liegt kein Bild darunter */
.vl-up-ico {
  font-size: 30px; color: var(--fg-a300, rgba(255,255,255,0.3));
  animation: vl-up-puls 1.8s ease-in-out infinite;
}
.vl-up-card.is-error .vl-up-ico, .vl-up-row.is-error .vl-up-ico, .vl-up-tile.is-error .vl-up-ico {
  color: #F20D46; animation: none;
}
@keyframes vl-up-puls { 0%,100% { opacity: 0.45; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .vl-up-ico { animation: none; } }

.vl-up-track {
  height: 4px; border-radius: 999px; overflow: hidden;
  background: var(--surf-a100, rgba(255,255,255,0.1));
  margin-bottom: 6px;
}
.vl-up-fill {
  height: 100%; border-radius: 999px; background: #F20D46;
  transition: width 0.3s ease;
}
.vl-up-card.is-error .vl-up-fill, .vl-up-row.is-error .vl-up-fill { background: var(--fg-a300, rgba(255,255,255,0.3)); }
/* Mosaik: der Balken liegt als schmale Leiste unten in der Kachel */
.vl-up-track.mosaik { position: absolute; left: 8px; right: 8px; bottom: 8px; margin: 0; z-index: 3; }
/* Liste: schmaler Balken direkt hinter dem Namen */
.vl-up-track.zeile { flex: 0 0 90px; margin: 0 0 0 10px; }

/* Zwei Klassen im Selektor, weil `.vl-compact .vl-tile` sonst Hintergrund und
   Cursor zurueckgewinnt (hoehere Spezifitaet). */
.vl-compact .vl-tile.vl-up-tile {
  display: flex; align-items: center; justify-content: center;
  background: var(--surf-a050, rgba(255,255,255,0.05));
  cursor: default;
}
.vl-compact .vl-tile.vl-up-tile:hover { transform: none; }
.vl-up-row { cursor: default; }
.vl-up-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Context menu */
.ctx-menu { position: absolute; right: 8px; bottom: 8px; z-index: 10; }
/* Der Knopf sitzt auf dem Kachelfuss, also auf der Flaeche der Karte und nicht
   auf dem Bild. Er nimmt deshalb die Theme-Farben statt eines festen Schwarz:
   im Light-Theme war der harte schwarze Kreis ein Fremdkoerper auf der hellen
   Karte. --bg-s2 ist dunkel im Dark-, sandfarben im Light-Theme. */
.ctx-trigger { width: 28px; height: 28px; border-radius: 50%; background: var(--bg-s2, #1f1f1f); border: 1px solid var(--line-a100, rgba(255,255,255,0.1)); backdrop-filter: blur(8px); cursor: pointer; display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.2s, background 0.15s; }
.film-card:hover .ctx-trigger, .folder-tile:hover .ctx-trigger { opacity: 1; }
/* Solange das Menue offen ist, bleibt der Knopf sichtbar, auch wenn die Maus
   die Karte laengst verlassen hat (das Menue haengt am body, nicht an der Karte). */
.film-card.ctx-open .ctx-trigger, .folder-tile.ctx-open .ctx-trigger, .vl-tile.ctx-open .ctx-trigger { opacity: 1; }
.ctx-trigger:hover { background: var(--surf-a140, rgba(255,255,255,0.14)); }
.ctx-trigger:active { transform: scale(0.94); }

/* ---------- Wegploppen beim Loeschen ----------
   Geloeschtes verschwindet sofort und sichtbar, statt stehen zu bleiben, bis
   Datenbank und Storage durch sind. Kurz und hart am Ende, damit es nach
   "weg" aussieht und nicht nach "wird ausgeblendet". */
@keyframes vl-weg-anim {
  0%   { opacity: 1;   transform: scale(1); }
  18%  { opacity: 0.9; transform: scale(1.05); }
  100% { opacity: 0;   transform: scale(0.66); }
}
.vl-weg {
  pointer-events: none;
  animation: vl-weg-anim 0.2s cubic-bezier(.4, 0, .9, .25) forwards;
  transform-origin: center;
  z-index: 1;
}
/* Zeilen kippen nicht in sich zusammen, die schrumpfen zur Seite weg. */
.vl-row.vl-weg { animation-name: vl-weg-zeile; }
@keyframes vl-weg-zeile {
  0%   { opacity: 1; transform: translateX(0); }
  100% { opacity: 0; transform: translateX(-14px); }
}
@media (prefers-reduced-motion: reduce) {
  .vl-weg { animation: none; opacity: 0; }
}
.ctx-trigger:focus-visible { opacity: 1; outline: none; border-color: #F20D46; box-shadow: 0 0 0 1px #F20D46; }
.ctx-item:focus-visible { outline: none; background: var(--surf-a060, rgba(255,255,255,0.06)); box-shadow: 0 0 0 1px #F20D46 inset; }
.ctx-item:active { transform: scale(0.98); }
.ctx-dropdown { position: absolute; right: 0; bottom: 36px; background: var(--bg-s1b, #1a1a1a); border: 1px solid var(--line-a100, rgba(255,255,255,0.1)); border-radius: 12px; padding: 4px; min-width: 150px; box-shadow: 0 12px 40px rgba(0,0,0,0.5); display: none; z-index: 20; }
.ctx-dropdown.open { display: block; }
.ctx-item { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 8px; cursor: pointer; font-size: 12px; font-family: 'Funnel Display'; color: var(--fg-a700, rgba(255,255,255,0.7)); border: none; background: none; width: 100%; text-align: left; transition: background 0.15s; }
.ctx-item:hover { background: var(--surf-a060, rgba(255,255,255,0.06)); color: var(--fg-1, #fff); }
.ctx-item.danger { color: #F20D46; }
.ctx-item.danger:hover { background: rgba(242,13,70,0.1); }

/* ---------- Wisch-Modus (Handy) ---------- */
/* Eine Karte je Bild. Bewegt wird ausschliesslich ueber transform und opacity,
   alles andere zwingt den Browser bei jedem Bild zum Neuberechnen des Layouts,
   und genau das macht das Wischen ruckelig. */
#vl-sw{
  position:fixed; inset:0; z-index:85;
  /* Deckend, nicht durchscheinend. Bei 0.97 schimmerte die Galerie dahinter
     durch (heller Text auf dunklem Grund reicht dafuer schon), und beim Sichten
     zieht jede Bewegung im Hintergrund den Blick vom Bild weg. */
  background:#0a0708;
  display:flex; flex-direction:column;
  opacity:0; transition:opacity .16s ease;
  overscroll-behavior:contain;
}
#vl-sw.offen{ opacity:1; }

.sw-kopf{ display:flex; align-items:center; gap:12px; padding:12px 16px; flex:none; }
/* War min-w-0 von Tailwind. Eigene Klasse, damit im Wisch-Modus ueberhaupt
   keine Tailwind-Klasse mehr vorkommt und sein Beobachter waehrend der Geste
   schlafen darf. */
.sw-info{ min-width:0; }
.sw-titel{ font-size:13px; font-weight:600; color:#fff; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sw-meta{ font-size:11px; color:rgba(255,255,255,.5); font-variant-numeric:tabular-nums; }
.sw-x{
  margin-left:auto; flex:none; width:34px; height:34px; border-radius:50%;
  background:rgba(255,255,255,.08); border:0; color:#fff; font-size:15px; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  transition:transform .12s ease, background-color .12s ease;
}
.sw-x:hover{ background:rgba(255,255,255,.14); }
.sw-x:active{ transform:scale(.94); }
.sw-x:focus-visible{ outline:2px solid rgba(255,255,255,.6); outline-offset:2px; }

.sw-stapel{ position:relative; flex:1 1 auto; margin:4px 16px 8px; min-height:0; }
.sw-karte{
  position:absolute; inset:0; border-radius:18px; overflow:hidden;
  background:#161616; border:1px solid rgba(255,255,255,.09);
  display:flex; align-items:center; justify-content:center;
  will-change:transform;
}
.sw-karte img{ width:100%; height:100%; object-fit:contain; }
/* Die naechste Karte liegt sichtbar dahinter. Ohne sie wirkt der Stapel leer,
   sobald die oberste wegfliegt, und man sieht kurz nur den Hintergrund. */
.sw-hinten{ transform:scale(.94) translateY(10px); opacity:.55; }
/* Der Uebergang gilt nur fuer den Abflug und das Zurueckfedern. Am Finger darf
   die Karte KEINEN haben, sonst laeuft sie der Bewegung um eine Viertelsekunde
   hinterher. Als Klasse statt als Eigenschaft, die in jedem Bild neu gesetzt
   wird. */
.sw-karte.fliegt{ transition:transform .28s cubic-bezier(.22,.61,.36,1), opacity .28s ease; }
/* touch-action:none, NICHT pan-y. pan-y hiesse: das vertikale Wischen gehoert
   dem Browser. Genau das sind hier aber zwei der vier Gesten (hoch bearbeiten,
   runter ueberspringen). Auf einem echten Geraet haette Safari sie abgefangen
   und die Seite gescrollt, statt die Karte dem Finger folgen zu lassen.

   Zu sehen war das in keinem automatischen Test: synthetische Touch-Events
   gehen direkt an das Element und umgehen die Gestenvergabe des Browsers
   vollstaendig. Der Fehler haette erst auf Klaras Handy gestanden.

   Die Listener duerfen deshalb passiv bleiben: mit touch-action:none kommt
   ohnehin jede Geste bei uns an, ein preventDefault waere nur Ballast. */
.sw-vorn{ box-shadow:0 20px 50px rgba(0,0,0,.55); touch-action:none; }

.sw-marke{
  position:absolute; top:18px; left:50%; transform:translateX(-50%);
  padding:8px 16px; border-radius:999px; font-weight:800; font-size:13px;
  letter-spacing:.1em; opacity:0; pointer-events:none;
  border:2px solid currentColor; background:rgba(0,0,0,.45); backdrop-filter:blur(6px);
}
.sw-marke.approved{ color:#30d158; }
.sw-marke.out{ color:rgba(255,255,255,.75); }
.sw-marke.edit{ color:#ffd000; }
.sw-marke.skip{ color:rgba(255,255,255,.5); }

.sw-fuss{ display:flex; align-items:center; justify-content:center; gap:14px; padding:6px 16px 4px; flex:none; }
.sw-btn{
  width:56px; height:56px; border-radius:50%; border:1px solid rgba(255,255,255,.12);
  background:rgba(255,255,255,.06); color:#fff; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  transition:transform .12s ease, background-color .12s ease, opacity .12s ease;
}
.sw-btn .material-symbols-outlined{ font-size:26px; }
.sw-btn:active{ transform:scale(.9); }
.sw-btn:focus-visible{ outline:2px solid rgba(255,255,255,.6); outline-offset:2px; }
.sw-btn.zurueck{ width:44px; height:44px; }
.sw-btn.zurueck:disabled{ opacity:.3; cursor:default; }
.sw-btn.out:hover, .sw-btn.out.on{ background:rgba(255,255,255,.16); }
.sw-btn.edit{ color:#ffd000; }
.sw-btn.edit:hover, .sw-btn.edit.on{ background:rgba(255,208,0,.18); }
.sw-btn.approved{ color:#30d158; }
.sw-btn.approved:hover, .sw-btn.approved.on{ background:rgba(48,209,88,.18); }
.sw-btn.on{ border-color:currentColor; }

.sw-hinweis{
  padding:4px 20px 16px; text-align:center; flex:none;
  font-size:11px; line-height:1.6; color:rgba(255,255,255,.45);
}
.sw-hinweis button{
  display:block; margin:6px auto 0; background:none; border:0; padding:4px 8px;
  color:rgba(255,255,255,.75); text-decoration:underline; cursor:pointer; font-size:11px;
}
.sw-hinweis button:focus-visible{ outline:2px solid rgba(255,255,255,.6); outline-offset:2px; }

.sw-fertig{
  position:absolute; inset:0; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:10px; color:rgba(255,255,255,.7);
}
.sw-fertig .material-symbols-outlined{ font-size:44px; color:#30d158; }
.sw-fertig button{
  margin-top:6px; padding:10px 20px; border-radius:999px; border:0;
  background:var(--btn-primary-bg, #fff); color:var(--btn-primary-fg, #0A0708); font-weight:700; font-size:13px; cursor:pointer;
  transition:transform .12s ease, opacity .12s ease;
}
.sw-fertig button:active{ transform:scale(.95); }
.sw-fertig button:focus-visible{ outline:2px solid rgba(255,255,255,.6); outline-offset:2px; }
