/* ==========================================================================
   cart-button.css — animierter "In den Warenkorb"-Button
   --------------------------------------------------------------------------
   Die ganze Choreo hängt an EINER Größe: --sw-h (Buttonhöhe). Der Puck ist
   genau --sw-h breit und fährt von links (0) nach rechts (100% - --sw-h).
   Drei clip-paths sind an dieselbe Strecke gekoppelt:

     Grün      linke Kante  = Puck linke Kante   → wird am Ende zum Kreis
     Text alt  linke Kante  = Puck rechte Kante  → wird vom Wagen gefressen
     Text neu  rechte Kante = Puck linke Kante   → wird dahinter freigelegt

   Gleiche Dauer + gleiche Kurve = die Kanten sitzen in jedem Frame exakt auf
   dem Puck, egal wie du --sw-dur oder das Easing änderst. Kein JS-Messen.
   ========================================================================== */

.btn-swallow {
  /* --- Stellschrauben --- */
  --sw-h:        4.25rem;                          /* Höhe = Durchmesser der Bubble */
  --sw-pad:      1.5rem;                           /* Innenabstand auf der Textseite */
  --sw-ok:       #89c106;
  --sw-ok-2:     #89c106;
  --sw-ok-rgb:   137, 193, 6;                      /* dasselbe Grün für den Halo */
  --sw-ok-ink:   #5c8104;                          /* dunkler, für Text auf Weiß */
  --sw-rest:     #e4e7ea;                          /* liegt unter dem Grün */
  --sw-rest-fg:  #1f2937;
  --sw-err:      #dc2626;
  --sw-label:    1.2rem;                           /* Schriftgröße der beiden Texte */
  --sw-cart-home: .5rem;                           /* Ruheposition des Wagens, rechts der Puckmitte */
  --sw-cart-x:   var(--sw-cart-home);              /* aktueller Versatz, Hover und Fahrt ändern ihn */
  --sw-dur:      620ms;                            /* muss zu CFG.travel im JS passen */
  --sw-ease:     cubic-bezier(.84, -0.14, .3, 1);  /* holt vor dem Start leicht aus */
  --sw-pop:      cubic-bezier(.84, 1.56, .64, 1);

  position: relative;
  display: inline-flex;
  align-items: center;
  height: var(--sw-h);
  padding: 0 var(--sw-pad) 0 var(--sw-h);
  border: 0;
  border-radius: 999px;
  background: var(--sw-rest);
  color: #fff;
  font: 500 1rem/1 inherit;
  font-family: var(--font-display);
  letter-spacing: .01em;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s var(--sw-ease);
  
  width: 100%;
  max-width: 90vw;
    
}

.btn-swallow:active { transform: scale(.98); }
.btn-swallow:focus-visible { outline: 2px solid var(--sw-ok-ink); outline-offset: 3px; }

/* Breite: unsichtbarer Platzhalter mit beiden Texten übereinander.
   Beide Zustände haben denselben Gesamt-Innenabstand (--sw-h + --sw-pad),
   deshalb reicht eine Breite für beide. */
.btn-swallow__size {
  display: grid;
  visibility: hidden;
  font-size: var(--sw-label);
  /* Bei fester Buttonbreite darf der Platzhalter nichts aufschieben:
     ohne min-width kann ein Flex-Kind nicht unter seine Textbreite
     schrumpfen und würde über den Button hinausragen. */
  min-width: 0;
  overflow: hidden;
}
.btn-swallow__size > i { grid-area: 1 / 1; white-space: nowrap; font-style: normal; }

/* --- Der grüne Layer ----------------------------------------------------- */
.btn-swallow__fill {
  position: absolute;
  /* Bewusst die Langform statt inset: 0. left ist die animierte
     Eigenschaft, und eine Transition von auto auf eine Länge läuft nicht.
     Ausgeschrieben steht dort garantiert eine 0 als Startwert. */
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 0;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--sw-ok-2), var(--sw-ok));
  transition: left var(--sw-dur) var(--sw-ease), background-color .25s;
}
.btn-swallow:hover .btn-swallow__fill { filter: brightness(1.07); }
.btn-swallow.is-run:hover .btn-swallow__fill { filter: none; }
/* Nur die linke Kante wandert. Weil inset: 0 auch right: 0 gesetzt hat,
   bleibt die rechte Kante von allein stehen und die Breite ergibt sich —
   eine einzige animierte Eigenschaft statt einer Form.

   Vorher lief das über clip-path: inset(… round 999px). Das ist die einzige
   Stelle im ganzen CSS mit einem Radius in der Form, und genau die sprang.
   Formen mit Border-Radius interpolieren nicht überall zuverlässig; scheitert
   es, schaltet der Browser den Wert diskret um — Sprung zur Hälfte der Dauer
   statt Bewegung. left ist eine schlichte Länge und animiert überall, so wie
   der Puck darüber, der ja auch bei dir sauber fährt. */
.btn-swallow.is-run .btn-swallow__fill { left: calc(100% - var(--sw-h)); }

/* --- Die zwei Textebenen ------------------------------------------------- */
.btn-swallow__lyr {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  white-space: nowrap;
  border-radius: inherit;
  overflow: hidden;                                /* längere Fehlertexte bluten nicht raus */
  transition: clip-path var(--sw-dur) var(--sw-ease), transform var(--sw-dur) var(--sw-ease);
  justify-content: center;
  font-size: var(--sw-label);
}
.btn-swallow__lyr--idle {
  clip-path: inset(0 0 0 var(--sw-h));     
 
    padding-bottom: 3px;        /* Startkante = rechte Puckkante */
}
.btn-swallow__lyr--done {
  padding: 0 var(--sw-h) 0 var(--sw-pad);
  color: var(--sw-rest-fg);
  clip-path: inset(0 100% 0 0);                    /* komplett zugedeckt */
}
.btn-swallow.is-run .btn-swallow__lyr--idle {
  clip-path: inset(0 0 0 100%);
  transform: translateX(-12px);                    /* wird leicht eingesogen */
}
.btn-swallow.is-run .btn-swallow__lyr--done { clip-path: inset(0 var(--sw-h) 0 0); }

/* --- Der Puck: fährt die Strecke, trägt die Icons ------------------------ */
.btn-swallow__puck {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  width: var(--sw-h);
  height: var(--sw-h);
  display: grid;
  place-items: center;
  border-radius: 999px;
  transition: left var(--sw-dur) var(--sw-ease);
}
.btn-swallow.is-run .btn-swallow__puck { left: calc(100% - var(--sw-h)); }
.btn-swallow.is-done .btn-swallow__puck { animation: sw-land .55s var(--sw-pop); }

@keyframes sw-land {
  0%   { transform: scale(1);    box-shadow: 0 0 0 0    rgba(var(--sw-ok-rgb), .55); }
  40%  { transform: scale(1.14); }
  100% { transform: scale(1);    box-shadow: 0 0 0 16px rgba(var(--sw-ok-rgb), 0); }
}

/* --- Icons im Puck ------------------------------------------------------- */
.btn-swallow__puck > svg {
  	grid-area: 1 / 1;
	width: 2.5em;
	height: 2.5em;
	overflow: visible;
	transition: opacity .2s var(--sw-ease),
	            transform .35s var(--sw-pop),
	            translate .35s var(--sw-pop);
}

/* Der Wagen sitzt nicht mittig im Puck, sondern etwas rechts davon.
   Das war vorher margin-left: 1rem — jetzt translate, aus zwei Gründen:
   margin ist Layout und lässt sich nicht sauber wegtransitionieren, und
   der Hover-Anlauf unten braucht ohnehin dieselbe Achse.

   Zur Umrechnung: 1rem margin ergab 8px sichtbaren Versatz, nicht 16.
   Beim Zentrieren rechnet der Grid die Marge mit, verschoben wird also
   nur um die Hälfte. .5rem translate sieht deshalb genauso aus wie
   1rem margin vorher. */
.btn-swallow__cart {
  fill: currentColor;
  /* Bewusst translate und nicht transform: die Zustände weiter unten
     benutzen transform für Drehung und Skalierung. Getrennte Eigenschaften
     überschreiben sich nicht gegenseitig, beide animieren zusammen. */
  translate: var(--sw-cart-x) 0;
}

/* Anlauf beim Überfahren: der Wagen rückt ein Stück vor und legt sich
   leicht zurück, als würde er gleich losfahren. Nur im Ruhezustand —
   während der Fahrt und danach hat der Wagen anderes zu tun. */
.btn-swallow:not(.is-run):not(.is-done):not(.is-final):hover .btn-swallow__cart {
  --sw-cart-x: calc(var(--sw-cart-home) + 7px);
  transform: rotate(-7deg);
}
/* Die Räder laufen einen Tick weiter als der Korb — das ist der
   Unterschied zwischen Anfahren und Verschieben. */
.btn-swallow:not(.is-run):not(.is-done):not(.is-final):hover .btn-swallow__cart-wheels {
  transform: translateX(1.4px);
  transition: transform .35s var(--sw-pop);
}

/* Sobald es losgeht, zieht sich der Wagen in die Puckmitte zurück. Sonst
   ragt er am rechten Ende der Strecke über den Rand der Bubble hinaus —
   bei 2.5em Icon und 1rem Versatz genau 2px, und die sieht man, weil
   dort nichts mehr clippt. */
.btn-swallow.is-run     .btn-swallow__cart,
.btn-swallow.is-waiting .btn-swallow__cart,
.btn-swallow.is-done    .btn-swallow__cart { --sw-cart-x: 0; }
.btn-swallow__spin,
.btn-swallow__check {
  fill: none;
  stroke: currentColor;
  stroke-width: 3.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
}
.btn-swallow__spin circle { stroke-dasharray: 55 28; }

.btn-swallow.is-run     .btn-swallow__cart  { transform: rotate(-6deg); }
.btn-swallow.is-waiting .btn-swallow__cart  { opacity: 0; transform: scale(.5); }
.btn-swallow.is-waiting .btn-swallow__spin  { opacity: 1; animation: sw-spin .75s linear infinite; }
.btn-swallow.is-done    .btn-swallow__cart  { opacity: 0; transform: scale(.4) rotate(-20deg); }
.btn-swallow.is-done    .btn-swallow__spin  { opacity: 0; }
.btn-swallow.is-done    .btn-swallow__check { opacity: 1; }

/* Haken wird gezeichnet — pathLength="1" macht das unabhängig von der Pfadlänge */
.btn-swallow__tick {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset .3s var(--sw-ease);
}
.btn-swallow.is-done .btn-swallow__tick { stroke-dashoffset: 0; transition-delay: .08s; }

@keyframes sw-spin { to { transform: rotate(360deg); } }

/* --- Schon im Warenkorb: derselbe Endzustand, aber ohne Einflug ---------
   Der fertige Zustand steht schon im HTML, deshalb läuft beim Seitenaufbau
   keine Transition. is-static hält zusätzlich die Lande-Animation an, sonst
   würde bei jedem Seitenaufbau jede Kachel einmal aufploppen. */
.btn-swallow.is-static .btn-swallow__puck { animation: none; }
.btn-swallow.is-final  { cursor: default; }

a.btn-swallow { text-decoration: none; cursor: pointer; }
a.btn-swallow:hover .btn-swallow__fill { filter: brightness(1.07); }

/* Für einen Frame alle Übergänge aus. Wird gesetzt, wenn jemand im
   loop-Modus nochmal klickt, während der Haken noch steht: der Button
   springt hart auf Anfang, statt den Wagen sichtbar rückwärts fliegen zu
   lassen, und die Animation kann sauber neu starten. */
.btn-swallow.is-instant,
.btn-swallow.is-instant *,
.btn-swallow.is-instant .btn-swallow__fill {
  transition: none !important;
  animation: none !important;
}

/* --- Stückzahl am Icon --------------------------------------------------- */
.btn-swallow__badge {
      position: absolute;
    top: 0.85em;
    right: 0.01em;
    min-width: 1.35em;
    height: 1.35em;
    padding: 0 .3em;
    display: grid;
    place-items: center;
    border-radius: 999px;
    background: #fff;
    color: var(--sw-ok-ink);
    font-size: 0.82em;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 1px 3px rgb(0 0 0 / .25);
    transition: transform .3s var(--sw-pop);
}
/* Leer = nichts im Korb. Das JS setzt einfach den Text, den Rest macht CSS. */
.btn-swallow__badge:empty { display: none; }
.btn-swallow__badge.is-bumped { animation: sw-badge .45s var(--sw-pop); }

@keyframes sw-badge {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.45); }
  100% { transform: scale(1); }
}

/* --- Fehlerfall ---------------------------------------------------------- */
.btn-swallow.is-err { animation: sw-shake .4s var(--sw-ease); }
.btn-swallow.is-err .btn-swallow__fill { background: var(--sw-err); }
@keyframes sw-shake {
  20%  { transform: translateX(-5px); }
  45%  { transform: translateX(4px); }
  70%  { transform: translateX(-3px); }
  100% { transform: none; }
}

/* --- Farbvarianten ------------------------------------------------------- */
.btn-swallow--ink   { --sw-rest: #14161a; --sw-rest-fg: #f3f4f6; }
.btn-swallow--paper { --sw-rest: #fff;    --sw-rest-fg: #14161a; box-shadow: inset 0 0 0 1px rgba(20,22,26,.14); }

/* --- Größen (statt inline style) ----------------------------------------- */
.btn-swallow--sm { --sw-h: 2.75rem; --sw-pad: 1.15rem; font-size: .9rem; }
.btn-swallow--lg { --sw-h: 3.75rem; --sw-pad: 1.75rem; font-size: 1.15rem; }

/* Über die volle Spaltenbreite, z.B. in der Produktkachel.
   Der Platzhalter muss dann mitwachsen, sonst sitzt der Text links. */
.btn-swallow--block { display: flex; width: 100%; justify-content: flex-start; }
.btn-swallow--block .btn-swallow__size { flex: 1; }

/* --- Mengenwähler --------------------------------------------------------
   Steht im selben Formular wie der Button. Die Höhen sind bewusst eigene
   Variablen und nicht --sw-h: der Wähler ist ein Nachbar des Buttons, kein
   Teil von ihm, und --sw-h steuert im Button die halbe Choreografie mit. */
.cart-form--qty {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
}

.qty {
  --qty-h: 3.25rem;
  display: inline-flex;
  align-items: center;
  height: var(--qty-h);
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px rgba(20,22,26,.18);
  overflow: hidden;
  flex: none;
  font-family: var(--font-display);
}
.qty--sm { --qty-h: 2.75rem; font-size: .9rem; }
.qty--lg { --qty-h: 3.75rem; font-size: 1.15rem; }

.qty__btn {
  width: 2.6em;
  height: 100%;
  border: 0;
  background: transparent;
  color: inherit;
  font: 400 1.25em/1 inherit;
  font-family: inherit;
  cursor: pointer;
  transition: background .2s;
  -webkit-tap-highlight-color: transparent;
}
.qty__btn:hover { background: rgba(20,22,26,.07); }
.qty__btn:disabled { opacity: .3; cursor: default; background: transparent; }
.qty__btn:focus-visible { outline: 2px solid var(--sw-ok-ink); outline-offset: -2px; }

.qty__input {
  width: 4rem;
  height: 100%;
  border: 0;
  background: transparent;
  color: inherit;
  text-align: center;
  font: 500 1em/1 inherit;
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
  padding:0px;
  font-size: 1.3rem;
}
.qty__input::-webkit-outer-spin-button,
.qty__input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty__input:focus { outline: 0; }
.qty__input:focus-visible { outline: 2px solid var(--sw-ok-ink); outline-offset: -2px; border-radius: 4px; }

/* --- Verkauft: gleiche Silhouette, aber nichts zum Anklicken ------------- */
.cart-sold {
  display: inline-flex;
  align-items: center;
  gap: .6em;
  height: 3.25rem;
  padding: 0 1.5rem;
  border-radius: 999px;
  background: transparent;
  box-shadow: inset 0 0 0 1px rgba(20,22,26,.18);
  color: #6b7280;
  font: 500 1rem/1 inherit;
  font-family: inherit;
  letter-spacing: .01em;
  cursor: default;
}
.cart-sold__icon { width: 1.2em; height: 1.2em; flex: none; opacity: .8; }

/* --- Barrierefreiheit ---------------------------------------------------- */
.btn-swallow__status {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .btn-swallow,
  .btn-swallow * {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
  }
  .btn-swallow__tick { stroke-dashoffset: 0; }
}