diff --git a/parfum-shop/src/style/breakpoints.css b/parfum-shop/src/style/breakpoints.css
new file mode 100644
index 0000000..3cda1e3
--- /dev/null
+++ b/parfum-shop/src/style/breakpoints.css
@@ -0,0 +1,27 @@
+/**
+ * Breakpoints
+ * ----------------------------------------------------------------------------
+ * Mobile-first standard. New layout code must use min-width queries below.
+ *
+ * sm >= 480px Phone landscape
+ * md >= 768px Tablet
+ * lg >= 1024px Tablet landscape / small desktop
+ * xl >= 1280px Desktop
+ *
+ * Existing legacy max-width queries in page-level CSS files remain in place
+ * and are migrated incrementally. See plan, Phase E.
+ */
+
+/* Visibility utilities */
+.is-hidden-md-down {
+ display: none;
+}
+
+@media (min-width: 768px) {
+ .is-hidden-md-down {
+ display: revert;
+ }
+ .is-hidden-md-up {
+ display: none;
+ }
+}
diff --git a/parfum-shop/src/style/grid.css b/parfum-shop/src/style/grid.css
new file mode 100644
index 0000000..a405d3d
--- /dev/null
+++ b/parfum-shop/src/style/grid.css
@@ -0,0 +1,131 @@
+/**
+ * 12-Column Grid System
+ * ----------------------------------------------------------------------------
+ * Mobile-first. All columns span 12 by default; `md:` and `lg:` modifiers
+ * narrow the span on larger viewports.
+ *
+ *
+ *
+ *
+ *
+ */
+
+/* Containers */
+.container,
+.container-narrow,
+.container-wide {
+ width: var(--container);
+ margin-inline: auto;
+}
+
+.container-narrow {
+ width: var(--container-narrow);
+}
+
+.container-wide {
+ width: var(--container-wide);
+}
+
+/* Section spacing */
+.section-pad-xs {
+ padding-block: var(--section-y-xs);
+}
+
+.section-pad-sm {
+ padding-block: var(--section-y-sm);
+}
+
+.section-pad-md {
+ padding-block: var(--section-y);
+}
+
+.section-pad-lg {
+ padding-block: var(--section-y-lg);
+}
+
+/* Grid */
+.grid-12 {
+ display: grid;
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ gap: var(--grid-gap);
+}
+
+.grid-gap-sm {
+ gap: var(--gap-sm);
+}
+
+.grid-gap-md {
+ gap: var(--gap-md);
+}
+
+.grid-gap-lg {
+ gap: var(--gap-lg);
+}
+
+/* Base column spans (mobile-first; default = full width) */
+.col-span-1 { grid-column: span 1; }
+.col-span-2 { grid-column: span 2; }
+.col-span-3 { grid-column: span 3; }
+.col-span-4 { grid-column: span 4; }
+.col-span-5 { grid-column: span 5; }
+.col-span-6 { grid-column: span 6; }
+.col-span-7 { grid-column: span 7; }
+.col-span-8 { grid-column: span 8; }
+.col-span-9 { grid-column: span 9; }
+.col-span-10 { grid-column: span 10; }
+.col-span-11 { grid-column: span 11; }
+.col-span-12 { grid-column: span 12; }
+
+.col-start-1 { grid-column-start: 1; }
+.col-start-2 { grid-column-start: 2; }
+.col-start-3 { grid-column-start: 3; }
+.col-start-4 { grid-column-start: 4; }
+.col-start-5 { grid-column-start: 5; }
+.col-start-6 { grid-column-start: 6; }
+.col-start-7 { grid-column-start: 7; }
+
+@media (min-width: 768px) {
+ .md\:col-span-1 { grid-column: span 1; }
+ .md\:col-span-2 { grid-column: span 2; }
+ .md\:col-span-3 { grid-column: span 3; }
+ .md\:col-span-4 { grid-column: span 4; }
+ .md\:col-span-5 { grid-column: span 5; }
+ .md\:col-span-6 { grid-column: span 6; }
+ .md\:col-span-7 { grid-column: span 7; }
+ .md\:col-span-8 { grid-column: span 8; }
+ .md\:col-span-9 { grid-column: span 9; }
+ .md\:col-span-10 { grid-column: span 10; }
+ .md\:col-span-11 { grid-column: span 11; }
+ .md\:col-span-12 { grid-column: span 12; }
+
+ .md\:col-start-1 { grid-column-start: 1; }
+ .md\:col-start-2 { grid-column-start: 2; }
+ .md\:col-start-3 { grid-column-start: 3; }
+ .md\:col-start-4 { grid-column-start: 4; }
+ .md\:col-start-5 { grid-column-start: 5; }
+ .md\:col-start-6 { grid-column-start: 6; }
+ .md\:col-start-7 { grid-column-start: 7; }
+}
+
+@media (min-width: 1024px) {
+ .lg\:col-span-1 { grid-column: span 1; }
+ .lg\:col-span-2 { grid-column: span 2; }
+ .lg\:col-span-3 { grid-column: span 3; }
+ .lg\:col-span-4 { grid-column: span 4; }
+ .lg\:col-span-5 { grid-column: span 5; }
+ .lg\:col-span-6 { grid-column: span 6; }
+ .lg\:col-span-7 { grid-column: span 7; }
+ .lg\:col-span-8 { grid-column: span 8; }
+ .lg\:col-span-9 { grid-column: span 9; }
+ .lg\:col-span-10 { grid-column: span 10; }
+ .lg\:col-span-11 { grid-column: span 11; }
+ .lg\:col-span-12 { grid-column: span 12; }
+
+ .lg\:col-start-1 { grid-column-start: 1; }
+ .lg\:col-start-2 { grid-column-start: 2; }
+ .lg\:col-start-3 { grid-column-start: 3; }
+ .lg\:col-start-4 { grid-column-start: 4; }
+ .lg\:col-start-5 { grid-column-start: 5; }
+ .lg\:col-start-6 { grid-column-start: 6; }
+ .lg\:col-start-7 { grid-column-start: 7; }
+}
diff --git a/parfum-shop/src/style/tokens.css b/parfum-shop/src/style/tokens.css
new file mode 100644
index 0000000..ff25667
--- /dev/null
+++ b/parfum-shop/src/style/tokens.css
@@ -0,0 +1,126 @@
+/**
+ * Design Tokens
+ * ----------------------------------------------------------------------------
+ * Single source of truth for theme colors, spacing, typography, breakpoints,
+ * grid and motion. Imported once via index.css.
+ *
+ * Tokens follow a BEM-like prefix scheme:
+ * --theme-* colors and surfaces (theme-aware via body.theme-light)
+ * --gap-* spacing primitives
+ * --section-* vertical section rhythm
+ * --container-* horizontal content widths
+ * --text-* typographic scale
+ * --bp-* breakpoint values (mobile-first)
+ * --grid-* layout grid system
+ * --ease-* motion easing
+ * --duration-* motion duration
+ */
+
+:root {
+ /* Brand */
+ --theme-black: #262626;
+ --theme-white: #eaeaea;
+ --theme-accent: #ff6a00;
+ --theme-accent-rgb: 255 106 0;
+
+ /* Surfaces (dark theme — default) */
+ --theme-bg: #262626;
+ --theme-surface: #2f2f2f;
+ --theme-surface-soft: #363636;
+ --theme-paper: #404040;
+ --theme-text: #eaeaea;
+ --theme-text-muted: #c8c8c8;
+ --theme-border: #4a4a4a;
+ --theme-border-strong: rgba(234, 234, 234, 0.26);
+ --theme-shadow: 0 24px 70px rgba(0, 0, 0, 0.28);
+ --theme-shadow-soft: 0 16px 42px rgba(0, 0, 0, 0.18);
+
+ /* Canonical drop-shadow for product bottle artwork. Used wherever the
+ flacon has room (hero, recommendation banner, product transition). */
+ --shadow-product: drop-shadow(0 34px 72px rgba(0, 0, 0, 0.42));
+
+ /* Tighter version for small grid contexts (landing product cards,
+ discovery product thumbnails, recommendation cards) — fits inside
+ the card bounds even with overflow: hidden. */
+ --shadow-product-card: drop-shadow(0 14px 26px rgba(0, 0, 0, 0.3));
+
+ /* Footer keeps its dark identity in both themes */
+ --footer-bg: #171717;
+ --footer-text: #f5f5f5;
+ --footer-text-muted: rgba(255, 255, 255, 0.7);
+ --footer-text-faint: rgba(255, 255, 255, 0.52);
+ --footer-border: rgba(255, 255, 255, 0.08);
+ --footer-watermark: rgba(255, 255, 255, 0.035);
+
+ /* Spacing — horizontal page padding */
+ --page-x: clamp(1rem, 4vw, 5rem);
+
+ /* Spacing — vertical section rhythm */
+ --section-y-xs: clamp(2rem, 5vw, 4.5rem);
+ --section-y-sm: clamp(3rem, 7vw, 7rem);
+ --section-y: clamp(4rem, 10vw, 10rem);
+ --section-y-lg: clamp(5rem, 14vw, 14rem);
+
+ /* Containers */
+ --container: min(calc(100% - (var(--page-x) * 2)), 1440px);
+ --container-narrow: min(calc(100% - (var(--page-x) * 2)), 920px);
+ --container-wide: min(calc(100% - (var(--page-x) * 2)), 1680px);
+ --text-measure: 68ch;
+
+ /* Spacing — reusable gaps */
+ --gap-2xs: clamp(0.35rem, 0.7vw, 0.65rem);
+ --gap-xs: clamp(0.5rem, 1vw, 0.875rem);
+ --gap-sm: clamp(0.75rem, 1.5vw, 1.25rem);
+ --gap-md: clamp(1rem, 2vw, 2rem);
+ --gap-lg: clamp(1.5rem, 4vw, 4rem);
+ --gap-xl: clamp(2rem, 6vw, 6rem);
+
+ /* Radius — design intent: hard edges everywhere */
+ --radius-xs: 0;
+ --radius-sm: 0;
+ --radius-md: 0;
+ --radius-lg: 0;
+ --radius-xl: 0;
+
+ /* Typography scale */
+ --text-xs: clamp(0.75rem, 0.72rem + 0.15vw, 0.875rem);
+ --text-sm: clamp(0.875rem, 0.83rem + 0.2vw, 1rem);
+ --text-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
+ --text-lg: clamp(1.125rem, 1.05rem + 0.35vw, 1.375rem);
+ --text-xl: clamp(1.35rem, 1.15rem + 0.9vw, 2rem);
+ --text-2xl: clamp(1.75rem, 1.25rem + 2vw, 3.5rem);
+ --text-display: clamp(3.05rem, 10.5vw, 10.8rem);
+
+ /* Breakpoints (mobile-first, used in JS via matchMedia and as docs) */
+ --bp-sm: 480px;
+ --bp-md: 768px;
+ --bp-lg: 1024px;
+ --bp-xl: 1280px;
+
+ /* Grid system */
+ --grid-cols: 12;
+ --grid-gap: var(--gap-md);
+
+ /* Accessibility */
+ --touch-target-min: 44px;
+
+ /* Motion */
+ --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
+ --ease-snap: cubic-bezier(0.16, 1, 0.3, 1);
+ --duration-fast: 160ms;
+ --duration-med: 260ms;
+ --duration-slow: 720ms;
+}
+
+body.theme-light {
+ --theme-bg: #eaeaea;
+ --theme-surface: #f5f5f5;
+ --theme-surface-soft: #f0f0f0;
+ --theme-paper: #ffffff;
+ --theme-text: #262626;
+ --theme-text-muted: #5f5f5f;
+ --theme-border: #d6d6d6;
+ --theme-border-strong: rgba(38, 38, 38, 0.22);
+ --theme-shadow: 0 24px 70px rgba(38, 38, 38, 0.13);
+ --theme-shadow-soft: 0 16px 42px rgba(38, 38, 38, 0.1);
+}