diff --git a/parfum-shop/src/App.css b/parfum-shop/src/App.css
index 9e9bf2b..9366ba2 100644
--- a/parfum-shop/src/App.css
+++ b/parfum-shop/src/App.css
@@ -81,7 +81,8 @@ main {
[class*="-box"],
button,
input,
-textarea {
+textarea,
+select {
transition:
background-color var(--duration-med) var(--ease-out),
border-color var(--duration-med) var(--ease-out),
diff --git a/parfum-shop/src/components/Footer.css b/parfum-shop/src/components/Footer.css
index 956edae..47f7d48 100644
--- a/parfum-shop/src/components/Footer.css
+++ b/parfum-shop/src/components/Footer.css
@@ -74,9 +74,16 @@
}
.site-footer__nav {
+ display: block;
+}
+
+.site-footer__nav ul {
display: flex;
flex-direction: column;
gap: 0.72rem;
+ list-style: none;
+ margin: 0;
+ padding: 0;
}
.site-footer__nav a {
diff --git a/parfum-shop/src/components/Footer.jsx b/parfum-shop/src/components/Footer.jsx
index f0aa705..40d331a 100644
--- a/parfum-shop/src/components/Footer.jsx
+++ b/parfum-shop/src/components/Footer.jsx
@@ -1,6 +1,28 @@
import { Link } from "react-router";
import "./Footer.css";
+const footerLinkGroups = [
+ {
+ heading: "Navigation",
+ ariaLabel: "Footer Navigation",
+ links: [
+ { to: "/", label: "Startseite" },
+ { to: "/#dufte", label: "D\u00FCfte" },
+ { to: "/discovery-set", label: "Discovery Set" },
+ ],
+ },
+ {
+ heading: "Rechtliches & Info",
+ ariaLabel: "Footer Rechtliches und Info",
+ links: [
+ { to: "/about", label: "About Us" },
+ { to: "/support", label: "Support" },
+ { to: "/impressum", label: "Impressum" },
+ { to: "/datenschutz", label: "Datenschutz" },
+ ],
+ },
+];
+
function Footer({ flushTop = false }) {
return (
);
diff --git a/parfum-shop/src/components/ProductDetailPage.css b/parfum-shop/src/components/ProductDetailPage.css
index d600caa..c0bbeb8 100644
--- a/parfum-shop/src/components/ProductDetailPage.css
+++ b/parfum-shop/src/components/ProductDetailPage.css
@@ -369,8 +369,8 @@
min-height: 44px;
padding: 0 1rem;
border-radius: var(--radius-lg);
- background: var(--theme-accent);
- color: #fff;
+ background: var(--theme-accent-fill);
+ color: var(--theme-accent-contrast);
text-decoration: none;
white-space: nowrap;
font-size: var(--text-sm);
@@ -403,9 +403,9 @@
}
.buy-button {
- border-color: var(--theme-accent);
- background: var(--theme-accent);
- color: #fff;
+ border-color: var(--theme-accent-fill);
+ background: var(--theme-accent-fill);
+ color: var(--theme-accent-contrast);
}
.restock-button {
@@ -880,13 +880,13 @@
overflow: hidden;
background:
radial-gradient(circle at 86% 12%, rgba(255, 255, 255, 0.24), transparent 18rem),
- linear-gradient(135deg, var(--theme-accent), #e95700);
+ linear-gradient(135deg, var(--theme-accent-fill), var(--theme-accent-fill-strong));
}
.detail-bottom-cta .eyebrow,
.detail-bottom-cta h2,
.detail-bottom-cta p {
- color: #fff;
+ color: var(--theme-accent-contrast);
}
.detail-bottom-cta p {
@@ -905,7 +905,7 @@
border: 0;
border-radius: var(--radius-lg);
background: #fff;
- color: var(--theme-accent);
+ color: var(--theme-accent-fill-strong);
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.18);
font-size: var(--text-sm);
letter-spacing: 0;
diff --git a/parfum-shop/src/components/ShopDrawer.css b/parfum-shop/src/components/ShopDrawer.css
index 71be3bc..1795e1a 100644
--- a/parfum-shop/src/components/ShopDrawer.css
+++ b/parfum-shop/src/components/ShopDrawer.css
@@ -119,9 +119,9 @@
.shop-field input {
width: 100%;
min-height: 42px;
- border: 1px solid var(--theme-border);
+ border: 1px solid var(--theme-control-border);
border-radius: 0;
- background: var(--theme-surface-soft);
+ background: var(--theme-control-bg);
padding: 10px 11px;
color: var(--theme-text);
font: inherit;
@@ -129,6 +129,16 @@
text-transform: none;
}
+.shop-field input:hover {
+ border-color: var(--theme-control-border-hover);
+}
+
+.shop-field input:focus {
+ border-color: var(--theme-control-border-focus);
+ outline: 2px solid var(--theme-focus-ring);
+ outline-offset: 2px;
+}
+
.drawer-primary,
.drawer-secondary,
.cart-remove,
@@ -251,8 +261,8 @@
}
.payment-card.active {
- border-color: #ff6a00;
- background: rgba(255, 106, 0, 0.12);
+ border-color: var(--theme-accent);
+ background: rgba(var(--theme-accent-rgb) / 0.12);
}
.totals-box {
@@ -306,7 +316,7 @@
}
.drawer-error {
- border-color: #ff6a00;
+ border-color: var(--theme-accent);
}
.profile-head {
@@ -366,8 +376,8 @@
}
.pref-toggle.active {
- border-color: #ff6a00;
- background: rgba(255, 106, 0, 0.12);
+ border-color: var(--theme-accent);
+ background: rgba(var(--theme-accent-rgb) / 0.12);
}
.subscription-list {
@@ -415,7 +425,7 @@
}
.subscription-row button:hover {
- border-color: #ff6a00;
+ border-color: var(--theme-accent);
}
.requirement-row {
@@ -423,7 +433,7 @@
}
.requirement-row strong.met {
- color: #ff6a00;
+ color: var(--theme-accent);
}
.order-card {
diff --git a/parfum-shop/src/components/ShopDrawer.jsx b/parfum-shop/src/components/ShopDrawer.jsx
index 938a074..be38df2 100644
--- a/parfum-shop/src/components/ShopDrawer.jsx
+++ b/parfum-shop/src/components/ShopDrawer.jsx
@@ -1,4 +1,4 @@
-import { useState } from "react";
+import { useId, useState } from "react";
import { Link } from "react-router";
import { formatChf } from "../shop/money";
import { useShop } from "../shop/useShop";
@@ -18,14 +18,36 @@ const notificationLabels = [
["discovery_enabled", "Discovery Set Updates"],
];
-function Field({ label, value, onChange, type = "text", readOnly = false }) {
+function Field({
+ label,
+ value,
+ onChange,
+ type = "text",
+ readOnly = false,
+ id,
+ name,
+ autoComplete,
+ inputMode,
+}) {
+ const generatedId = useId();
+ const fallbackName = label
+ .toLowerCase()
+ .replace(/[^a-z0-9]+/g, "_")
+ .replace(/^_|_$/g, "");
+ const fieldName = name || fallbackName;
+ const fieldId = id || `shop-field-${fieldName}-${generatedId}`;
+
return (
-
-
-
-

-
-
-
-
+
+
+
))}
diff --git a/parfum-shop/src/pages/SupportPage.css b/parfum-shop/src/pages/SupportPage.css
index 8e6d493..7649bda 100644
--- a/parfum-shop/src/pages/SupportPage.css
+++ b/parfum-shop/src/pages/SupportPage.css
@@ -205,8 +205,8 @@
margin-top: 1.15rem;
padding: 0 1.1rem;
border-radius: var(--radius-lg);
- background: var(--theme-accent);
- color: #fff;
+ background: var(--theme-accent-fill);
+ color: var(--theme-accent-contrast);
font-size: var(--text-sm);
text-decoration: none;
transition:
@@ -240,13 +240,13 @@
overflow: hidden;
background:
radial-gradient(circle at 92% 0%, rgba(255, 255, 255, 0.22), transparent 20rem),
- var(--theme-accent);
+ var(--theme-accent-fill);
}
.support-bottom-copy .support-label,
.support-bottom-copy h2,
.support-bottom-copy p {
- color: #fff;
+ color: var(--theme-accent-contrast);
}
.support-bottom-copy p {
@@ -286,7 +286,7 @@
.support-btn--primary {
background: #fff;
- color: var(--theme-accent);
+ color: var(--theme-accent-fill-strong);
}
.support-btn--secondary {
diff --git a/parfum-shop/src/style/tokens.css b/parfum-shop/src/style/tokens.css
index ff25667..967ca5d 100644
--- a/parfum-shop/src/style/tokens.css
+++ b/parfum-shop/src/style/tokens.css
@@ -22,6 +22,11 @@
--theme-white: #eaeaea;
--theme-accent: #ff6a00;
--theme-accent-rgb: 255 106 0;
+ --theme-accent-fill: #c24700;
+ --theme-accent-fill-rgb: 194 71 0;
+ --theme-accent-fill-strong: #a83b00;
+ --theme-accent-contrast: #ffffff;
+ --theme-focus-ring: #ff9440;
/* Surfaces (dark theme — default) */
--theme-bg: #262626;
@@ -32,6 +37,10 @@
--theme-text-muted: #c8c8c8;
--theme-border: #4a4a4a;
--theme-border-strong: rgba(234, 234, 234, 0.26);
+ --theme-control-bg: var(--theme-surface);
+ --theme-control-border: #8a8a8a;
+ --theme-control-border-hover: #9a9a9a;
+ --theme-control-border-focus: var(--theme-focus-ring);
--theme-shadow: 0 24px 70px rgba(0, 0, 0, 0.28);
--theme-shadow-soft: 0 16px 42px rgba(0, 0, 0, 0.18);
@@ -121,6 +130,11 @@ body.theme-light {
--theme-text-muted: #5f5f5f;
--theme-border: #d6d6d6;
--theme-border-strong: rgba(38, 38, 38, 0.22);
+ --theme-focus-ring: #a83b00;
+ --theme-control-bg: #ffffff;
+ --theme-control-border: #767676;
+ --theme-control-border-hover: #5f5f5f;
+ --theme-control-border-focus: var(--theme-focus-ring);
--theme-shadow: 0 24px 70px rgba(38, 38, 38, 0.13);
--theme-shadow-soft: 0 16px 42px rgba(38, 38, 38, 0.1);
}