diff --git a/src/components/honeycomb.tsx b/src/components/honeycomb.tsx
new file mode 100644
index 0000000..a783370
--- /dev/null
+++ b/src/components/honeycomb.tsx
@@ -0,0 +1,89 @@
+import { useId } from "react";
+
+/**
+ * Wabenraster als Markensignatur: dieselbe spitz stehende Sechseckform wie
+ * im Logomark, als feines Linienmuster. Liegt absolut im naechsten
+ * relativen Elternteil, ist rein dekorativ (aria-hidden) und laeuft ueber
+ * eine Maske zu den Raendern hin aus, damit es nie als harte Kachelkante
+ * endet.
+ *
+ * Farbe ueber currentColor (text-*-Klasse am Aufrufer), Staerke ueber
+ * opacity — so passt dasselbe Muster auf Creme wie auf Waldgruen.
+ */
+export function HoneycombPattern({
+ className = "",
+ size = 22,
+ fade = "radial",
+}: {
+ className?: string;
+ /** Radius eines Sechsecks in px. */
+ size?: number;
+ /** Wohin das Muster auslaeuft. */
+ fade?: "radial" | "right" | "bottom" | "none";
+}) {
+ const id = useId().replace(/:/g, "");
+ const r = size;
+ const w = Math.sqrt(3) * r;
+ const tileH = 3 * r;
+
+ // Zwei Sechsecke je Kachel (versetzte Reihen), spitz nach oben wie im Logo.
+ const hex = (cx: number, cy: number) =>
+ Array.from({ length: 6 }, (_, i) => {
+ const angle = (Math.PI / 3) * i - Math.PI / 2;
+ return `${(cx + r * Math.cos(angle)).toFixed(2)},${(cy + r * Math.sin(angle)).toFixed(2)}`;
+ }).join(" ");
+
+ const masks: Record = {
+ radial: "radial-gradient(ellipse at center, black 20%, transparent 75%)",
+ right: "linear-gradient(to left, black, transparent 80%)",
+ bottom: "linear-gradient(to top, black, transparent 85%)",
+ none: undefined,
+ };
+
+ return (
+
+ );
+}
+
+/** Kleines Sechseck als Aufzaehlungs- und Statuszeichen (statt Unicode-Glyphen). */
+export function HexMark({ className = "h-3 w-3", filled = true }: { className?: string; filled?: boolean }) {
+ return (
+
+ );
+}
+
+/** Haekchen im Sechseck — fuer Vorteilslisten (ersetzt das Textzeichen "✓"). */
+export function HexCheck({ className = "h-4 w-4" }: { className?: string }) {
+ return (
+
+ );
+}
diff --git a/src/components/product-card.tsx b/src/components/product-card.tsx
index 581d0a8..81b99f4 100644
--- a/src/components/product-card.tsx
+++ b/src/components/product-card.tsx
@@ -2,13 +2,14 @@
import Link from "next/link";
import { useState } from "react";
-import { motion } from "motion/react";
+import { AnimatePresence, motion } from "motion/react";
import { ContentImage } from "@/components/content-image";
import { QuantityStepper } from "@/components/quantity-stepper";
import { StarRating } from "@/components/star-rating";
import { Button } from "@/components/ui";
import { formatPrice, formatPricePerKg } from "@/lib/format";
import { useCartStore } from "@/store/cart-store";
+import { launchCartFlight } from "@/components/cart-flight";
import { useI18n } from "@/i18n/i18n-provider";
import type { ProductWithRelations } from "@/lib/data";
import type { ProductCategory } from "@/generated/prisma/client";
@@ -68,20 +69,78 @@ export function TasteScale({
{label}
-
+ {/* Ausloeser ist die ganze Skala: die Fuellsegmente starten mit
+ Breite 0 und wuerden selbst nie als "sichtbar" gemeldet. */}
+
{Array.from({ length: 5 }, (_, i) => (
+ >
+ {i < value ? (
+ // Die Skala "fuellt sich" beim Erscheinen Segment fuer Segment
+ // wie ein Glas — sichtbar, dass es um Intensitaet geht.
+
+ ) : null}
+
))}
-
+
);
}
+/**
+ * Knopfbeschriftung, die nach dem Hinzufuegen zu "Hinzugefuegt" mit
+ * gezeichnetem Haekchen wechselt — die Bestaetigung bleibt am Ort des
+ * Klicks, waehrend der Tropfen zum Warenkorb fliegt.
+ */
+function AddedLabel({ justAdded, idle, done }: { justAdded: boolean; idle: string; done: string }) {
+ return (
+
+
+ {justAdded ? (
+
+ ) : null}
+ {/* Das Woerterbuch haengt ein "✓" an — hier zeichnet das SVG das Haekchen. */}
+ {justAdded ? done.replace(/\s*✓\s*$/, "") : idle}
+
+
+ );
+}
+
function toCartItem(product: ProductWithRelations) {
return {
productId: product.id,
@@ -113,13 +172,14 @@ export function AddToCartButton({
);
@@ -151,13 +211,14 @@ export function AddToCartWithQuantity({
@@ -168,10 +229,13 @@ export function AddToCartWithQuantity({
export function ProductCard({
product,
reviewSummary,
+ index = 0,
}: {
product: ProductWithRelations;
/** Optional — nur die Shop-Uebersicht laedt Bewertungen gebuendelt fuer das ganze Raster. */
reviewSummary?: { average: number | null; count: number };
+ /** Position im Raster — staffelt das Erscheinen (gedeckelt, damit lange Listen nicht warten lassen). */
+ index?: number;
}) {
const { t, locale } = useI18n();
const stock = product.inventory?.quantity ?? 0;
@@ -180,21 +244,21 @@ export function ProductCard({
+ {/* Warmer Honigschimmer, der beim Hover diagonal ueber das Glas
+ zieht — wie Licht, das durch Honig faellt. */}
+
{stock === 0 ? (
{t.product.outOfStock}
) : stock <= 5 ? (
-
+
{t.product.onlyLeft(stock)}
) : null}
-