/* ==========================================================================
   NAO STOCK — Bildarchiv
   Aufsatz auf css/unlisted.css. Das Broadsheet-System liefert Farben, Schrift
   und Kopfleiste; hier steht nur, was ein Bildarchiv zusätzlich braucht:
   das Masonry-Raster und der Leuchtkasten.

   Papier, Tinte, Haarlinien — keine Rundungen, keine Schatten, keine Verläufe.
   Jede Kachel trägt ihre Haarlinie: Der Bestand besteht überwiegend aus
   Blaupausen — Lilac-Linien auf demselben Papier, das auch die Seite trägt.
   Ohne Rahmen hätten diese Bilder keine Kante und schwämmen als lose Striche
   im Satzspiegel. Bei Fotos schadet die Linie nichts, bei Blaupausen ist sie
   das einzige, was die Kachel begrenzt.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Kopfleiste — Wortmarke, Schlagworte, Suche
   -------------------------------------------------------------------------- */

/* Wortmarke „Private Stock Funds".
   Das Signet ist ein gestufter Stapel aus drei Blättern — es liest sich als
   Bildstapel und als Tranchen zugleich, also als beides, was der Name meint.
   Gebaut aus der Grammatik des Hauses: rechte Winkel, 1px-Haarlinien, eine
   einzige lilafarbene Fläche. Das hinterste Blatt trägt das Lilac und bleibt
   lila, während die beiden vorderen mit der Textfarbe kippen — der Akzent
   gehört der Marke, nicht dem Text.
   Der Name steht in der Serife: Er ist der lange Teil der Marke und braucht
   die ruhigere Schrift. */
.smark { display: flex; align-items: center; gap: 11px; color: var(--ink); min-width: 0; }
.smark__sig { flex: none; height: 24px; width: auto; display: block; overflow: visible; }
.smark b {
  font-family: var(--serif); font-weight: 700;
  font-size: 21px; line-height: 1; letter-spacing: -.022em;
  white-space: nowrap;
}
.smark--gross .smark__sig { height: 38px; }
.smark--gross b { font-size: 32px; }

/* Über dem Raster steht keine Filterliste. Auf einer Bilderwand ist die Liste
   der Schlagworte selbst schon eine Textwand — sie schob die erste Bildreihe
   nach unten und war bei wachsendem Bestand die längste Zeile der Seite.
   Gefiltert wird über die Schlagworte im Leuchtkasten; ist ein Filter gesetzt,
   zeigt ihn dieser eine Knopf und hebt ihn beim Anklicken wieder auf. */
.sfilter {
  flex: none; cursor: pointer;
  background: var(--lilac); color: var(--ink);
  border: 0; padding: 7px 11px;
  font-weight: 600; font-size: 10px; line-height: 1;
  letter-spacing: .18em; text-transform: uppercase;
}
.sfilter:hover { background: var(--ink); color: var(--on-dark); }
.sfilter span { margin-left: 8px; }

/* --------------------------------------------------------------------------
   Seitenkopf
   -------------------------------------------------------------------------- */

/* Kein Aufmacher und keine Leiste: Das Archiv beginnt mit dem Raster. Eine
   große Überschrift über einer Bilderwand erklärt nichts, was die Bilder nicht
   selbst zeigen, und eine Trennlinie darüber zöge eine zweite Kante direkt unter
   die der Kopfzeile — zwei Striche für eine Trennung. Was in der Leiste stand,
   steht jetzt in der Kopfzeile: der Zähler und, wenn gesetzt, der Filter. */
.smain { padding-top: 22px; }

/* Der Zähler zeigt immer den echten Bestand; bei gesetztem Filter „12 / 123". */
.scount {
  flex: none; white-space: nowrap;
  font-weight: 600; font-size: 10px; line-height: 1.2;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--on-light-66);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   Masonry
   Vier Spalten, oben UND unten bündig.
   Das leistet der CSS-Mehrspaltensatz nicht: Er verteilt die Kacheln zwar auf
   Spalten, aber jede Spalte endet dort, wo ihre letzte Kachel zufällig aufhört —
   unten franst das Raster aus. Bündig unten heißt: Alle Spalten müssen auf
   dieselbe Höhe kommen. Also wird gerechnet — `masse()` in stock.html schreibt
   jeder Kachel ihre Höhe in Pixeln ans Element, hier steht nur das Gerüst.
   Gestreckt wird dabei nicht das Bild, sondern der Ausschnitt: Die Kachel füllt
   mit `cover`, eine andere Höhe heißt ein anderer Anschnitt, keine Verzerrung.
   -------------------------------------------------------------------------- */

.sgrid { display: flex; align-items: flex-start; gap: 8px; padding-bottom: 96px; }
.scol { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
/* Wie viele Spalten es sind, entscheidet stock.html — die Zahl geht in die
   Höhenrechnung ein und dürfte hier nicht daneben noch einmal stehen. */
@media (max-width: 700px) { .sgrid, .scol { gap: 6px; } }

.stile {
  display: block; position: relative;
  flex: none;
  width: 100%; margin: 0;
  /* Rückfall, wenn masse() nicht rechnen kann — etwa weil die Seite in einem
     nicht dargestellten Rahmen liegt und die Breite 0 ist. Ohne ihn hätte die
     Kachel dann gar keine Höhe und das Raster fiele zu Streifen zusammen. Die
     ausgerechnete Höhe steht als inline height am Element und sticht das hier. */
  aspect-ratio: var(--ar, 16 / 9);
  /* Papier statt Tinte als Grund: Solange das Bild noch lädt, steht dort eine
     leere Fläche in der Farbe der Seite — eine dunkle Platte, die dann in eine
     helle Blaupause umschlägt, blitzt bei jedem Bild einmal auf. */
  background: var(--paper);
  cursor: zoom-in;
  /* Keine Linie um die Kachel. Nötig war sie nur, solange der Bestand aus
     Blaupausen bestand — Lilac-Linien auf demselben Papier wie die Seite, die
     ohne Rahmen keine Kante gehabt hätten. Der Bestand sind jetzt Fotos, und
     die bringen ihre Kante selbst mit; jede zusätzliche Linie legte nur ein
     Gitternetz über die Bilderwand.
     ACHTUNG: Kommen die Blaupausen zurück (ARTIKELBILDER_AUFNEHMEN in
     api/stock.php), braucht .stile--blau seine Haarlinie wieder — sonst
     schwimmen sie als lose Striche im Satzspiegel. */
  border: 0; padding: 0; text-align: left; color: inherit;
  overflow: hidden;
}
/* Die Höhe steht am .stile selbst (in Pixeln, aus masse()) und ist bekannt,
   bevor ein einziges Bild geladen ist — sonst spränge das Raster bei jedem
   eintreffenden Bild. Der Rahmen füllt sie. */
.stile__frame { display: block; width: 100%; height: 100%; }
/* Einblenden beim Scrollen.
   Sichtbar wird ein Bild erst, wenn ZWEI Dinge zutreffen: Es ist geladen
   (Klasse am Bild) und seine Kachel steht im Fenster (Klasse an der Kachel).
   Beides zu trennen ist der ganze Punkt — geladen wird mit Vorlauf, damit beim
   Scrollen nichts fehlt, gezeigt wird erst im Fenster, damit die Einblendung
   auch gesehen wird. Fielen beide zusammen, blendete das Bild außerhalb des
   Sichtfelds ein und stünde beim Hereinscrollen einfach fertig da. */
.stile img {
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0;
  transform: scale(1.035);
  transition: opacity .6s cubic-bezier(.2, .6, .2, 1), transform .8s cubic-bezier(.2, .6, .2, 1);
  will-change: opacity, transform;
}
.stile.is-sicht img.geladen { opacity: 1; transform: none; }
/* Treppe statt Gitter — der Pinterest-Griff.
   Pinterest staffelt, weil die Pins verschiedene Formate haben. Die Blaupausen
   des Hauses sind ausnahmslos 16:9; bei gleicher Spaltenbreite steht damit jede
   Kachel gleich hoch und aus dem Wasserfall wird eine Tabelle. Deshalb bekommt
   jede Blaupause eine von drei Kachelhöhen zugeteilt (16:9, 3:2, 4:3).

   Das Bild FÜLLT diesen Rahmen (`cover`), es wird nicht eingepasst. Eingepasst
   schwebte die Zeichnung mittig in der höheren Kachel und die Zeichnungen
   standen von Kachel zu Kachel auf verschiedener Höhe — bündig sind dann die
   Rahmen, aber nicht das, was man sieht. Gefüllt sitzt jede Zeichnung oben auf
   der Kante. Der Preis ist ein seitlicher Anschnitt: Aus 16:9 in eine 4:3-Kachel
   fehlt rund ein Viertel der Breite. Der Schnitt liegt deshalb mittig — die
   Motive sind zentrierte isometrische Kompositionen, da nimmt ein symmetrischer
   Schnitt am wenigsten weg. Das Vollbild im Leuchtkasten zeigt ohnehin die
   ungeschnittene Zeichnung. */
/* Der Schnitt liegt rechtsbündig — dieselbe Regel wie bei den Artikelkarten in
   css/unlisted.css: Die Titelbilder tragen ihr eingebranntes „AI generiert" in
   der rechten unteren Ecke, ein mittiger Schnitt würde es anschneiden. Die
   Motive sind weiträumig, der fehlende linke Rand fällt nicht auf.

   ACHTUNG — die Zeile für die Blaupausen trägt: Seit das HTML-Schild entfallen
   ist, ist das eingebrannte Zeichen ihre EINZIGE AI-Kennzeichnung im Raster.
   Wer .stile--blau auf einen mittigen oder linksbündigen Schnitt setzt,
   schneidet sie ab und muss .stile__ai wieder einsetzen.
   Fotos aus dem Bildpool haben dort nichts stehen; bei ihnen liegt das Motiv in
   der Mitte, also wird auch mittig geschnitten. */
.stile img { object-position: 50% 50%; }
.stile--blau img { object-position: 100% 50%; }


/* Die Beschriftung ist eine kompakte Plakette unten links, wie im Vorbild —
   nur eckig statt als Pille, weil das Broadsheet keine Rundungen kennt. Sie ist
   so breit wie ihr Text und höchstens so breit wie zwei Drittel der Kachel; über
   die volle Breite gezogen verdeckte sie das halbe Bild und wäre keine Plakette
   mehr, sondern eine Bauchbinde. */
.stile__cap {
  position: absolute; left: 8px; bottom: 8px; max-width: calc(100% - 16px);
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--paper); color: var(--ink);
  padding: 7px 8px 7px 11px;
  opacity: 0; transform: translateY(4px);
  transition: opacity .16s ease, transform .16s ease;
  pointer-events: none;
}
.stile__cap b {
  min-width: 0;
  font-weight: 600; font-size: 12px; line-height: 1.2; letter-spacing: -.005em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.stile__cap span {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  background: var(--ink); color: var(--paper);
  font-size: 10px; line-height: 1;
}
.stile:hover .stile__cap, .stile:focus-visible .stile__cap { opacity: 1; transform: none; }

/* AI-Kennzeichnung: Die Blaupausen tragen sie eingebrannt in der rechten
   unteren Ecke, aber object-fit: cover kann sie abschneiden. Deshalb trägt
   die Kachel ihr eigenes Schild — sichtbar bleibt es in jedem Zuschnitt. */
/* Das HTML-Schild „AI generiert" ist entfallen — achtundsechzig dunkle Marken
   waren das, was das Raster unruhig machte. Die Kennzeichnung bleibt trotzdem:
   Sie steht eingebrannt in der rechten unteren Ecke jeder Zeichnung, und der
   rechtsbündige Schnitt oben lässt genau diese Ecke stehen. Die Regel des
   Hauses verlangt das Schild nur dort, wo der Zuschnitt das eingebrannte
   Zeichen verdecken KANN — hier kann er es nicht. Ändert sich der Schnitt,
   muss das Schild zurück. */

.sleer { padding: 80px 0 120px; text-align: center; color: var(--on-light-66); }
.sleer b { display: block; font-family: var(--serif); font-size: 30px; color: var(--ink); margin-bottom: 10px; letter-spacing: -.02em; }
.sleer code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; background: rgba(213, 197, 246, .4); padding: 2px 5px; }

/* --------------------------------------------------------------------------
   Leuchtkasten
   -------------------------------------------------------------------------- */

.slb {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: stretch;
  background: rgba(27, 19, 39, .94);
}
.slb[hidden] { display: none !important; }
.slb__stage {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 40px;
}
.slb__stage img { max-width: 100%; max-height: calc(100vh - 80px); width: auto; height: auto; object-fit: contain; }

.slb__side {
  flex: none; width: 372px; max-width: 42vw;
  background: var(--paper); color: var(--ink);
  border-left: 1px solid var(--rule);
  padding: 26px var(--pad) 26px 30px;
  display: flex; flex-direction: column; gap: 18px;
  overflow-y: auto;
}
.slb__kick { font-weight: 600; font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--on-light-66); }
.slb__title {
  margin: 0; font-family: var(--serif); font-weight: 700;
  font-size: 30px; line-height: 1.08; letter-spacing: -.024em;
}
.slb__note { margin: 0; font-size: 13px; line-height: 1.65; color: var(--on-light-66); }
.slb__facts { display: grid; grid-template-columns: auto 1fr; gap: 8px 18px; margin: 0; padding: 16px 0 0; border-top: 1px solid var(--on-light-12); }
.slb__facts dt { font-weight: 600; font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--on-light-45); padding-top: 2px; }
.slb__facts dd { margin: 0; font-size: 13px; line-height: 1.5; word-break: break-word; }
.slb__tags { display: flex; flex-wrap: wrap; gap: 7px; }
.slb__tags button {
  background: none; cursor: pointer;
  border: 1px solid var(--on-light-12); padding: 5px 9px;
  font-weight: 600; font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--on-light-66);
}
.slb__tags button:hover { border-color: var(--ink); color: var(--ink); }
/* Der Download steht als einziger Knopf in voller Breite und in Tinte — er ist
   das, wofür ein Bildarchiv da ist. „Im Tab öffnen" und „Pfad kopieren" sind
   Nebenwege und teilen sich die Zeile darunter. Drei gleich große Knöpfe
   nebeneinander passten in die 372 px der Spalte ohnehin nicht lesbar. */
.slb__acts { margin-top: auto; display: flex; flex-direction: column; gap: 8px; padding-top: 18px; }
.slb__acts__row { display: flex; gap: 8px; }
.slb__acts a, .slb__acts button {
  flex: 1 1 auto; text-align: center; cursor: pointer;
  border: 1px solid var(--rule); background: none; color: var(--ink); padding: 12px 14px;
  font-weight: 600; font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
}
.slb__acts a:hover, .slb__acts button:hover { background: var(--lilac); border-color: var(--lilac); color: var(--ink); }
.slb__acts--prim { background: var(--ink); color: var(--on-dark); border-color: var(--ink); }

.slb__x {
  position: absolute; left: 26px; top: 22px;
  width: 38px; height: 38px; cursor: pointer;
  background: none; border: 1px solid var(--rule-dark-2); color: var(--on-dark);
  font-size: 16px; line-height: 1;
}
.slb__x:hover { background: var(--lilac); color: var(--ink); border-color: var(--lilac); }

/* Blättern mit den Pfeiltasten geht immer; die Knöpfe sind die sichtbare Fassung. */
.slb__step {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 44px; height: 60px; cursor: pointer;
  background: none; border: 1px solid var(--rule-dark-2); color: var(--on-dark);
  font-size: 15px; line-height: 1;
}
.slb__step:hover { background: var(--lilac); color: var(--ink); border-color: var(--lilac); }
.slb__step--prev { left: 26px; }
.slb__step--next { right: calc(372px + 26px); }
@media (max-width: 900px) { .slb__step--next { right: 26px; } }

/* Im Hochformat steht das Bild oben, die Angaben darunter. Die Knöpfe rücken
   in eine Reihe an den oberen Rand: seitlich stehende Pfeile lägen dort über
   dem Bild und wären auf halber Höhe des Fensters nicht mehr zu treffen. */
@media (max-width: 900px) {
  .slb { flex-direction: column; overflow-y: auto; }
  .slb__stage { flex: none; padding: 64px 16px 16px; min-height: 0; }
  .slb__stage img { max-height: 46vh; }
  .slb__side { width: auto; max-width: none; border-left: 0; border-top: 1px solid var(--rule); padding: 22px 20px 26px; }
  .slb__x { left: 16px; top: 14px; width: 36px; height: 36px; }
  .slb__step { top: 14px; transform: none; width: 40px; height: 36px; }
  .slb__step--prev { left: auto; right: 62px; }
  .slb__step--next { right: 16px; }
}

@media (max-width: 700px) {
  /* Am Telefon teilen sich Wortmarke und Suchfeld eine Zeile von 335 px.
     Die Marke gibt nach, das Suchfeld bleibt bedienbar. */
  .smark { gap: 8px; }
  .smark__sig { height: 19px; }
  .smark b { font-size: 16px; }
  .smain { padding-top: 14px; }
  /* Am Telefon konkurrieren Zähler und Suchfeld um dieselbe Zeile — die Suche
     gewinnt, die Zahl steht ohnehin im Raster darunter. */
  .scount { display: none; }
}

/* Ohne Bewegungswunsch bleibt das Einblenden, aber ohne Weg dahin: Das Bild ist
   entweder da oder nicht. Ganz ohne Übergang stünde sonst ein hartes Aufblitzen. */
@media (prefers-reduced-motion: reduce) {
  .stile img { transition: opacity .01s linear; transform: none; }
  .stile.is-sicht img.geladen { transform: none; }
  .stile__cap { transition: none; }
}
