/* ============================================================================
   album.common.css — themeneutrale Struktur-/Verhaltensregeln, die für JEDE
   Instanz gelten. Wird in html.js IMMER *nach* der Theme-CSS geladen.

   Warum diese Datei existiert: die Theme-Dateien (album.css, album.promptheus.css,
   album.violet.css, album.teal.css) sind **vollständige Ersetzungen**, keine
   Ergänzungen — es wird immer genau eine davon geladen. Regeln, die zu einem
   JS-Feature gehören (Grid-Dichte, Tastatur-Fokus, i-Info-Toggle), müssten also
   in allen vier dupliziert werden und liefen sonst auf einzelnen Instanzen
   stillschweigend ins Leere. Genau das war der Fall, bis diese Datei kam.

   Regel: Alles, was **Farbe/Look** ist, gehört in die Theme-CSS. Alles, was
   **Mechanik** ist (Geometrie, Sichtbarkeitszustände von JS-Features), gehört
   hierher — und nutzt Theme-Variablen (--accent …) für die Farbgebung.
   ============================================================================ */

/* ── Grid-Dichte (imgtag-Stil: +/- am Desktop, Pinch auf Touch) ──
   --tile-min setzt JS auf :root; die Kachelbreite folgt daraus. */
:root{--tile-min:96px}
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--tile-min),1fr));gap:0.35rem;user-select:none}
.grid-size-ctl{display:flex;gap:0.2rem}
.gsz-btn{padding:0.5rem 0.75rem!important;min-width:2.4rem;font-weight:700}
@media (pointer:coarse){.grid-size-ctl{display:none!important}} /* Touch: Pinch statt Buttons */

/* ── Tastatur-Navigation im Grid: Fokus-Rahmen + Info-Overlay ── */
.item.gnav-focus{outline:2px solid var(--accent);outline-offset:1px;box-shadow:0 0 12px var(--accent-a40)}
.gnav-info{position:absolute;inset:auto 0 0 0;background:rgba(0,0,0,0.72);color:#fff;font-size:0.6rem;line-height:1.35;padding:0.3rem 0.4rem;pointer-events:none;white-space:pre-wrap;backdrop-filter:blur(3px)}

/* ── Virtualisiertes Grid (TanStack Virtual ueber Zeilen) ──
   .gallery-virt ist der Rahmen, .gv-inner haelt die Gesamthoehe (damit die
   Bildlaufleiste stimmt), .gv-row wird per transform an die richtige Stelle
   geschoben. Nur sichtbare Zeilen liegen im DOM. */
.gallery-virt{position:relative;width:100%}
.gv-inner{position:relative;width:100%}
.gv-row{position:absolute;top:0;left:0;right:0;will-change:transform}
.gv-row .item{position:absolute}

/* ── Bildunterschrift (Name/Größe) nur bei aktivem i-Toggle ──
   Ohne i zeigt das Grid wirklich nur Bilder, kein reservierter Textplatz. */
.item-info{display:none}
body.grid-info-on .item-info{display:block}

/* ── Datumskoepfe im virtualisierten Grid ── */
.gv-head{display:flex;align-items:flex-end;padding:0 0.2rem 0.35rem;font-size:0.78rem;font-weight:600;color:var(--accent);cursor:pointer;user-select:none}
.gv-head:hover{color:#fff}

/* ── Auswaehlen-Modus ── */
body.select-mode .item{cursor:copy}
body.select-mode .item .item-check{opacity:1}
/* Waehrend der Wisch-Auswahl kein Text-Markieren/Scrollen in der Galerie */
body.select-mode .gallery-virt{touch-action:pan-y;user-select:none}

/* ── Kopfzeile: Titel + Anzahl, Button-Reihe ──
   Die Anzahl steht schon serverseitig im HTML (erster Paint), der Client traegt
   danach den gefilterten Stand nach. */
.hdr-top{display:flex;align-items:baseline;justify-content:space-between;gap:0.8rem;flex-wrap:wrap}
.hdr-count{font-size:0.78rem;color:rgba(255,255,255,0.45);white-space:nowrap}
.hdr-btns{display:flex;gap:0.6rem;flex-wrap:wrap;margin-top:0.8rem}

/* ── Skeleton: die Form der Seite steht im ersten Paint ──
   Vorher war die Seite bis zum Eintreffen von api/list voellig leer und damit
   nicht von einem leeren Album zu unterscheiden. Serverseitig gerendert, wird
   beim ersten loadPane() durch das echte Grid ersetzt. */
.skel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--tile-min),1fr));gap:0.35rem}
.skel-tile{aspect-ratio:1;border-radius:8px}
.skel-tile,.item.loading{
  background-color:rgba(255,255,255,0.06);
  background-image:linear-gradient(100deg,transparent 15%,rgba(255,255,255,0.13) 50%,transparent 85%);
  background-size:220% 100%;background-repeat:no-repeat;
  animation:skel-sweep 1.3s ease-in-out infinite;
}
.item.loading img{opacity:0}
.item img{transition:opacity 0.25s}
@keyframes skel-sweep{from{background-position:120% 0}to{background-position:-120% 0}}
@media (prefers-reduced-motion:reduce){.skel-tile,.item.loading{animation:none}}

/* ── Stoerung beim Laden (statt stehengebliebener Skeleton-Kacheln) ── */
.pane-error{padding:1.5rem 0.2rem;color:rgba(255,255,255,0.75);font-size:0.88rem;line-height:1.5}
.pane-error-detail{margin:0.4rem 0 0.9rem;font-size:0.78rem;color:rgba(255,255,255,0.45);word-break:break-word}

/* ── Mobile Bedienleiste unten + Mehr-Sheet ──
   Nur unter 600px aktiv (album.js haengt die Header-Buttons per matchMedia um).
   Daumenerreichbar, und der Header schrumpft auf Titel + Anzahl. */
.mobile-bar{position:fixed;left:0;right:0;bottom:0;z-index:70;display:flex;align-items:stretch;gap:0.3rem;
  padding:0.35rem 0.5rem;padding-bottom:max(0.35rem,env(safe-area-inset-bottom));
  background:rgba(18,20,28,0.92);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  border-top:1px solid rgba(255,255,255,0.09)}
.mobile-bar-slots{display:flex;flex:1;gap:0.3rem;min-width:0}
.mobile-bar .btn,.mbar-more{flex:1;min-width:0;justify-content:center;font-size:0.7rem;
  padding:0.55rem 0.3rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mbar-more{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:0.05rem;
  max-width:4.5rem;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);
  color:#e0e0e0;font-family:inherit;font-size:1rem;line-height:1;cursor:pointer}
.mbar-more span{font-size:0.6rem;opacity:0.75}
/* Grid nicht hinter der Leiste verstecken */
body.has-mobile-bar{padding-bottom:4.2rem}
body.has-mobile-bar .hdr-btns{display:none}
/* Auswahl-Leiste ueber die Bedienleiste heben statt sie zu ueberdecken */
body.has-mobile-bar .sel-toolbar{bottom:4.4rem}

.sheet-backdrop{position:fixed;inset:0;z-index:75;background:rgba(0,0,0,0.5)}
.more-sheet{position:fixed;left:0;right:0;bottom:0;z-index:80;
  background:rgba(22,24,32,0.98);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  border-top:1px solid rgba(255,255,255,0.12);border-radius:14px 14px 0 0;
  padding:0.5rem 1rem calc(1rem + env(safe-area-inset-bottom));
  transform:translateY(100%);transition:transform 0.22s ease-out}
.more-sheet.open{transform:translateY(0)}
.sheet-grip{width:2.5rem;height:0.25rem;border-radius:999px;background:rgba(255,255,255,0.25);
  margin:0.25rem auto 0.7rem;cursor:pointer}
.sheet-title{font-size:0.72rem;text-transform:uppercase;letter-spacing:0.06em;
  color:rgba(255,255,255,0.4);margin-bottom:0.6rem}
.sheet-btns{display:grid;grid-template-columns:1fr 1fr;gap:0.5rem}
.sheet-btns .btn{justify-content:flex-start;font-size:0.78rem;padding:0.65rem 0.7rem}
.sheet-btns .grid-size-ctl{grid-column:1 / -1}
@media (prefers-reduced-motion:reduce){.more-sheet{transition:none}}

/* ── Kontextmenue (langes Druecken / Rechtsklick) ── */
#item-menu{position:fixed;z-index:300;min-width:12rem;background:rgba(18,20,28,0.96);border:1px solid rgba(255,255,255,0.16);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);padding:0.35rem;box-shadow:0 10px 40px rgba(0,0,0,0.5)}
.im-name{padding:0.3rem 0.5rem 0.45rem;font-size:0.7rem;color:rgba(255,255,255,0.45);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.im-row{display:block;width:100%;text-align:left;background:none;border:none;color:rgba(255,255,255,0.88);font-family:inherit;font-size:0.82rem;padding:0.5rem 0.55rem;cursor:pointer}
.im-row:hover{background:rgba(255,255,255,0.08);color:var(--accent)}
.im-row.danger{color:#f43f5e}
.im-row.danger:hover{background:rgba(244,63,94,0.12)}
