-
👑 Beste Kundinnen
-
Noch keine wiederkehrende Kundschaft.
-
-
+
+
+ 🌍
+
Herkunft der Bestellungen
+
+
+
+
🗺️
+
Noch keine Bestellungen.
+
Sobald Bestellungen eingehen, siehst du hier den Anteil je Land (DE/AT/CH/LU).
+
+
+
+
+
+
+
+
+
+
+
+ 👑
+
Stammkundschaft
+
+
+
+
💌
+
Noch keine wiederkehrende Kundschaft.
+
Sobald jemand zum zweiten Mal bestellt, erscheint sie hier — sortiert nach bisherigem Umsatz.
+
+
+
@@ -482,14 +540,19 @@ const lang: Locale = "de";
}));
const landList = document.getElementById("verwaltung-land-list");
- landList.innerHTML = auswertungLaender.length === 0
- ? `
Noch keine Bestellungen.
`
- : auswertungLaender.map((l) => `
+ const landEmpty = document.getElementById("verwaltung-land-empty");
+ if (auswertungLaender.length === 0) {
+ landList.innerHTML = "";
+ landEmpty.style.display = "";
+ } else {
+ landEmpty.style.display = "none";
+ landList.innerHTML = auswertungLaender.map((l) => `
${l.flagge} ${escapeHtml(l.name)}${l.count} Bestellungen · ${l.prozent}%
`).join("");
+ }
// ── NEU: Beste Kundinnen (Umsatz pro E-Mail, nur wer mehr als 1× bestellt hat) ──
const umsatzProKundin = new Map(); // email -> { name, summe, anzahl }
@@ -505,14 +568,12 @@ const lang: Locale = "de";
.sort((a, b) => b.summe - a.summe)
.slice(0, 8);
const maxKundenUmsatz = Math.max(1, ...besteKunden.map((k) => k.summe));
- const kundenCard = document.getElementById("verwaltung-kunden-card");
const kundenEmpty = document.getElementById("verwaltung-kunden-empty");
const kundenList = document.getElementById("verwaltung-kunden-list");
if (besteKunden.length === 0) {
- kundenCard.style.display = "none";
+ kundenList.innerHTML = "";
kundenEmpty.style.display = "";
} else {
- kundenCard.style.display = "";
kundenEmpty.style.display = "none";
kundenList.innerHTML = besteKunden.map((k) => `
diff --git a/src/styles/global.css b/src/styles/global.css
index c81089a..f0ae713 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -2861,6 +2861,75 @@ a:focus-visible, button:focus-visible {
/* Interne Bestellverwaltung (/verwaltung/) — Status-Kacheln, Filterleiste, Auswertungs-Balken. */
+/* "Kisten" — jede zusammengehörige Gruppe (Bestellstatus, Kennzahlen, Bestellliste, Bestseller,
+ Herkunft, Stammkundschaft) bekommt ihre eigene, klar abgegrenzte Box mit eigener Akzentfarbe
+ (--box-color, pro Kiste per inline style gesetzt) statt lose auf der Seite zu stehen — auf
+ Wunsch ("alles was zueinander passt in einer Kiste, richtig geil speziell") deutlich
+ eigenständiger gestaltet als eine normale .card: eigener farbiger Eckenschein, eigenes
+ Icon-Abzeichen vor dem Titel, dezent pulsierender Rand. */
+.verwaltung-box {
+ position: relative;
+ overflow: hidden;
+ border-radius: var(--radius-l);
+ border: 1.5px solid color-mix(in srgb, var(--box-color, var(--c-accent)) 38%, transparent);
+ background: linear-gradient(155deg, color-mix(in srgb, var(--box-color, var(--c-accent)) 9%, var(--c-anthracite-light)), var(--c-anthracite));
+ padding: 1.6rem 1.7rem;
+ margin: 1.4rem 0;
+ animation: verwaltung-box-glow 3.4s ease-in-out infinite;
+}
+@keyframes verwaltung-box-glow {
+ 0%, 100% { box-shadow: 0 0 0 1px color-mix(in srgb, var(--box-color, var(--c-accent)) 22%, transparent); }
+ 50% { box-shadow: 0 0 22px -8px color-mix(in srgb, var(--box-color, var(--c-accent)) 55%, transparent); }
+}
+.verwaltung-box::before {
+ content: "";
+ position: absolute;
+ top: -45%;
+ right: -15%;
+ width: 260px;
+ height: 260px;
+ background: radial-gradient(circle, color-mix(in srgb, var(--box-color, var(--c-accent)) 30%, transparent), transparent 70%);
+ pointer-events: none;
+}
+.verwaltung-box-head {
+ display: flex;
+ align-items: center;
+ gap: 0.8rem;
+ margin-bottom: 1.1rem;
+ position: relative;
+ z-index: 1;
+}
+.verwaltung-box-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ width: 2.6rem;
+ height: 2.6rem;
+ border-radius: 50%;
+ font-size: 1.3rem;
+ background: color-mix(in srgb, var(--box-color, var(--c-accent)) 24%, transparent);
+ border: 1px solid color-mix(in srgb, var(--box-color, var(--c-accent)) 55%, transparent);
+}
+.verwaltung-box-head h2 { margin: 0; font-size: 1.3rem; }
+.verwaltung-box-body { position: relative; z-index: 1; }
+@media (prefers-reduced-motion: reduce) { .verwaltung-box { animation: none; } }
+
+/* Leerzustände innerhalb einer Kiste — großes Icon + kurzer, freundlicher Text statt nacktem
+ Fließtext, damit auch "noch nichts da" nicht trostlos wirkt. */
+.verwaltung-box-empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ gap: 0.4rem;
+ padding: 2.2rem 1rem;
+ color: var(--c-text-muted);
+}
+.verwaltung-box-empty-icon { font-size: 2.6rem; opacity: 0.75; }
+.verwaltung-box-empty p { margin: 0; }
+.verwaltung-box-empty p:first-of-type { color: var(--c-text); font-weight: 600; font-size: 1.02rem; }
+
/* Hero-Kopf: dieselbe "besondere" Formsprache wie die anderen Premium-Karten der Seite
(wanderndes Verlaufslicht + pulsierender Rand + Funkeln), passend zu einer Seite, die "alles
übertrifft" — nur dezenter/edler gehalten, weil es ein Arbeits-Dashboard ist, kein Verkaufs-