/* shinyvase.ch — Homepage / Gallery-Grid
 * Editorial-Minimalism / Museum: monochrom, viel Weissraum, die Vasen liefern die Farbe.
 * Eigenes Stylesheet, siehe wiki/specs/2026-07-09-shinyvase-design-konzept.md.
 * KEIN teil3 global1.css, KEIN 3d-druckerei-Stylesheet — eigenstaendige Marke. */

@font-face {
  font-family: 'EB Garamond';
  src: url('../fonts/EBGaramond.ttf') format('truetype');
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'EB Garamond';
  src: url('../fonts/EBGaramond-Italic.ttf') format('truetype');
  font-weight: 400 600;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('../fonts/Inter-Regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('../fonts/Inter-Medium.otf') format('opentype');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Museum-Palette — monochrom, die Vasen liefern die Farbe. */
  --color-primary: #18181B;
  --color-on-primary: #FFFFFF;
  --color-foreground: #09090B;
  --color-background: #FAFAF9;
  --color-card: #FFFFFF;
  --color-muted: #F4F4F1;
  --color-muted-foreground: #6B7280;
  --color-border: #E4E4E1;
  --color-accent: #57534E;
  --color-destructive: #DC2626;
  --color-ring: #18181B;

  /* --- Grundton: Seite, Karte, Bild ------------------------------------
     EIN Ton fuer alles: Seite, Karte und Bild-Slot. Die Karte hebt sich
     allein durch --karten-schatten ab, nicht durch einen Farbunterschied.
     Deshalb 0.2 und nicht 0.12 -- auf gleichem Grund muss der Schatten die
     Kante ueberhaupt erst erzeugen.

     DERSELBE WERT steht in vaseprep/freistellen.py als BG (dort als RGB-
     Tupel). Er wird beim Export in die WebP-Dateien EINGEBRANNT -- aendert
     man ihn hier, muessen die Vasen neu exportiert werden, sonst umgibt jedes
     Foto eine Kante. Die beiden Stellen sind durch
     tests/test_hintergrundfarbe.py gekoppelt: der Test liest dieses CSS und
     schlaegt an, wenn die Werte auseinanderlaufen.

     --vase-seite-unten macht aus dem Grund einen Verlauf. Gleicher Wert wie
     --vase-seite = flach (aktuell so). */
  --vase-seite: #FEFEFE;
  --vase-seite-unten: #FEFEFE;
  --vase-karte: #FEFEFE;
  --vase-bild: #FEFEFE;
  --karten-schatten: 0.2;

  --font-brand: 'EB Garamond', Garamond, 'Times New Roman', serif;
  --font-body: 'Inter', system-ui, sans-serif;

  --space-section: 64px;
  --transition-fast: 220ms ease-out;
}

* {
  box-sizing: border-box;
}

html {
  min-height: 100dvh;
}

body {
  margin: 0;
  min-height: 100dvh;
  /* Grauer Grund mit weichem Verlauf: oben heller, unten etwas tiefer. Er ist
     der Trenner zwischen den weissen Karten -- die Karten sind Flaechen, die
     darauf liegen. Ohne den Kontrast verschwindet die Kartenkante und der
     Text unter dem Bild wirkt heimatlos. Sehr flacher Verlauf, das Auge soll
     ihn nicht als Effekt bemerken.
     Setzt man --vase-seite-unten auf denselben Wert wie --vase-seite, wird der
     Verlauf flach -- das ist der Fall, wenn Seite und Karte denselben Ton
     haben sollen. Dann traegt --karten-schatten die Trennung allein. */
  background: linear-gradient(180deg, var(--vase-seite) 0%,
                              var(--vase-seite-unten) 100%);
  background-attachment: fixed;
  color: var(--color-foreground);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

@media (max-width: 480px) {
  body { font-size: 16px; } /* kein iOS-Auto-Zoom */
}

a {
  color: inherit;
}

/* Sichtbarer Focus-Ring fuer Keyboard-Nav (a11y) */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
.vase-card:focus-visible {
  outline: 2px solid var(--color-ring);
  outline-offset: 2px;
}

/* Kopfzeile: Logo links, Filter rechts daneben — EINE Zeile, damit die Vasen
   ohne Scrollen anfangen. Das Siegel ist die Marke, es braucht keine Buehne. */
.shinyvase-topbar {
  display: flex;
  align-items: center;
  gap: 24px;
  /* Volle Seitenbreite (nur der Header, das Grid darunter bleibt zentriert).
     nowrap: die Zeile bricht nie um -- bei Enge werden die Filter kompakter
     (siehe .vase-filters__inner / .vase-filter select), nicht mehrzeilig. */
  width: 100%;
  margin: 0;
  padding: 14px 32px;
  flex-wrap: nowrap;
}
/* Nur die GALERIE-Topbar klebt beim Scrollen oben (Filter + Warenkorb bleiben
   greifbar, waehrend man durch die Vasen scrollt). Selektor via :has(.vase-filters):
   nur der Galerie-Header traegt die Filter -- Detail/Warenkorb/Ueber-uns bleiben
   im Fluss (dort kollidierte sticky mit dem -88px-Hochzug der Titel).

   Der sichtbare #FEFEFE-Balken (Vasen-Grundton) endet an der FILTER-Unterkante,
   nicht an der Logo-/Warenkorb-Unterkante: dazu traegt der Header nur oben
   Padding (align-items:flex-start, padding-bottom 0), seine Hoehe ist damit
   padding-top + Filterhoehe. Logo und Warenkorb sind aus dem Fluss genommen
   (position:absolute) -- sie bestimmen die Balkenhoehe nicht und ragen nach
   unten darueber hinaus. Mit z-index:-1 liegen sie UNTER dem Grid (das
   z-index:1 bekommt), verschwinden beim Scrollen also hinter den Vasen.

   NUR ab 821px (Desktop): unter 820px greift der Spaltenmodus-Media-Query weiter
   unten, der die Topbar stapelt -- absolute Logos/Cart und die margin-Werte
   wuerden dieses Layout zerreissen (Filter liefen aus dem Schirm, Warenkorb
   ueberlappte). Mobil bleibt der Header also im normalen Fluss, nicht sticky. */
@media (min-width: 821px) {
  .shinyvase-topbar:has(.vase-filters) {
    position: sticky;
    top: 0;
    z-index: 2;
    background: #FEFEFE;
    align-items: flex-start;
    /* 4px unten: der #FEFEFE-Balken reicht knapp UNTER die Select-Unterkante,
       damit deren heller Rahmen (border 0.6px) + der Sub-Pixel-Uebergang zum
       Grund nicht als schmaler Streifen unter der Filterleiste durchscheinen. */
    padding: 16px 32px 4px;
    overflow: visible;
  }
  /* Der Langswitch ist nur 21px hoch, die Filterleiste daneben 36px. Mit dem
     align-items:flex-start oben (das der #FEFEFE-Balken braucht) haengt er an
     der Oberkante und sitzt 7.5px ueber dem Zaehler "38 / 38", der in der
     Filterleiste mittig steht. align-self:center gibt ihm dieselbe Mitte,
     ohne die Balkenhoehe anzutasten. */
  .shinyvase-topbar:has(.vase-filters) .shinyvase-langswitch {
    align-self: center;
  }
  .shinyvase-topbar:has(.vase-filters) > a:has(.shinyvase-topbar__logo),
  .shinyvase-topbar:has(.vase-filters) .shinyvase-cart {
    position: absolute;
    z-index: -1;
  }
  .shinyvase-topbar:has(.vase-filters) > a:has(.shinyvase-topbar__logo) {
    top: 14px;
    left: 32px;
  }
  /* Weisser Ellipsen-Grund hinter dem maskierten Logo. Das Logo-SVG rendert per
     CSS-Maske nur Kontur + Schriftzug (die Ellipse ist fill:none) -- ohne Grund
     scheint der Seitenhintergrund durch. Das <img> selbst kann kein ::before
     tragen, darum sitzt es am Logo-<a>: eine weisse Ellipse (border-radius:50%),
     knapp innerhalb der Kontur, hinter dem Logo (z-index:-1). */
  .shinyvase-topbar:has(.vase-filters) > a:has(.shinyvase-topbar__logo)::before {
    content: "";
    position: absolute;
    inset: 3px 5px;
    border-radius: 50%;
    background: #FFFFFF;
    z-index: -1;
  }
  .shinyvase-topbar:has(.vase-filters) .shinyvase-cart {
    top: 16px;
    right: 32px;
    margin-left: 0;
  }
  /* Das Logo ist aus dem Fluss (absolute), die Filter wuerden sonst ganz links
     unter ihm beginnen. Linker Abstand = Logo-Breite (119px) + gap (24px), damit
     die Filterleiste rechts neben dem Logo startet. */
  .shinyvase-topbar:has(.vase-filters) .vase-filters {
    margin-left: 143px;
  }
  /* Der Warenkorb ist aus dem Fluss (absolute, right:32px) -- der Sprachumschalter
     weiss davon nichts und wuerde bis unter den Warenkorb laufen. Rechter Abstand
     = Warenkorb-Breite (44px) + gap (24px), damit der Umschalter davor endet. */
  .shinyvase-topbar:has(.vase-filters) .shinyvase-langswitch {
    margin-right: 68px;
  }
  /* Grid ueber Logo/Warenkorb legen, damit die Vasen sie beim Scrollen verdecken. */
  .shinyvase-topbar:has(.vase-filters) ~ main {
    position: relative;
    z-index: 1;
  }
}

/* Das Logo kommt als <img src="logo.svg"> -- ein <img> rendert das SVG in
   einem eigenen Dokument und erbt daher KEIN currentColor aus dieser Seite.
   Statt das 22-KB-SVG in jedes Jelly zu inlinen (zwei Pflegestellen), wird es
   hier als Maske benutzt: die Silhouette schneidet die Flaeche aus, die Farbe
   kommt aus background-color -- und damit aus dem Token, das im dunklen Theme
   mitwandert. Der weisse Ellipsen-Fill im SVG ist auf none gesetzt, sonst
   waere die Maske eine volle Ellipse statt einer Kontur. */
.shinyvase-topbar__logo {
  display: block;
  /* Maskiertes <img> hat keine Intrinsic-Size mehr -> Breite explizit.
     Siegel-Seitenverhaeltnis 754:470, bei 74px Hoehe also 119px. */
  width: 119px;
  height: 74px;
  flex: none;
  background-color: var(--color-foreground);
  -webkit-mask: url("../img/logo.svg") no-repeat center / contain;
  mask: url("../img/logo.svg") no-repeat center / contain;
}

/* Sprachumschalter (Schritt 9a): dezente Sprachkuerzel rechts in der Topbar.
   Der Warenkorb-Link davor ist oft hidden, deshalb schiebt der Switcher sich
   selbst per margin-left:auto nach rechts. */
.shinyvase-langswitch {
  margin-left: auto;
  display: flex;
  gap: 2px;
  flex: none;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* Der Langswitch soll beim Seitenwechsel nicht springen: auf der Galerie sitzt
   seine Mitte bei 34px (padding-top 16 + halbe Filterhoehe 18). Seiten OHNE
   Filterleiste (Detail, Warenkorb, Ueber uns) haben eine hoehere Topbar, weil
   das 74px-Logo dort im Fluss steht -- zentriert laege der Schalter bei 51px.
   align-self:flex-start + margin-top bringt ihn auf dieselben 34px:
   Topbar-padding-top ist dort 14px, 34 - 14 - 10.5 (halbe Schalterhoehe) = 9.5.
   Die Galerie ist ausgenommen, sie regelt es im :has(.vase-filters)-Block. */
/* Nur Desktop: unter 820px stapelt die Topbar (align-items:stretch, gap:12px),
   dort wuerde das margin-top zum Gap addieren und einen Versatz erzeugen. */
@media (min-width: 821px) {
  .shinyvase-topbar:not(:has(.vase-filters)) .shinyvase-langswitch {
    align-self: flex-start;
    margin-top: 9.5px;
  }
}

.shinyvase-langswitch__item {
  padding: 4px 7px;
  border-radius: 4px;
  color: var(--color-muted-foreground);
  text-decoration: none;
  line-height: 1;
}
.shinyvase-langswitch__item:hover {
  color: var(--color-foreground);
  background: var(--color-muted);
}
.shinyvase-langswitch__item--active {
  color: var(--color-foreground);
  font-weight: 600;
  cursor: default;
}

/* Der Header bleibt so lange wie moeglich einzeilig -- die Filter schrumpfen
   dynamisch (clamp-Gap + knappes Padding). Erst auf echter Tablet-/Handy-Breite,
   wo auch kompakt nichts mehr nebeneinander passt, bricht er in eine Spalte. */
@media (max-width: 820px) {
  .shinyvase-topbar {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 14px 24px 0;
    flex-wrap: wrap;
  }
  .shinyvase-topbar__logo { align-self: flex-start; }
  /* Filter-Umbruch: die eigentlichen Regeln stehen weiter unten in einem
     zweiten max-width:820px-Block NACH den Basis-Regeln von .vase-filters__inner
     -- sonst ueberschreibt die spaeter deklarierte Basis-Regel (nowrap,
     overflow-x:auto) diese hier bei gleicher Spezifitaet. */
  /* Im Spaltenmodus stapeln Warenkorb und Sprachschalter untereinander. Ohne
     eigene Ausrichtung klebte der Warenkorb links (align-items:stretch greift
     bei ihm nicht, er ist flex:none) -- der Sprachschalter steht rechts. Beide
     ans rechte Ende ziehen, damit sie als Block rechtsbuendig zusammenstehen. */
  .shinyvase-cart { align-self: flex-end; }
  .shinyvase-langswitch { align-self: flex-end; }
  /* Der Hochzug der Warenkorb-/Ueber-uns-Titel (-88px, Buendigkeit zum Logo)
     wird mobil zurueckgenommen -- die Regel steht weiter unten NACH der
     Basis-Regel .shinyvase-basket/.shinyvase-about, sonst ueberschriebe die
     spaeter deklarierte Basis (-88px) diesen Override und der Titel rutschte
     ueber das Logo. */
}

/* Filterleiste: eine horizontale Reihe, Hoehe = Hoehe eines Selects (36px).
   Kein --color-muted-Band, keine Labels ausserhalb — jedes Select traegt
   seinen Namen selbst als erste Option (= zugleich der Alle-Zustand). */
.vase-filters {
  flex: 1;
  min-width: 0;
}

.vase-filters__inner {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  /* Dynamischer Gap: schrumpft mit der Fensterbreite, damit die 7 Filter in
     einer Zeile bleiben (clamp = min 4px eng, ideal 1vw, max 20px weit). */
  gap: clamp(4px, 1vw, 20px);
  min-width: 0;
  /* Zweistufige Enge-Strategie: die Filter (Schrift/Hoehe/Padding) schrumpfen per
     clamp bis zum Minimum. Reicht das nicht (sehr schmales Fenster), scrollt die
     Leiste horizontal, statt Zaehler/Warenkorb zu ueberlappen -- beide bleiben
     immer sichtbar. Der Zaehler wird aus dem Scrollbereich genommen (siehe
     .vase-filters__count), damit er als fixer Anker rechts stehen bleibt. */
  overflow-x: auto;
  scrollbar-width: none;         /* Firefox: Scrollleiste ausblenden */
}
.vase-filters__inner::-webkit-scrollbar { display: none; }  /* WebKit: dito */

/* Der Filter-Wrapper gibt PLATZABHAENGIG nach: min-width:0 bricht das
   flex-Default (min-width:auto = nie unter Inhaltsbreite), flex:1 1 auto laesst
   ihn schrumpfen, sobald Warenkorb + Zaehler rechts Platz brauchen -- nicht erst
   wenn das Fenster schmaler wird. So verkleinern sich die Filter genau dann,
   wenn das Dia-/Warenkorb-Icon erscheint (siehe Zweistufen-Strategie oben). */
.vase-filter {
  min-width: 0;
  flex: 1 1 auto;
}

.vase-filter select {
  font-family: var(--font-body);
  /* Alles dynamisch, damit die 7 Filter neben Logo, Warenkorb und Sprachlinks
     in eine Zeile passen -- wird der Platz eng (z.B. wenn das Warenkorb-Icon
     erscheint), schrumpfen Schrift, Hoehe und Padding mit, statt zu
     ueberlappen. Bei viel Platz volle Groesse (14px / 36px). */
  font-size: clamp(11.5px, 0.85vw, 14px);
  color: var(--color-foreground);
  background: var(--color-card);
  border: 1px solid var(--color-border);
  border-radius: 0;
  padding: 0 clamp(16px, 1.4vw, 24px) 0 clamp(5px, 0.6vw, 8px);
  height: clamp(30px, 2.6vw, 36px);
  /* Fuellt den schrumpfenden Wrapper und gibt selbst nach; min-width als
     Untergrenze, damit der Name (= erste Option) nicht ganz verschwindet, der
     Rest wird per Ellipsis abgeschnitten statt zu ueberlaufen. */
  width: 100%;
  min-width: 4.5em;
  text-overflow: ellipsis;
  cursor: pointer;
  transition: border-color var(--transition-fast);
  /* Eigener Chevron statt System-Arrow: der System-Arrow bringt auf jeder
     Plattform eine andere Breite/Optik mit und sprengt die ruhige Reihe. */
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' fill='none' stroke='%236B7280' stroke-width='1.4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  /* Chevron-Abstand/-Groesse skalieren mit dem Padding mit, damit er im engen
     Zustand nicht in den Text laeuft. */
  background-position: right clamp(5px, 0.6vw, 9px) center;
  background-size: clamp(9px, 0.9vw, 12px);
}

.vase-filter select:hover {
  border-color: var(--color-accent);
}

/* Spaltenmodus: die Filterleiste bricht mehrzeilig um statt horizontal zu
   scrollen. STEHT HIER, nach den Basis-Regeln von .vase-filters__inner /
   .vase-filter select -- ein frueherer max-width:820px-Block (bei .shinyvase-
   topbar) wuerde bei gleicher Spezifitaet von den spaeteren Basis-Regeln
   ueberschrieben (nowrap, overflow-x:auto, min-width:4.5em blieben aktiv, die
   7 Filter liefen ueber den Rand). flex-basis ~44% -> 2 Filter pro Zeile;
   min-width zurueckgenommen, damit sie wirklich schmaler werden koennen. */
@media (max-width: 820px) {
  .vase-filters__inner {
    flex-wrap: wrap;
    overflow-x: visible;
  }
  .vase-filter {
    flex: 1 1 44%;
  }
  .vase-filter select {
    min-width: 0;
    font-size: 14px;
    height: 36px;
  }
}

/* Handy-Kopfzeile (Task 10). Zwei Aenderungen gegenueber dem 820er-Spaltenmodus:
   Sprachschalter und Warenkorb teilen sich EINE Zeile statt untereinander zu
   stapeln, und die Filter scrollen wieder horizontal statt als 2x3-Raster den
   halben Bildschirm zu fuellen. Die Reihenfolge im Markup ist Logo, Filter,
   Sprachschalter, Warenkorb -- ueber order ruecken die beiden Letzten neben das
   Logo, ohne dass das Markup sich aendert. Oberhalb von 480px bleibt alles wie
   es war. STEHT NACH dem 820er-Block, sonst gewinnt dieser bei gleicher
   Spezifitaet. */
@media (max-width: 480px) {
  .shinyvase-topbar {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 12px;
  }
  .shinyvase-topbar > a:has(.shinyvase-topbar__logo) {
    order: 1;
    margin-right: auto;
  }
  .shinyvase-langswitch {
    order: 2;
    align-self: center;
  }
  .shinyvase-cart {
    order: 3;
    align-self: center;
  }
  /* Volle Zeile unter Logo/Sprache/Warenkorb. */
  .vase-filters {
    order: 4;
    flex: 1 0 100%;
  }
  .vase-filters__inner {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-bottom: 4px;
    scrollbar-width: none;
  }
  .vase-filters__inner::-webkit-scrollbar {
    display: none;
  }
  .vase-filter {
    flex: 0 0 auto;
  }
}

/* Der Chevron ist ein Data-URI und kann kein currentColor erben — sobald es
   ein dunkles Theme gibt, braucht er hier seinen eigenen Stift. */
@media (prefers-color-scheme: dark) {
  .vase-filter select {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' fill='none' stroke='%23A1A1AA' stroke-width='1.4'/%3E%3C/svg%3E");
  }
}

/* Gesetzter Filter hebt sich ab — sonst sieht man einer Reihe grauer Selects
   nicht an, dass gefiltert wird. */
.vase-filter select.is-active {
  border-color: var(--color-primary);
  font-weight: 500;
}

.vase-filters__count {
  font-size: clamp(11px, 0.8vw, 13px);
  color: var(--color-muted-foreground);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex: none;
  /* Klebt am rechten Rand der (evtl. scrollenden) Filterleiste, damit die
     Anzahl immer sichtbar bleibt statt mit den Filtern wegzuscrollen. Der
     Hintergrund deckt durchscrollende Filter darunter ab -- #FEFEFE wie der
     Sticky-Header, nicht --color-background (#FAFAF9), sonst hebt sich der
     Zaehler mit einem leicht anderen Grau vom Header ab. */
  position: sticky;
  right: 0;
  padding-left: 10px;
  margin-left: auto;
  background: #FEFEFE;
}

/* Reset als Icon-Button in derselben Reihe. Erscheint nur, wenn ueberhaupt ein
   Filter gesetzt ist — ein toter Button in der Grundansicht ist Ballast. */
.vase-filters__reset {
  display: none;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: none;
  color: var(--color-muted-foreground);
  background: none;
  border: 1px solid transparent;
  padding: 0;
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

.vase-filters.has-active-filters .vase-filters__reset {
  display: inline-flex;
}

.vase-filters__reset:hover {
  color: var(--color-foreground);
  border-color: var(--color-border);
}

.vase-filters__reset svg {
  width: 14px;
  height: 14px;
}


/* Vasen-Grid — das Herz der Seite */
.vase-grid {
  max-width: 1280px;
  margin: 0 auto;
  /* Oben nur so viel Luft, dass die Filter atmen — die Vasen sind der Inhalt,
     sie sollen ohne Scrollen anfangen. Unten die volle Sektionshoehe. */
  padding: 20px 24px var(--space-section);
  display: grid;
  grid-template-columns: 1fr;
  gap: 17px 20px;
}

@media (min-width: 768px) {
  .vase-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .vase-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1440px) {
  .vase-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Die Karte ist eine geschlossene Flaeche: Bild UND Text sitzen auf demselben
   weissen Grund, der Seitenhintergrund trennt die Karten voneinander. Sonst
   schwimmt der Text frei und man muss raten, welcher Preis zu welchem Bild
   gehoert -- besonders bei engem Gap. */
.vase-card {
  display: block;
  cursor: pointer;
  color: inherit;
  text-decoration: none;
  background: var(--vase-karte);
  /* Versatz nach rechts/unten statt zentriert: die Karte liegt auf dem Grund,
     das Licht kommt von oben links. Die Deckung steckt in --karten-schatten,
     weil sie am Abstand zwischen Seiten- und Kartenton haengt: bei grauem
     Grund ist die Kante schon da und 0.12 reicht (mehr wirkt schmutzig statt
     edel); ruecken die Toene zusammen, muss der Schatten die Kante allein
     erzeugen -- auf gleichem Ton braucht es etwa 0.2. */
  box-shadow: 2px 2px 8px rgba(0, 0, 0, var(--karten-schatten));
  transition: box-shadow var(--transition-fast);
}

.vase-card:hover,
.vase-card:focus-visible {
  box-shadow: 3px 4px 14px rgba(0, 0, 0, 0.18);
}

/* Bild-Slot auf Weiss -- derselbe Grund, auf den vaseprep die Frames
   freistellt (freistellen.py BG). So geht das Foto nahtlos in den Slot ueber
   und die Karte liest sich als Bild + Textzone darunter. Aendert sich der eine
   Wert, muss der andere mit. Bis 2026-07-19 war beides #F4F4F1 -- vorher
   exportierte Vasen zeigen bis zu ihrem Neuexport eine leichte Kante. */
.vase-card__image-slot {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  background: var(--vase-bild);
  overflow: hidden;
}

.vase-card__image-slot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* 360-Grad-Rotation (Signature-Feature): Frame-Wechsel per src-Swap, nie
   width/height animiert. Mouse-Leave springt hart auf Frame 0 zurueck -- KEINE
   Opacity-Crossfade, sonst schiene der Slot-Hintergrund durch (grauer Aufblitz
   bei weissen Bildern). Die Interaktion (Hover-Drehung/Touch-Drag) bleibt aktiv. */

/* Textzone der Karte: gemeinsamer Innenabstand, damit die drei Zeilen als
   Block in der Flaeche sitzen statt an der Kante zu kleben. Der Hover-Effekt
   liegt jetzt auf der ganzen Karte (box-shadow), nicht mehr als Unterstrich
   am Namen -- der lief ueber die volle Kartenbreite und sah aus wie ein
   Trennstrich. */
.vase-card__name {
  font-family: var(--font-brand);
  font-style: italic;
  font-weight: 500;
  font-size: 21px;
  margin: 0 0 4px;
  padding: 14px 16px 0;
}

/* Bearbeiten-Stift neben dem Vasennamen (Karte und Detailseite), nur fuer
   Admins im Markup. Gedaempft wie .newsletter__insta, beim Hover dunkel. */
.vase-edit {
  /* Auf der Detailseite ein <button>: Browser-Standard zuruecksetzen. */
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  display: inline-flex;
  vertical-align: middle;
  margin-left: 8px;
  color: var(--color-muted-foreground);
  line-height: 0;
  cursor: pointer;
  transition: color var(--transition-fast);
}

.vase-edit:hover,
.vase-edit:focus-visible {
  color: var(--color-foreground);
}

.vase-edit svg {
  width: 16px;
  height: 16px;
}

.vase-detail__name .vase-edit svg {
  width: 22px;
  height: 22px;
}

.vase-card__meta {
  font-size: 13px;
  color: var(--color-muted-foreground);
  margin: 0 0 6px;
  padding: 0 16px;
}

/* Kein padding-bottom mehr: der Preis war frueher das letzte Element der Karte
   und trug deren unteren Abschluss. Seit der CTA darunter sitzt, waeren die
   16px Luft mitten in der Textzone -- den Abschluss traegt jetzt der CTA. */
.vase-card__price {
  font-family: var(--font-body);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  font-size: 15px;
  margin: 0;
  padding: 0 16px;
}

/* Karten-CTA: Vase direkt in den Korb, ohne Umweg ueber die Detailseite.
   <span role="button">, kein <button> -- die Karte selbst ist ein <a>, ein
   Button darin waere verschachtelte Interaktivitaet (siehe buildCardCta).

   Textlink statt Knopf, rechtsbuendig: ein umrandeter Knopf trug den
   kraeftigsten Ton der ganzen Karte (--color-ring, fast schwarz) und stach
   damit staerker hervor als Vasenname und Bild. Die Vasen sollen die
   Aufmerksamkeit tragen, nicht der Kaufknopf. Rechtsbuendig, weil der Preis
   links steht: die beiden teilen sich eine ruhige Zeile statt uebereinander
   zu stapeln.

   Der CTA traegt den unteren Kartenabschluss (der Preis hat dafuer sein
   padding-bottom abgegeben), sitzt aber dicht unter dem Preis: die beiden
   gehoeren als Zeile zusammen. */
.vase-card__cta {
  display: block;
  margin: 0 16px 14px;
  padding: 2px 0;
  border: 0;
  background: transparent;
  font-family: var(--font-body);
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--color-muted-foreground);
  text-align: right;
  /* Die Unterstreichung IST die Klickbarkeit -- ohne sie liest sich der Text
     wie eine Beschriftung. Sie faellt im Zustand "im Korb" weg und macht den
     Unterschied ohne Maus sichtbar (auf Touch gibt es keinen Hover). */
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: #D4D4D8;
  cursor: pointer;
  transition: color 120ms ease, text-decoration-color 120ms ease;
}

.vase-card__cta:hover {
  color: var(--color-foreground);
  text-decoration-color: var(--color-foreground);
}

.vase-card__cta:focus-visible {
  outline: 2px solid var(--color-ring);
  outline-offset: 2px;
}

/* Im Korb: sichtbar, aber nicht mehr anklickbar -- es sind Unikate. Kein
   display:none, der Zustand ist die Information. Ohne Unterstreichung und
   eine Stufe heller als der Kauf-CTA. */
.vase-card__cta--im-korb {
  text-decoration: none;
  color: var(--color-muted-foreground);
  cursor: default;
  pointer-events: none;
}

.vase-card__cta--fehler {
  text-decoration: none;
  color: var(--color-muted-foreground);
  cursor: default;
  pointer-events: none;
}

.vase-grid__empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--color-muted-foreground);
  padding: 48px 0;
}

/* Produkt-Detailseite. Oben bewusst weniger Luft als --space-section:
   der Inhalt soll naeher an die Topbar ruecken (User-Feinschliff 2026-07-28). */
.vase-detail {
  max-width: 1100px;
  margin: 0 auto;
  padding: 25px 24px var(--space-section);
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
}

@media (min-width: 768px) {
  .vase-detail {
    grid-template-columns: 1fr 1fr;
    gap: 64px;
    align-items: start;
  }
}

.vase-detail--not-found {
  display: block;
  text-align: center;
  padding: var(--space-section) 24px;
}

.vase-detail__image-slot {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  background: var(--color-card);
  overflow: hidden;
  /* Wie die Galerie-Karte + das Warenkorb-Thumb: das grosse Vasenbild liegt
     mit Schatten auf dem Grund (2px 2px 8px, Deckung aus --karten-schatten). */
  box-shadow: 2px 2px 8px rgba(0, 0, 0, var(--karten-schatten));
}

.vase-detail__image-slot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Detail-Galerie (Spec 2026-10-01-shinyvase-detail-fotos): Bild-Slot und
   Thumbnail-Leiste teilen sich die Grid-Zelle; Fotos liegen als eigene Ebene
   ueber Video/Canvas und werden ganz gezeigt (contain). */
.vase-detail__media {
  min-width: 0;
}

.vase-detail__image-slot .vase-detail__photo {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--color-card);
}

/* .vase-detail__image-slot img setzt display:block und schlaegt damit das
   hidden-Attribut -- die leere Foto-Ebene laege sonst weiss ueber der Vase. */
.vase-detail__image-slot .vase-detail__photo[hidden] {
  display: none;
}

.vase-detail__thumbs {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  overflow-x: auto;
  padding: 2px;
}

/* display:flex schlaegt [hidden]: ohne Fotos faellt die Leiste ganz weg. */
.vase-detail__thumbs[hidden] {
  display: none;
}

.vase-detail__thumb-huelle {
  position: relative;
  flex: 0 0 auto;
}

/* Nur fuer Admins: Fotos per Ziehen umsortieren (vase-admin.js). */
.vase-detail__thumb-huelle[draggable="true"] .vase-detail__thumb {
  cursor: grab;
}

.vase-detail__thumb-huelle.ist-gezogen {
  opacity: 0.4;
}

.vase-detail__thumb-huelle.ist-ziel .vase-detail__thumb {
  outline: 2px dashed var(--color-accent);
  outline-offset: 2px;
}

/* Nur fuer Admins (vase-admin.js): Bearbeiten/Loeschen an den Foto-Thumbnails. */
.vase-detail__thumb-aktion {
  position: absolute;
  top: 2px;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(24, 24, 27, 0.75);
  color: #FFFFFF;
  font-size: 12px;
  line-height: 20px;
  cursor: pointer;
}

.vase-detail__thumb-aktion--edit {
  left: 2px;
}

.vase-detail__thumb-aktion--x {
  right: 2px;
  font-size: 14px;
}

.vase-detail__thumb {
  position: relative;
  flex: 0 0 auto;
  width: 64px;
  aspect-ratio: 4 / 5;
  padding: 0;
  border: 1px solid var(--color-border);
  background: var(--color-card);
  cursor: pointer;
}

.vase-detail__thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.vase-detail__thumb[aria-current="true"] {
  outline: 2px solid var(--color-ring);
  outline-offset: 1px;
}

.vase-detail__thumb:focus-visible {
  outline: 2px solid var(--color-ring);
  outline-offset: 2px;
}

/* Dezent: mittleres Grau ohne Hintergrund (Wunsch Simon). */
.vase-detail__badge {
  position: absolute;
  right: 4px;
  bottom: 2px;
  font-size: 10px;
  line-height: 14px;
  color: var(--color-muted-foreground);
}

@media (max-width: 480px) {
  .vase-detail__thumb {
    width: 52px;
  }
}

/* Rotations-Video (ADR-005): Video und Standbild-Canvas liegen exakt ueber
   dem Vorschaubild, gleiche Einpassung. */
.vase-card__image-slot video,
.vase-card__image-slot canvas,
.vase-detail__image-slot video,
.vase-detail__image-slot canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

.vase-detail__name {
  font-family: var(--font-brand);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  line-height: 1.1;
  margin: 0 0 16px;
}

.vase-detail__teaser {
  color: var(--color-muted-foreground);
  margin: 0 0 20px;
}

.vase-detail__price {
  font-family: var(--font-body);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  font-size: 21px;
  margin: 0 0 28px;
}

.vase-detail__specs {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 16px;
  margin: 0 0 28px;
  font-size: 15px;
}

.vase-detail__specs dt {
  color: var(--color-muted-foreground);
}

.vase-detail__specs dd {
  margin: 0;
}

/* Reihe "Andere Exemplare von X" unter dem Teilen-Block: kleine quadratische
   Thumbs (wie die Warenkorb-Diashow), verlinkt auf die jeweilige Detailseite. */
.vase-detail__others {
  margin-top: 28px;
}

.vase-detail__others-title {
  margin: 0 0 10px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-foreground);
}

.vase-detail__others-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vase-detail__others-list a {
  display: block;
}

.vase-detail__others-list img {
  display: block;
  height: 72px;
  width: auto; /* Seitenverhältnis des Fotos bleibt erhalten, kein Beschnitt */
  /* Wie Galerie-Karte, Detailbild und Warenkorb-Thumb: Freistell-Grund
     (--vase-bild) + derselbe Schatten statt Rand/Rundung, damit auch die
     kleinen Varianten auf dem Grund liegen. */
  background: var(--vase-bild, #FEFEFE);
  box-shadow: 2px 2px 8px rgba(0, 0, 0, var(--karten-schatten));
  transition: box-shadow var(--transition-fast);
}

.vase-detail__others-list a:hover img,
.vase-detail__others-list a:focus-visible img {
  box-shadow: 3px 4px 14px rgba(0, 0, 0, 0.18);
}

.vase-detail__description {
  margin: 0 0 32px;
}

.vase-detail__cta {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 500;
  color: var(--color-on-primary);
  background: var(--color-primary);
  border: none;
  padding: 14px 28px;
  min-height: 44px;
  cursor: pointer;
  transition: background var(--transition-fast);
}

.vase-detail__cta:hover {
  background: var(--color-accent);
}

.vase-detail__cta:disabled {
  cursor: default;
  opacity: 0.7;
}

.vase-detail__feedback {
  margin: 12px 0 0;
  font-size: 14px;
  color: var(--color-muted-foreground);
}

.vase-detail__feedback--error {
  color: var(--color-destructive);
}

/* Ueber-uns / Impressum: schmale Lesespalte, ruhig gesetzt wie der Rest der
   Seite. Titel in der Markenschrift (kursiv, wie die Vasen-Namen), Fliesstext
   in Inter. Zwei Sektionen (Story oben, Impressum unten) mit Trennlinie. */
.shinyvase-about {
  /* 820px statt der 680px-Lesespalte der uebrigen Seiten: das Video im
     Story-Abschnitt ist Hochformat und braucht Breite, sonst bleiben daneben
     keine lesbaren Zeilen. Der Text selbst bleibt durch die Float-Breite
     begrenzt. */
  max-width: 820px;
  /* Negativer margin-top zieht den "Über uns"-Titel hoch bis seine Oberkante mit
     der Logo-Oberkante fluchtet (wie beim Warenkorb-Titel; Header 102px hoch,
     -88px setzt die Titel-Oberkante auf 14px). Der Titel steht rechts vom Logo,
     kein horizontaler Konflikt. Im Spaltenmodus (<=820px) zurueckgenommen. */
  margin: -88px auto 0;
  padding: 0 24px var(--space-section);
}
.shinyvase-about__section + .shinyvase-about__section {
  margin-top: 40px;
  padding-top: 40px;
  border-top: 1px solid var(--color-border);
}
.shinyvase-about__title {
  font-family: var(--font-brand);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  color: var(--color-foreground);
  margin: 0 0 16px;
}
.shinyvase-about__heading {
  font-family: var(--font-brand);
  font-style: italic;
  font-weight: 500;
  font-size: 1.5rem;
  color: var(--color-foreground);
  margin: 0 0 16px;
}
.shinyvase-about__lead {
  font-size: 1.125rem;
  color: var(--color-foreground);
}
/* Entwurfsvermerk auf AGB und Datenschutz: sichtbar, aber nicht laut. */
.shinyvase-about__hint {
  font-size: .8rem;
  font-style: italic;
  color: var(--color-muted-foreground);
}
.shinyvase-about p {
  font-family: var(--font-body);
  color: var(--color-muted-foreground);
  line-height: 1.7;
  margin: 0 0 14px;
}
/* Video laeuft stumm im Loop, steht zuoberst im Story-Abschnitt und wird vom
   Text umflossen (float rechts). 300px bei 680px Lesespalte laesst dem Text
   rund 355px -- schmaler wuerde der Flattersatz unruhig. height:auto bewahrt
   das Seitenverhaeltnis (848x480, Querformat).
   Das margin-top haelt die Oberkante auf Hoehe der ersten Textzeile statt am
   Titel zu kleben. */
.shinyvase-about__video {
  float: right;
  /* Die Datei ist 848x480 gespeichert, traegt aber rotation=-90: angezeigt
     wird HOCHFORMAT 480x848. 260px Breite ergeben 459px Hoehe; in der auf
     820px verbreiterten Spalte bleiben daneben rund 480px Text. */
  width: 260px;
  height: auto;
  max-width: 40%;
  /* Seitenverhaeltnis fest, damit der Platz schon vor dem Laden der
     Videometadaten stimmt und der Text nicht umspringt. */
  aspect-ratio: 480 / 848;
  margin: 6px 0 16px 28px;
}
/* Der Float darf nicht in den Impressum-Abschnitt hineinragen: die Story ist
   kuerzer als das Video, sobald das Fenster breit ist. clear raeumt ihn ab. */
.shinyvase-about__section::after {
  content: "";
  display: table;
  clear: both;
}

/* 1fr auto 1fr: das Copyright (Spalte 2) bleibt exakt im Seitenzentrum,
   der Newsletter zentriert sich im rechten Drittel daneben. */
.shinyvase-footer {
  border-top: 1px solid var(--color-border);
  padding: 20px 24px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  text-align: center;
  font-size: 13px;
  color: var(--color-muted-foreground);
}
.shinyvase-footer > p {
  grid-column: 2;
  margin: 0;
}
.shinyvase-footer .newsletter {
  grid-column: 3;
  justify-self: center;
}
/* Die Rechtslinks stehen im linken Drittel, gegenueber dem Newsletter. Sie
   brechen bei Bedarf um, statt die Spalte breiter zu machen. */
.shinyvase-footer__nav {
  grid-column: 1;
  justify-self: center;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 14px;
}
@media (max-width: 820px) {
  .shinyvase-footer {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
}

/* Das Copyright im Footer ist zugleich der Link zur Ueber-uns-Seite. Dezent:
   erbt die Footer-Farbe, hebt sich erst beim Hover ab. */
.shinyvase-footer a {
  color: inherit;
  text-decoration: none;
}
.shinyvase-footer a:hover {
  color: var(--color-foreground);
  text-decoration: underline;
}

/* Newsletter-Anmeldung im Footer: sitzt als kompakter Block neben dem
   Copyright (Flex-Zeile im Footer), Titel linksbuendig ueber dem Feld.
   Honeypot (.newsletter__hp) wird aus dem Viewport geschoben statt
   display:none, damit Bots ihn weiterhin sehen. */
.newsletter {
  max-width: 420px;
  min-width: 0;
  text-align: left;
}
.newsletter__title {
  margin: 0 0 5px;
  font-size: 13px;
  color: var(--color-foreground);
}
.newsletter__form {
  display: flex;
  gap: 8px;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
}
.newsletter__form input[type="email"] {
  flex: 1 1 180px;
  padding: 6px 10px;
  font: inherit;
  font-size: 12px;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-card);
  color: var(--color-foreground);
}
.newsletter__form button {
  padding: 4px 10px;
  font: inherit;
  font-size: 12px;
  border: none;
  border-radius: 4px;
  background: var(--color-primary);
  color: var(--color-on-primary);
  cursor: pointer;
}
.newsletter__form button:hover {
  background: var(--color-accent);
}
/* Instagram-Logo als dritter Flex-Posten neben dem Abonnieren-Button:
   gleiche Zeile, gleiche Hoehe, gleiche gedaempfte Farbe wie die Footer-Links. */
.newsletter__insta {
  display: inline-flex;
  align-items: center;
  align-self: center;
  margin-left: 2px;
  color: var(--color-muted-foreground);
  line-height: 0;
}
.shinyvase-footer a.newsletter__insta:hover {
  color: var(--color-foreground);
  text-decoration: none;
}
.newsletter__hp {
  position: absolute;
  left: -5000px;
}
/* Antwort des Anmelde-Endpoints. Steht per hidden-Attribut im Markup und wird
   vom Skript im Footer eingeblendet. */
.newsletter__response {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.4;
  color: var(--color-muted-foreground);
}
.newsletter__response.is-error {
  color: var(--color-destructive);
}


/* ---- Warenkorb ---- */
/* Negativer margin-top zieht den Warenkorb-Titel hoch, sodass seine Oberkante
   mit der Logo-Oberkante fluchtet (Header ist 102px hoch: Logo 74px + 2x14px
   Padding; -88px setzt den Titel auf die Logo-Oberkante bei 14px). Der Titel
   steht horizontal weit rechts vom Logo, kollidiert also nicht. Im Spaltenmodus
   (<=820px) ist die Topbar niedriger -> dort zuruecknehmen. */
.shinyvase-basket { max-width: 640px; margin: -88px auto 0; padding: 0 1rem 2rem; }
/* Gleiche Schrift wie .shinyvase-about__title: alle Seitentitel der Site
   sehen gleich aus (kursive Brand-Serif), nicht nur der Ueber-uns-Titel. */
.shinyvase-basket__title {
  font-family: var(--font-brand);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  color: var(--color-foreground);
  margin-top: 0;
  margin-bottom: 1.5rem;
}
/* Mobil (Spaltenmodus) steht das Logo in einer eigenen Header-Zeile ganz oben.
   Der -88px-Hochzug (auf Desktop Buendigkeit zum Logo) wuerde den Titel unter
   das Logo ziehen -- mobil muss der Inhalt UNTERHALB des Logos beginnen. Darum
   den Hochzug hier zuruecknehmen. STEHT NACH den Basis-Regeln, sonst wirkungslos
   (gleiche Spezifitaet, spaetere Regel gewinnt). */
/* Der Hochzug des Titels (margin-top:-88px) setzt voraus, dass die Lesespalte
   RECHTS neben dem Logo beginnt. Seit die Ueber-uns-Spalte 820px breit ist,
   rutscht sie schon unter 1200px Fensterbreite unter das Logo -- Titel und
   Siegel ueberlagern sich dann unleserlich. Darum hier zuruecknehmen, nicht
   erst bei 820px. Gemessen: Logo endet bei 151px, Kollision ab Spaltenlinks
   unter 167px. */
@media (max-width: 1200px) {
  .shinyvase-about { margin-top: 1.5rem; }
}

@media (max-width: 820px) {
  .shinyvase-basket { margin-top: 1.5rem; }
  .shinyvase-about { margin-top: 1.5rem; }
  /* Umfliessen aufheben: neben einem 300px-Video bliebe auf dem Handy keine
     lesbare Textbreite. Video wird volle Spaltenbreite, Text laeuft darunter. */
  /* Hochformat-Video auf dem Handy nicht auf volle Spaltenbreite ziehen --
     es wuerde fast zwei Bildschirmhoehen fuellen. Hoehe deckeln, zentriert. */
  .shinyvase-about__video {
    float: none;
    height: 60vh;
    max-height: 420px;
    width: auto;
    max-width: 100%;
    margin: 0 auto 20px;
  }
}
.shinyvase-basket__list { list-style: none; margin: 0; padding: 0; }
.shinyvase-basket__item { display: flex; gap: 1rem; padding: 1rem 0; border-bottom: 1px solid var(--color-muted, #F4F4F1); }
.shinyvase-basket__thumb {
  width: 88px;
  aspect-ratio: 4/5;
  object-fit: cover;
  /* Wie die Galerie-Karte: Freistell-Grund (--vase-bild) + derselbe Schatten
     (2px 2px 8px, Deckung aus --karten-schatten), damit das Vasenbild auch im
     Warenkorb auf dem Grund zu liegen scheint statt flach anzukleben. */
  background: var(--vase-bild, #FEFEFE);
  box-shadow: 2px 2px 8px rgba(0, 0, 0, var(--karten-schatten));
}
/* Das Thumbnail verlinkt auf die Detailseite -- der Link umschliesst nur das
   Bild, also den Schatten aufs Bild lassen und den Link selbst als Block
   fuehren. Beim Hover ein kraeftigerer Schatten wie bei den Galerie-Karten. */
.shinyvase-basket__thumb-link {
  display: block;
  flex: none;
  line-height: 0;
  transition: box-shadow var(--transition-fast);
}
.shinyvase-basket__thumb-link:hover .shinyvase-basket__thumb,
.shinyvase-basket__thumb-link:focus-visible .shinyvase-basket__thumb {
  box-shadow: 3px 4px 14px rgba(0, 0, 0, 0.18);
}
.shinyvase-basket__info { display: flex; flex-direction: column; gap: .35rem; }
.shinyvase-basket__timer { font-size: .85rem; opacity: .7; }
.shinyvase-basket__remove, .shinyvase-basket__reclaim {
  align-self: flex-start; background: none; border: 1px solid currentColor;
  padding: .3rem .8rem; cursor: pointer; font: inherit; }
.shinyvase-basket__removed-item { display: flex; align-items: center; gap: .75rem; padding: .6rem 0; opacity: .8; }
.shinyvase-basket__total { margin-top: 1.5rem; font-size: 1.1rem; }
.shinyvase-basket__checkout { display: inline-block; margin-top: 1rem; }

/* ---- Topbar-Warenkorb-Diashow ---- */
.shinyvase-cart {
  /* KEIN margin-left:auto -- den rechts-Schub traegt der Langswitch. Der Cart
     steht im DOM HINTER dem Langswitch (in allen Templates), also schiebt das
     margin-left:auto des Langswitch beide als Gruppe nach rechts; der Cart klebt
     rechts daneben. Ist der Cart hidden (display:none), bleibt der Langswitch
     trotzdem rechts. Auf der Galerie fuellt die Filterleiste (flex:1) die Mitte,
     der Effekt ist dort ohnehin gleich. */
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 44px;
  height: 55px;                 /* 4:5, passend zum Vasenformat */
  flex: none;
  margin-left: clamp(8px, 1vw, 16px);
}
.shinyvase-cart[hidden] { display: none; }
.shinyvase-cart__stage {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--color-muted, #F4F4F1);
}
.shinyvase-cart__stage img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.shinyvase-cart__stage img.is-active { opacity: 1; }
/* Die Diashow im Topbar-Korb laeuft von selbst. Wer reduzierte Bewegung
   eingestellt hat, bekommt keinen Ueberblendeffekt -- shinyvase-cart.js
   startet das Intervall dann ohnehin nicht, das hier faengt den Fall ab,
   dass beim Rendern noch ein Wechsel in der Warteschlange steht. */
@media (prefers-reduced-motion: reduce) {
  .shinyvase-cart__stage img { transition: none; }
}
.shinyvase-cart__badge {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 9px;
  background: rgba(24, 24, 27, 0.85);
  color: var(--color-on-primary, #fff);
  font-family: var(--font-body);
  font-size: 11px;
  line-height: 18px;
  text-align: center;
}
/* --- Checkout-Formular auf der Warenkorbseite --- */
.shinyvase-checkout { margin-top: 2.5rem; max-width: 34rem; }
.shinyvase-checkout__title { font-size: 1.1rem; margin-bottom: 1rem; }
.shinyvase-checkout__form label { display: block; margin-bottom: .6rem; font-size: .9rem; }
.shinyvase-checkout__form input { display: block; width: 100%; padding: .5rem;
  border: 1px solid var(--color-border); border-radius: 2px; font-size: 1rem; }
.shinyvase-checkout__row { display: flex; gap: .8rem; }
.shinyvase-checkout__row label { flex: 1; }
.shinyvase-checkout__billing { margin: .8rem 0; font-size: .9rem; }
.shinyvase-checkout__billing summary { cursor: pointer; padding: .3rem 0; }
.shinyvase-checkout__summary { margin: 1.2rem 0; }
.shinyvase-checkout__line { display: flex; justify-content: space-between; padding: .3rem 0; }
.shinyvase-checkout__line--total { font-weight: 600; border-top: 1px solid var(--color-border); margin-top: .3rem; }
.shinyvase-checkout__pay { width: 100%; padding: .8rem; font-size: 1rem; cursor: pointer;
  background: var(--color-primary); color: var(--color-on-primary); border: 0; border-radius: 2px; }
/* Die MwSt-Zeile ist kein Betrag, sondern eine Fussnote zum Total. */
.shinyvase-checkout__line--vat { font-size: .8rem; color: var(--color-muted-foreground); padding-top: 0; }
.shinyvase-checkout__hint { font-size: .8rem; color: var(--color-muted-foreground); margin-top: .6rem; text-align: center; }
.shinyvase-checkout__terms { font-size: .8rem; color: var(--color-muted-foreground); margin-top: .4rem; text-align: center; }
.shinyvase-checkout__terms a { text-decoration: underline; }
.shinyvase-checkout__error { color: #B00020; font-size: .85rem; margin-top: .2rem; }

/* Gleiches Raster wie .shinyvase-topbar (1280px, 24px seitliches Padding),
   damit Titel und Text buendig mit dem Logo starten -- sonst wirkt der Block
   auf breiten Fenstern verrutscht. */
.shinyvase-order-done { max-width: 1280px; margin: 0 auto; padding: 3rem 24px; }
/* Siehe .shinyvase-basket__title: dieselbe Titelschrift wie Ueber uns. */
.shinyvase-order-done__title {
  font-family: var(--font-brand);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  color: var(--color-foreground);
  margin-bottom: 1.5rem;
}
.shinyvase-order-done__text { font-size: 1.05rem; line-height: 1.6; margin-bottom: 2rem; }
.shinyvase-order-done__back a { color: var(--color-primary); text-decoration: none; }
.shinyvase-order-done__back a:hover { text-decoration: underline; }

/* Warn-Dialog: abgelaufene Vase(n) beim Checkout (JS shinyvase-basket.js) */
.shinyvase-dialog__overlay {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(0,0,0,0.45);
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
}
.shinyvase-dialog {
  background: var(--color-card);
  color: var(--color-foreground);
  border-radius: 10px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.25);
  max-width: 420px; width: 100%;
  padding: 1.5rem;
}
.shinyvase-dialog__msg { font-size: 1rem; line-height: 1.5; margin: 0 0 0.75rem; }
.shinyvase-dialog__list {
  font-weight: 600; margin: 0 0 1.25rem;
  color: var(--color-muted-foreground);
}
.shinyvase-dialog__actions {
  display: flex; gap: 0.75rem; flex-wrap: wrap; justify-content: flex-end;
}
.shinyvase-dialog__back,
.shinyvase-dialog__accept {
  border: none; border-radius: 6px; padding: 0.6rem 1.1rem;
  font-size: 0.95rem; cursor: pointer;
}
.shinyvase-dialog__back {
  background: var(--color-muted); color: var(--color-foreground);
  border: 1px solid var(--color-border);
}
.shinyvase-dialog__accept {
  background: var(--color-primary); color: var(--color-on-primary);
}
.shinyvase-dialog__back:hover { background: var(--color-border); }
.shinyvase-dialog__accept:hover { opacity: 0.9; }

/* ---- Versandart im Checkout ----
   Radio-Gruppe ueber den Adressfeldern: die Kostenfolge soll sichtbar sein,
   bevor der Kunde die Adresse eintippt. Rahmenlos wie der uebrige Checkout. */
.shinyvase-checkout__versandart {
  border: 1px solid var(--color-border);
  padding: 14px 16px 12px;
  margin: 0 0 1.25rem;
}

.shinyvase-checkout__versandart legend {
  padding: 0 6px;
  font-size: 14px;
  color: var(--color-muted-foreground);
}

/* Spezifitaet ueber .shinyvase-checkout__form label/input weiter unten:
   dort gilt label{display:block} und input{display:block;width:100%}, was das
   Radio als Blockelement ueber die volle Breite und damit mittig UEBER den Text
   setzt statt links daneben. Darum hier mit __form davor. */
.shinyvase-checkout__form .shinyvase-checkout__radio {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
  margin-bottom: 0;
  cursor: pointer;
}

.shinyvase-checkout__form .shinyvase-checkout__radio input[type="radio"] {
  display: inline-block;
  width: auto;
  flex: none;
  margin: 0;
  padding: 0;
  accent-color: var(--color-primary);
}

.shinyvase-checkout__pickup-note {
  margin: 8px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-muted-foreground);
}

.shinyvase-checkout__pickup-note[hidden] { display: none; }

/* ---- Teilen ----
   Dezent unter dem CTA: der primaere Handlungsaufruf bleibt "In den Warenkorb",
   Teilen ist ein Angebot. Darum textlicher Knopf ohne Flaeche, keine bunten
   Netzwerk-Buttons (die waeren im Museum-Look ein Fremdkoerper). */
.shinyvase-share {
  position: relative;
  margin-top: 1rem;
}

.shinyvase-share__button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 2px;
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--color-muted-foreground);
  cursor: pointer;
  transition: color var(--transition-fast);
}

.shinyvase-share__button:hover {
  color: var(--color-foreground);
}

/* Das SVG richtet sich an der Textbox aus, nicht an der optischen Mitte der
   Glyphen: ein halbes Pixel nach unten sitzt sauberer auf der x-Hoehe. */
.shinyvase-share__icon {
  flex-shrink: 0;
  transform: translateY(0.5px);
}

/* Menue nur auf dem Desktop sichtbar (auf dem Handy uebernimmt das native
   Share-Sheet). position:absolute, damit es die Seite nicht verschiebt.
   Es klappt nach OBEN auf (bottom statt top): der Teilen-Knopf ist das letzte
   Element der Info-Spalte, nach unten waere das Menue am Viewport-Rand
   abgeschnitten. Ueber dem Knopf liegt die Beschreibung, dort ist immer Platz.
   Schatten entsprechend nach oben gerichtet. */
.shinyvase-share__menu {
  position: absolute;
  z-index: 10;
  bottom: calc(100% + 4px);
  left: 0;
  min-width: 170px;
  display: flex;
  flex-direction: column;
  padding: 6px 0;
  background: var(--color-card);
  border: 1px solid var(--color-border);
  box-shadow: 2px -4px 14px rgba(0, 0, 0, 0.12);
}

.shinyvase-share__menu[hidden] { display: none; }

.shinyvase-share__menu a,
.shinyvase-share__menu button {
  padding: 8px 16px;
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-size: 14px;
  text-align: left;
  color: var(--color-foreground);
  text-decoration: none;
  cursor: pointer;
}

.shinyvase-share__menu a:hover,
.shinyvase-share__menu button:hover {
  background: var(--color-muted);
}

/* Inline-Bearbeitung auf der Detailseite: das Formular aus der Admin-Seite
   (Styles in admin/vase-form.css) ersetzt den Info-Bereich. Ausblenden per
   Regel statt hidden-Attribut: Specs (grid) und Warenkorb-Knopf haben ein
   eigenes display, das hidden ueberstimmen wuerde. */
.vase-detail__info[data-editing="1"] > :not(.vase-inline-edit) {
  display: none !important;
}

.vase-inline-edit .vase-form {
  margin-top: 0;
}
