@salesmind-ai/design-system 0.3.13 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/{SectionShell-GlglHCzz.d.cts → SectionShell-D1YC7vey.d.cts} +2 -1
  2. package/dist/{SectionShell-GlglHCzz.d.ts → SectionShell-D1YC7vey.d.ts} +2 -1
  3. package/dist/{StatsSection-Dihy3zml.d.cts → StatsSection-Bdrm8XsT.d.cts} +2 -1
  4. package/dist/{StatsSection-MfKKyqL1.d.ts → StatsSection-Bs1ugbAt.d.ts} +2 -1
  5. package/dist/blog/index.cjs +13 -13
  6. package/dist/blog/index.css +59 -13
  7. package/dist/blog/index.css.map +1 -1
  8. package/dist/blog/index.d.cts +1 -1
  9. package/dist/blog/index.d.ts +1 -1
  10. package/dist/blog/index.js +2 -2
  11. package/dist/{chunk-C4XSNMRU.cjs → chunk-3BAQDW3V.cjs} +5 -4
  12. package/dist/chunk-3BAQDW3V.cjs.map +1 -0
  13. package/dist/{chunk-BJXGIHVZ.cjs → chunk-5LA3T22E.cjs} +124 -4
  14. package/dist/chunk-5LA3T22E.cjs.map +1 -0
  15. package/dist/{chunk-F33EEHWL.cjs → chunk-6D22TFLA.cjs} +4 -4
  16. package/dist/{chunk-QTARL7VL.js → chunk-7UZ5DETZ.js} +124 -4
  17. package/dist/chunk-7UZ5DETZ.js.map +1 -0
  18. package/dist/{chunk-EM7JHRYW.cjs → chunk-BJZ2DKS5.cjs} +9 -3
  19. package/dist/chunk-BJZ2DKS5.cjs.map +1 -0
  20. package/dist/chunk-BUTQSDQH.js +200 -0
  21. package/dist/chunk-BUTQSDQH.js.map +1 -0
  22. package/dist/{chunk-LSR7JYVH.cjs → chunk-H2KQ3WSH.cjs} +12 -11
  23. package/dist/chunk-H2KQ3WSH.cjs.map +1 -0
  24. package/dist/{chunk-6R4F3HK6.js → chunk-HDVAMYSG.js} +2 -2
  25. package/dist/{chunk-AFZW6GHI.cjs → chunk-LTPTW2US.cjs} +29 -29
  26. package/dist/{chunk-T5H5PNLN.js → chunk-OWS2KAXZ.js} +3 -3
  27. package/dist/chunk-PUPSK3DI.cjs +216 -0
  28. package/dist/chunk-PUPSK3DI.cjs.map +1 -0
  29. package/dist/{chunk-KE7T2HQC.js → chunk-QWE2RNCS.js} +4 -3
  30. package/dist/chunk-QWE2RNCS.js.map +1 -0
  31. package/dist/{chunk-KK5UO2P4.cjs → chunk-UVEMY3FQ.cjs} +9 -9
  32. package/dist/{chunk-UFAJY2DM.js → chunk-VFJZQQZU.js} +9 -3
  33. package/dist/chunk-VFJZQQZU.js.map +1 -0
  34. package/dist/{chunk-ARC5KXBC.js → chunk-WYH4TKS5.js} +6 -5
  35. package/dist/chunk-WYH4TKS5.js.map +1 -0
  36. package/dist/{chunk-LGNMFBLF.cjs → chunk-XEX2AEZK.cjs} +4 -4
  37. package/dist/{chunk-PWVQPXW4.js → chunk-Y26OHHMX.js} +2 -2
  38. package/dist/{chunk-2KQVZ5FB.js → chunk-YJ6C3EKW.js} +2 -2
  39. package/dist/core/index.cjs +52 -16
  40. package/dist/core/index.d.cts +2 -251
  41. package/dist/core/index.d.ts +2 -251
  42. package/dist/core/index.js +2 -2
  43. package/dist/index.cjs +150 -93
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.css +100 -14
  46. package/dist/index.css.map +1 -1
  47. package/dist/index.d.cts +17 -4
  48. package/dist/index.d.ts +17 -4
  49. package/dist/index.js +29 -9
  50. package/dist/index.js.map +1 -1
  51. package/dist/marketing/index.cjs +36 -36
  52. package/dist/marketing/index.css +59 -13
  53. package/dist/marketing/index.css.map +1 -1
  54. package/dist/marketing/index.d.cts +1 -1
  55. package/dist/marketing/index.d.ts +1 -1
  56. package/dist/marketing/index.js +2 -2
  57. package/dist/motion/index.cjs +8 -8
  58. package/dist/motion/index.d.cts +3 -1
  59. package/dist/motion/index.d.ts +3 -1
  60. package/dist/motion/index.js +2 -2
  61. package/dist/motion-C651Ry6d.d.cts +832 -0
  62. package/dist/motion-C651Ry6d.d.ts +832 -0
  63. package/dist/sections/index.cjs +8 -8
  64. package/dist/sections/index.css +60 -14
  65. package/dist/sections/index.css.map +1 -1
  66. package/dist/sections/index.d.cts +2 -2
  67. package/dist/sections/index.d.ts +2 -2
  68. package/dist/sections/index.js +2 -2
  69. package/dist/social-proof/index.cjs +13 -13
  70. package/dist/social-proof/index.css +59 -13
  71. package/dist/social-proof/index.css.map +1 -1
  72. package/dist/social-proof/index.d.cts +1 -1
  73. package/dist/social-proof/index.d.ts +1 -1
  74. package/dist/social-proof/index.js +3 -3
  75. package/dist/styles/styles.css +67 -0
  76. package/dist/theme/index.cjs +13 -13
  77. package/dist/theme/index.js +2 -2
  78. package/package.json +30 -30
  79. package/dist/chunk-ARC5KXBC.js.map +0 -1
  80. package/dist/chunk-BJXGIHVZ.cjs.map +0 -1
  81. package/dist/chunk-C4XSNMRU.cjs.map +0 -1
  82. package/dist/chunk-EM7JHRYW.cjs.map +0 -1
  83. package/dist/chunk-KE7T2HQC.js.map +0 -1
  84. package/dist/chunk-L352JRV6.cjs +0 -105
  85. package/dist/chunk-L352JRV6.cjs.map +0 -1
  86. package/dist/chunk-LSR7JYVH.cjs.map +0 -1
  87. package/dist/chunk-QTARL7VL.js.map +0 -1
  88. package/dist/chunk-UFAJY2DM.js.map +0 -1
  89. package/dist/chunk-YNVRDD2P.js +0 -98
  90. package/dist/chunk-YNVRDD2P.js.map +0 -1
  91. /package/dist/{chunk-6R4F3HK6.js.map → chunk-6D22TFLA.cjs.map} +0 -0
  92. /package/dist/{chunk-F33EEHWL.cjs.map → chunk-HDVAMYSG.js.map} +0 -0
  93. /package/dist/{chunk-AFZW6GHI.cjs.map → chunk-LTPTW2US.cjs.map} +0 -0
  94. /package/dist/{chunk-KK5UO2P4.cjs.map → chunk-OWS2KAXZ.js.map} +0 -0
  95. /package/dist/{chunk-T5H5PNLN.js.map → chunk-UVEMY3FQ.cjs.map} +0 -0
  96. /package/dist/{chunk-2KQVZ5FB.js.map → chunk-XEX2AEZK.cjs.map} +0 -0
  97. /package/dist/{chunk-PWVQPXW4.js.map → chunk-Y26OHHMX.js.map} +0 -0
  98. /package/dist/{chunk-LGNMFBLF.cjs.map → chunk-YJ6C3EKW.js.map} +0 -0
@@ -3,7 +3,122 @@ import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import clsx from 'clsx';
4
4
 
5
5
  // src/theme/AppearanceProvider.tsx
6
+
7
+ // src/theme/ensure-readable-contrast.ts
8
+ function parseHex(hex) {
9
+ const clean = hex.replace(/^#/, "");
10
+ let r, g, b;
11
+ if (clean.length === 3) {
12
+ r = parseInt(clean[0] + clean[0], 16);
13
+ g = parseInt(clean[1] + clean[1], 16);
14
+ b = parseInt(clean[2] + clean[2], 16);
15
+ } else if (clean.length === 6) {
16
+ r = parseInt(clean.substring(0, 2), 16);
17
+ g = parseInt(clean.substring(2, 4), 16);
18
+ b = parseInt(clean.substring(4, 6), 16);
19
+ } else {
20
+ return null;
21
+ }
22
+ if (isNaN(r) || isNaN(g) || isNaN(b)) return null;
23
+ return [r, g, b];
24
+ }
25
+ function toHex(r, g, b) {
26
+ const clamp = (n) => Math.max(0, Math.min(255, Math.round(n)));
27
+ return "#" + [clamp(r), clamp(g), clamp(b)].map((c) => c.toString(16).padStart(2, "0")).join("");
28
+ }
29
+ function rgbToHsl(r, g, b) {
30
+ const rn = r / 255;
31
+ const gn = g / 255;
32
+ const bn = b / 255;
33
+ const max = Math.max(rn, gn, bn);
34
+ const min = Math.min(rn, gn, bn);
35
+ const l = (max + min) / 2;
36
+ if (max === min) return [0, 0, l];
37
+ const d = max - min;
38
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
39
+ let h;
40
+ if (max === rn) h = ((gn - bn) / d + (gn < bn ? 6 : 0)) / 6;
41
+ else if (max === gn) h = ((bn - rn) / d + 2) / 6;
42
+ else h = ((rn - gn) / d + 4) / 6;
43
+ return [h * 360, s, l];
44
+ }
45
+ function hslToRgb(h, s, l) {
46
+ const hNorm = (h % 360 + 360) % 360;
47
+ if (s === 0) {
48
+ const v = Math.round(l * 255);
49
+ return [v, v, v];
50
+ }
51
+ const hue2rgb = (p2, q2, t) => {
52
+ if (t < 0) t += 1;
53
+ if (t > 1) t -= 1;
54
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
55
+ if (t < 1 / 2) return q2;
56
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
57
+ return p2;
58
+ };
59
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
60
+ const p = 2 * l - q;
61
+ const hFrac = hNorm / 360;
62
+ return [
63
+ Math.round(hue2rgb(p, q, hFrac + 1 / 3) * 255),
64
+ Math.round(hue2rgb(p, q, hFrac) * 255),
65
+ Math.round(hue2rgb(p, q, hFrac - 1 / 3) * 255)
66
+ ];
67
+ }
68
+ function relativeLuminance(r, g, b) {
69
+ const [rs, gs, bs] = [r / 255, g / 255, b / 255].map(
70
+ (c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
71
+ );
72
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
73
+ }
74
+ function contrastRatio(fg, bg) {
75
+ const l1 = relativeLuminance(...fg);
76
+ const l2 = relativeLuminance(...bg);
77
+ const lighter = Math.max(l1, l2);
78
+ const darker = Math.min(l1, l2);
79
+ return (lighter + 0.05) / (darker + 0.05);
80
+ }
81
+ var DEFAULT_MIN_RATIO = 4.5;
82
+ var MAX_ITERATIONS = 25;
83
+ function ensureReadableContrast(accentHex, surfaceHex, minRatio = DEFAULT_MIN_RATIO) {
84
+ const fg = parseHex(accentHex);
85
+ const bg = parseHex(surfaceHex);
86
+ if (!fg || !bg) return accentHex;
87
+ if (contrastRatio(fg, bg) >= minRatio) return accentHex;
88
+ const [h, s] = rgbToHsl(...fg);
89
+ const bgLuminance = relativeLuminance(...bg);
90
+ const shouldLighten = bgLuminance < 0.5;
91
+ const currentLightness = rgbToHsl(...fg)[2];
92
+ let lo, hi;
93
+ if (shouldLighten) {
94
+ lo = currentLightness;
95
+ hi = 1;
96
+ } else {
97
+ lo = 0;
98
+ hi = currentLightness;
99
+ }
100
+ let bestHex = accentHex;
101
+ for (let i = 0; i < MAX_ITERATIONS; i++) {
102
+ const mid = (lo + hi) / 2;
103
+ const [rr, gg, bb] = hslToRgb(h, s, mid);
104
+ const ratio = contrastRatio([rr, gg, bb], bg);
105
+ if (ratio >= minRatio) {
106
+ bestHex = toHex(rr, gg, bb);
107
+ if (shouldLighten) hi = mid;
108
+ else lo = mid;
109
+ } else {
110
+ if (shouldLighten) lo = mid;
111
+ else hi = mid;
112
+ }
113
+ }
114
+ return bestHex;
115
+ }
6
116
  var STORAGE_KEY = "void-appearance-settings";
117
+ var BRAND_PINK_HEX = {
118
+ default: "#f97316",
119
+ salesmind: "#ff005a"
120
+ };
121
+ var DARK_SURFACE_HEX = "#08040a";
7
122
  var DEFAULT_SETTINGS = {
8
123
  theme: "dark",
9
124
  brand: "default",
@@ -23,7 +138,7 @@ function hexToRgb(hex) {
23
138
  }
24
139
  return `${r}, ${g}, ${b}`;
25
140
  }
26
- function relativeLuminance(r, g, b) {
141
+ function relativeLuminance2(r, g, b) {
27
142
  const [rs, gs, bs] = [r / 255, g / 255, b / 255].map(
28
143
  (c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
29
144
  );
@@ -37,7 +152,7 @@ function accentForegroundRgb(hex) {
37
152
  if (isNaN(r) || isNaN(g) || isNaN(b)) {
38
153
  return "255, 255, 255";
39
154
  }
40
- return relativeLuminance(r, g, b) > 0.179 ? "0, 0, 0" : "255, 255, 255";
155
+ return relativeLuminance2(r, g, b) > 0.179 ? "0, 0, 0" : "255, 255, 255";
41
156
  }
42
157
  function generateSecondaryColor(hex) {
43
158
  const cleanHex = hex.replace(/^#/, "");
@@ -103,6 +218,11 @@ function applySettings(settings) {
103
218
  root.style.removeProperty("--custom-accent2-rgb");
104
219
  root.style.removeProperty("--custom-accent-fg-rgb");
105
220
  }
221
+ const brandPinkHex = settings.brand === "custom" ? settings.customColor : BRAND_PINK_HEX[settings.brand] ?? BRAND_PINK_HEX.default;
222
+ root.style.setProperty(
223
+ "--brand-pink-readable",
224
+ ensureReadableContrast(brandPinkHex, DARK_SURFACE_HEX)
225
+ );
106
226
  }
107
227
  function prefersReducedMotion() {
108
228
  if (typeof window === "undefined") return false;
@@ -423,6 +543,6 @@ var AppearancePanel = React2.forwardRef(
423
543
  );
424
544
  AppearancePanel.displayName = "AppearancePanel";
425
545
 
426
- export { AppearancePanel, AppearanceProvider, accentForegroundRgb, hexToRgb, initializeAppearance, prefersReducedMotion, relativeLuminance, useAppearance };
546
+ export { AppearancePanel, AppearanceProvider, accentForegroundRgb, hexToRgb, initializeAppearance, prefersReducedMotion, relativeLuminance2 as relativeLuminance, useAppearance };
427
547
  //# sourceMappingURL=out.js.map
428
- //# sourceMappingURL=chunk-QTARL7VL.js.map
548
+ //# sourceMappingURL=chunk-7UZ5DETZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme/AppearanceProvider.tsx","../src/theme/ensure-readable-contrast.ts","../src/components/AppearancePanel/AppearancePanel.tsx"],"names":["p","q","relativeLuminance","React","jsx"],"mappings":"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","sourcesContent":["import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';\nimport { ensureReadableContrast } from './ensure-readable-contrast';\n\n/* ============================================================================\n APPEARANCE TYPES\n ============================================================================ */\n\nexport type Theme = 'light' | 'light-contrast' | 'dark' | 'dark-contrast';\nexport type Brand = 'default' | 'salesmind' | 'custom';\nexport type NavPlacement = 'left' | 'right' | 'bottom';\nexport type Density = 'comfortable' | 'compact';\nexport type Radius = 'playful' | 'sharp';\n\nexport interface AppearanceSettings {\n theme: Theme;\n brand: Brand;\n navPlacement: NavPlacement;\n density: Density;\n radius: Radius;\n /** Hex color for custom brand (e.g., \"#ff2d8a\") */\n customColor: string;\n}\n\nexport interface AppearanceContextValue extends AppearanceSettings {\n setTheme: (theme: Theme) => void;\n setBrand: (brand: Brand) => void;\n setNavPlacement: (nav: NavPlacement) => void;\n setDensity: (density: Density) => void;\n setRadius: (radius: Radius) => void;\n setCustomColor: (color: string) => void;\n setAppearance: (settings: Partial<AppearanceSettings>) => void;\n resetToDefaults: () => void;\n}\n\n/* ============================================================================\n CONSTANTS\n ============================================================================ */\n\nconst STORAGE_KEY = 'void-appearance-settings';\n\nconst BRAND_PINK_HEX: Record<string, string> = {\n default: '#f97316',\n salesmind: '#ff005a',\n};\n\nconst DARK_SURFACE_HEX = '#08040a';\n\nconst DEFAULT_SETTINGS: AppearanceSettings = {\n theme: 'dark',\n brand: 'default',\n navPlacement: 'left',\n density: 'comfortable',\n radius: 'playful',\n customColor: '#f97316', // Default orange as fallback\n};\n\n/* ============================================================================\n UTILITIES\n ============================================================================ */\n\n/** Detect system color scheme preference */\n\n\n/** Convert hex color to RGB triplet string (e.g., \"255, 45, 138\") */\nfunction hexToRgb(hex: string): string {\n // Remove # if present\n const cleanHex = hex.replace(/^#/, '');\n\n // Parse hex values\n const r = parseInt(cleanHex.substring(0, 2), 16);\n const g = parseInt(cleanHex.substring(2, 4), 16);\n const b = parseInt(cleanHex.substring(4, 6), 16);\n\n // Validate parsed values\n if (isNaN(r) || isNaN(g) || isNaN(b)) {\n // Fallback to default orange if parsing fails\n return '249, 115, 22';\n }\n\n return `${r}, ${g}, ${b}`;\n}\n\n/**\n * Compute relative luminance of an RGB triplet using the WCAG 2.1 formula.\n * Returns a value between 0 (black) and 1 (white).\n * @see https://www.w3.org/TR/WCAG21/#dfn-relative-luminance\n */\nfunction relativeLuminance(r: number, g: number, b: number): number {\n const [rs, gs, bs] = [r / 255, g / 255, b / 255].map((c) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4),\n );\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n}\n\n/**\n * Determine whether text on an accent-colored background should be black or white.\n * Returns \"0, 0, 0\" for light accents and \"255, 255, 255\" for dark accents.\n * Uses WCAG 2.1 relative luminance with a 0.179 threshold (equivalent to ~4.5:1\n * contrast ratio against white).\n */\nfunction accentForegroundRgb(hex: string): string {\n const cleanHex = hex.replace(/^#/, '');\n const r = parseInt(cleanHex.substring(0, 2), 16);\n const g = parseInt(cleanHex.substring(2, 4), 16);\n const b = parseInt(cleanHex.substring(4, 6), 16);\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) {\n return '255, 255, 255'; // Fallback: white text\n }\n\n return relativeLuminance(r, g, b) > 0.179 ? '0, 0, 0' : '255, 255, 255';\n}\n\n/** Generate a complementary/secondary color from primary */\nfunction generateSecondaryColor(hex: string): string {\n const cleanHex = hex.replace(/^#/, '');\n const r = parseInt(cleanHex.substring(0, 2), 16);\n const g = parseInt(cleanHex.substring(2, 4), 16);\n const b = parseInt(cleanHex.substring(4, 6), 16);\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) {\n return '255, 208, 0'; // Default yellow\n }\n\n // Shift hue by ~60 degrees for a harmonious secondary\n // Simple approach: rotate RGB channels and boost brightness\n const secondary = {\n r: Math.min(255, g + 50),\n g: Math.min(255, b + 100),\n b: Math.min(255, r),\n };\n\n return `${secondary.r}, ${secondary.g}, ${secondary.b}`;\n}\n\n/** Load settings from localStorage */\nfunction loadSettings(): AppearanceSettings {\n if (typeof window === 'undefined') return DEFAULT_SETTINGS;\n\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored) as Partial<AppearanceSettings>;\n return {\n theme: parsed.theme || DEFAULT_SETTINGS.theme,\n brand: parsed.brand || DEFAULT_SETTINGS.brand,\n navPlacement: parsed.navPlacement || DEFAULT_SETTINGS.navPlacement,\n density: parsed.density || DEFAULT_SETTINGS.density,\n radius: parsed.radius || DEFAULT_SETTINGS.radius,\n customColor: parsed.customColor || DEFAULT_SETTINGS.customColor,\n };\n }\n } catch {\n // Ignore parse errors\n }\n\n // Use default dark preference for initial theme if no stored value\n return {\n ...DEFAULT_SETTINGS,\n theme: 'dark',\n };\n}\n\n/** Save settings to localStorage */\nfunction saveSettings(settings: AppearanceSettings): void {\n if (typeof window === 'undefined') return;\n\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));\n } catch {\n // Ignore storage errors (e.g., private browsing)\n }\n}\n\n/** Apply settings to document.documentElement */\nfunction applySettings(settings: AppearanceSettings): void {\n if (typeof document === 'undefined') return;\n\n const root = document.documentElement;\n\n // Apply data attributes\n root.setAttribute('data-theme', settings.theme);\n root.setAttribute('data-brand', settings.brand);\n root.setAttribute('data-nav', settings.navPlacement);\n root.setAttribute('data-density', settings.density);\n root.setAttribute('data-radius', settings.radius);\n\n // Handle custom brand RGB injection\n if (settings.brand === 'custom') {\n const primaryRgb = hexToRgb(settings.customColor);\n const secondaryRgb = generateSecondaryColor(settings.customColor);\n const foregroundRgb = accentForegroundRgb(settings.customColor);\n\n root.style.setProperty('--custom-accent-rgb', primaryRgb);\n root.style.setProperty('--custom-accent2-rgb', secondaryRgb);\n root.style.setProperty('--custom-accent-fg-rgb', foregroundRgb);\n } else {\n root.style.removeProperty('--custom-accent-rgb');\n root.style.removeProperty('--custom-accent2-rgb');\n root.style.removeProperty('--custom-accent-fg-rgb');\n }\n\n const brandPinkHex =\n settings.brand === 'custom'\n ? settings.customColor\n : BRAND_PINK_HEX[settings.brand] ?? BRAND_PINK_HEX.default;\n\n root.style.setProperty(\n '--brand-pink-readable',\n ensureReadableContrast(brandPinkHex, DARK_SURFACE_HEX),\n );\n}\n\n/** Check if user prefers reduced motion */\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined') return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/* ============================================================================\n CONTEXT\n ============================================================================ */\n\nconst AppearanceContext = createContext<AppearanceContextValue | null>(null);\n\n/* ============================================================================\n PROVIDER COMPONENT\n ============================================================================ */\n\nexport interface AppearanceProviderProps {\n /** Initial settings (overrides localStorage) */\n initialSettings?: Partial<AppearanceSettings>;\n /** Disable localStorage persistence */\n disablePersistence?: boolean;\n /** Children */\n children: React.ReactNode;\n}\n\nexport function AppearanceProvider({\n initialSettings,\n disablePersistence = false,\n children,\n}: AppearanceProviderProps) {\n // Start with deterministic defaults to avoid SSR/client hydration mismatch.\n // localStorage is read after mount in the effect below.\n const [settings, setSettings] = useState<AppearanceSettings>(() => ({\n ...DEFAULT_SETTINGS,\n ...initialSettings,\n }));\n\n // After hydration, sync with localStorage (runs once on mount)\n const [hydrated, setHydrated] = useState(false);\n useEffect(() => {\n if (!disablePersistence) {\n const loaded = loadSettings();\n setSettings({\n ...loaded,\n // initialSettings still take priority over localStorage\n ...initialSettings,\n });\n }\n setHydrated(true);\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Apply settings to DOM whenever they change\n useEffect(() => {\n applySettings(settings);\n if (!disablePersistence && hydrated) {\n saveSettings(settings);\n }\n }, [settings, disablePersistence, hydrated]);\n\n // Listen for system theme changes\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: light)');\n\n const handleChange = (e: MediaQueryListEvent) => {\n // Only auto-switch if user hasn't explicitly set a contrast variant\n setSettings((prev) => {\n if (prev.theme === 'light-contrast' || prev.theme === 'dark-contrast') {\n return prev; // Don't override contrast preferences\n }\n return {\n ...prev,\n theme: e.matches ? 'light' : 'dark',\n };\n });\n };\n\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n }, []);\n\n // Listen for reduced motion preference changes\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');\n\n // Initial check is handled by CSS media queries in tokens.css\n // This effect ensures we respect the preference dynamically\n const handleChange = () => {\n // Re-apply settings to ensure any motion-dependent values are updated\n applySettings(settings);\n };\n\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n }, [settings]);\n\n const setTheme = useCallback((theme: Theme) => {\n setSettings((prev) => ({ ...prev, theme }));\n }, []);\n\n const setBrand = useCallback((brand: Brand) => {\n setSettings((prev) => ({ ...prev, brand }));\n }, []);\n\n const setNavPlacement = useCallback((navPlacement: NavPlacement) => {\n setSettings((prev) => ({ ...prev, navPlacement }));\n }, []);\n\n const setDensity = useCallback((density: Density) => {\n setSettings((prev) => ({ ...prev, density }));\n }, []);\n\n const setRadius = useCallback((radius: Radius) => {\n setSettings((prev) => ({ ...prev, radius }));\n }, []);\n\n const setCustomColor = useCallback((customColor: string) => {\n setSettings((prev) => ({ ...prev, customColor, brand: 'custom' }));\n }, []);\n\n const setAppearance = useCallback((partial: Partial<AppearanceSettings>) => {\n setSettings((prev) => ({ ...prev, ...partial }));\n }, []);\n\n const resetToDefaults = useCallback(() => {\n setSettings(DEFAULT_SETTINGS);\n }, []);\n\n const contextValue: AppearanceContextValue = {\n ...settings,\n setTheme,\n setBrand,\n setNavPlacement,\n setDensity,\n setRadius,\n setCustomColor,\n setAppearance,\n resetToDefaults,\n };\n\n return <AppearanceContext.Provider value={contextValue}>{children}</AppearanceContext.Provider>;\n}\n\n/* ============================================================================\n HOOK\n ============================================================================ */\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport function useAppearance(): AppearanceContextValue {\n const context = useContext(AppearanceContext);\n\n if (!context) {\n throw new Error('useAppearance must be used within an AppearanceProvider');\n }\n\n return context;\n}\n\n/* ============================================================================\n STANDALONE UTILITY (for use outside React, e.g., SSR or initial load)\n ============================================================================ */\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport function initializeAppearance(settings?: Partial<AppearanceSettings>): void {\n const loaded = loadSettings();\n const merged = { ...loaded, ...settings };\n applySettings(merged);\n}\n\n/* ============================================================================\n UTILITY EXPORTS\n ============================================================================ */\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport { hexToRgb, relativeLuminance, accentForegroundRgb, prefersReducedMotion };\n","/**\n * Derive a readable accent text color that meets WCAG AA contrast requirements.\n *\n * Given an accent color intended for small text (e.g., section eyebrow labels),\n * this module computes a lightness-adjusted variant that satisfies a minimum\n * contrast ratio against a given surface color. Hue and saturation are preserved\n * so the result stays recognisably \"on brand\".\n *\n * The WCAG math here intentionally matches `relativeLuminance` in\n * `AppearanceProvider.tsx` (same constants, same 0.03928 threshold) so that\n * contrast decisions are consistent across the design system.\n */\n\n/* ============================================================================\n COLOR PARSING\n ============================================================================ */\n\n/** Parse a 3- or 6-character hex string into an RGB triplet, or null on failure. */\nexport function parseHex(hex: string): [number, number, number] | null {\n const clean = hex.replace(/^#/, '');\n\n let r: number, g: number, b: number;\n\n if (clean.length === 3) {\n r = parseInt(clean[0] + clean[0], 16);\n g = parseInt(clean[1] + clean[1], 16);\n b = parseInt(clean[2] + clean[2], 16);\n } else if (clean.length === 6) {\n r = parseInt(clean.substring(0, 2), 16);\n g = parseInt(clean.substring(2, 4), 16);\n b = parseInt(clean.substring(4, 6), 16);\n } else {\n return null;\n }\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) return null;\n\n return [r, g, b];\n}\n\n/** Format an RGB triplet as a 6-character hex string with `#` prefix. */\nexport function toHex(r: number, g: number, b: number): string {\n const clamp = (n: number) => Math.max(0, Math.min(255, Math.round(n)));\n return (\n '#' +\n [clamp(r), clamp(g), clamp(b)]\n .map((c) => c.toString(16).padStart(2, '0'))\n .join('')\n );\n}\n\n/* ============================================================================\n HSL CONVERSION\n ============================================================================ */\n\n/** Convert an RGB triplet (0–255 each) to HSL (h: 0–360, s/l: 0–1). */\nexport function rgbToHsl(\n r: number,\n g: number,\n b: number,\n): [number, number, number] {\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const l = (max + min) / 2;\n\n if (max === min) return [0, 0, l]; // achromatic\n\n const d = max - min;\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\n let h: number;\n if (max === rn) h = ((gn - bn) / d + (gn < bn ? 6 : 0)) / 6;\n else if (max === gn) h = ((bn - rn) / d + 2) / 6;\n else h = ((rn - gn) / d + 4) / 6;\n\n return [h * 360, s, l];\n}\n\n/** Convert HSL (h: 0–360, s/l: 0–1) back to an RGB triplet (0–255 each). */\nexport function hslToRgb(\n h: number,\n s: number,\n l: number,\n): [number, number, number] {\n const hNorm = ((h % 360) + 360) % 360; // normalise negative hues\n\n if (s === 0) {\n const v = Math.round(l * 255);\n return [v, v, v]; // achromatic\n }\n\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n const hFrac = hNorm / 360;\n\n return [\n Math.round(hue2rgb(p, q, hFrac + 1 / 3) * 255),\n Math.round(hue2rgb(p, q, hFrac) * 255),\n Math.round(hue2rgb(p, q, hFrac - 1 / 3) * 255),\n ];\n}\n\n/* ============================================================================\n WCAG CONTRAST\n ============================================================================ */\n\n/**\n * Compute relative luminance using the WCAG 2.1 formula.\n *\n * Intentionally identical to the implementation in AppearanceProvider.tsx\n * so that all contrast decisions in the DS stay consistent.\n *\n * @see https://www.w3.org/TR/WCAG21/#dfn-relative-luminance\n */\nexport function relativeLuminance(r: number, g: number, b: number): number {\n const [rs, gs, bs] = [r / 255, g / 255, b / 255].map((c) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4),\n );\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n}\n\n/**\n * WCAG 2.1 contrast ratio between two RGB triplets.\n * Result ranges from 1 (identical) to 21 (black vs white).\n */\nexport function contrastRatio(\n fg: [number, number, number],\n bg: [number, number, number],\n): number {\n const l1 = relativeLuminance(...fg);\n const l2 = relativeLuminance(...bg);\n const lighter = Math.max(l1, l2);\n const darker = Math.min(l1, l2);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/* ============================================================================\n MAIN: DERIVE READABLE ACCENT COLOR\n ============================================================================ */\n\n/** Default minimum contrast ratio — WCAG AA for small text. */\nconst DEFAULT_MIN_RATIO = 4.5;\n\n/** Maximum binary-search iterations (convergence is fast; 25 is generous). */\nconst MAX_ITERATIONS = 25;\n\n/**\n * Return an accent color adjusted to meet a minimum contrast ratio against\n * the given surface color. The hue and saturation of the original color are\n * preserved; only lightness is increased (for dark surfaces) or decreased\n * (for light surfaces) until the target ratio is reached.\n *\n * If the original color already satisfies the ratio, it is returned as-is.\n * If the input is malformed, `fallbackHex` (default: the original input) is\n * returned so consumers degrade gracefully.\n *\n * @param accentHex Foreground accent color as a 3- or 6-char hex string\n * @param surfaceHex Background surface color to contrast against\n * @param minRatio Minimum WCAG contrast ratio (default 4.5 for AA small text)\n * @returns Adjusted hex color string\n */\nexport function ensureReadableContrast(\n accentHex: string,\n surfaceHex: string,\n minRatio = DEFAULT_MIN_RATIO,\n): string {\n const fg = parseHex(accentHex);\n const bg = parseHex(surfaceHex);\n\n // Guard: if either input is unparseable, return the original accent unchanged.\n if (!fg || !bg) return accentHex;\n\n // Fast path: already meets contrast — no adjustment needed.\n if (contrastRatio(fg, bg) >= minRatio) return accentHex;\n\n const [h, s] = rgbToHsl(...fg);\n const bgLuminance = relativeLuminance(...bg);\n\n // Determine adjustment direction:\n // On a dark surface (low luminance) we lighten; on a light surface we darken.\n const shouldLighten = bgLuminance < 0.5;\n\n const currentLightness = rgbToHsl(...fg)[2];\n let lo: number, hi: number;\n if (shouldLighten) {\n lo = currentLightness;\n hi = 1.0;\n } else {\n lo = 0;\n hi = currentLightness;\n }\n\n let bestHex = accentHex;\n\n for (let i = 0; i < MAX_ITERATIONS; i++) {\n const mid = (lo + hi) / 2;\n const [rr, gg, bb] = hslToRgb(h, s, mid);\n const ratio = contrastRatio([rr, gg, bb], bg);\n\n if (ratio >= minRatio) {\n bestHex = toHex(rr, gg, bb);\n if (shouldLighten) hi = mid;\n else lo = mid;\n } else {\n if (shouldLighten) lo = mid;\n else hi = mid;\n }\n }\n\n return bestHex;\n}\n","import React, { useId } from 'react';\nimport clsx from 'clsx';\nimport {\n useAppearance,\n Theme,\n Brand,\n NavPlacement,\n Density,\n Radius,\n} from '../../theme/AppearanceProvider';\nimport './AppearancePanel.css';\n\n/* ============================================================================\n APPEARANCE PANEL — Internal Settings UI\n ============================================================================ */\n\n/** All translatable labels for the AppearancePanel. */\nexport interface AppearancePanelLabels {\n /** Panel heading. @default \"Appearance Settings\" */\n title?: string;\n /** Theme section heading. @default \"Theme\" */\n themeHeading?: string;\n /** Brand section heading. @default \"Brand\" */\n brandHeading?: string;\n /** Density section heading. @default \"Density\" */\n densityHeading?: string;\n /** Geometry section heading. @default \"Geometry\" */\n geometryHeading?: string;\n /** Navigation section heading. @default \"Navigation Layout\" */\n navHeading?: string;\n /** Accent color label (shown for Custom brand). @default \"Accent Color\" */\n accentColorLabel?: string;\n /** Reset button text. @default \"Reset to Defaults\" */\n resetLabel?: string;\n\n /* Theme options */\n themeLight?: string;\n themeLightContrast?: string;\n themeDark?: string;\n themeDarkContrast?: string;\n\n /* Brand options */\n brandDefault?: string;\n brandDefaultDescription?: string;\n brandSalesmind?: string;\n brandSalesmindDescription?: string;\n brandCustom?: string;\n brandCustomDescription?: string;\n\n /* Density options */\n densityComfortable?: string;\n densityComfortableDescription?: string;\n densityCompact?: string;\n densityCompactDescription?: string;\n\n /* Radius / geometry options */\n radiusPlayful?: string;\n radiusPlayfulDescription?: string;\n radiusSharp?: string;\n radiusSharpDescription?: string;\n\n /* Navigation options */\n navLeft?: string;\n navRight?: string;\n navBottom?: string;\n}\n\nexport interface AppearancePanelProps {\n /** Custom class name */\n className?: string;\n /** Override default English labels for i18n. */\n labels?: AppearancePanelLabels;\n}\n\nexport const AppearancePanel = React.forwardRef<HTMLDivElement, AppearancePanelProps>(\n ({ className, labels: l }, ref) => {\n const {\n theme,\n brand,\n navPlacement,\n density,\n radius,\n customColor,\n setTheme,\n setBrand,\n setNavPlacement,\n setDensity,\n setRadius,\n setCustomColor,\n resetToDefaults,\n } = useAppearance();\n\n // Generate unique IDs for accessibility\n const colorPickerId = useId();\n\n // Build option arrays from labels (fallback to English defaults)\n const themeOptions: { value: Theme; label: string }[] = [\n { value: 'light', label: l?.themeLight ?? 'Light' },\n { value: 'light-contrast', label: l?.themeLightContrast ?? 'Light (High Contrast)' },\n { value: 'dark', label: l?.themeDark ?? 'Dark' },\n { value: 'dark-contrast', label: l?.themeDarkContrast ?? 'Dark (High Contrast)' },\n ];\n\n const brandOptions: { value: Brand; label: string; description: string }[] = [\n { value: 'default', label: l?.brandDefault ?? 'Default', description: l?.brandDefaultDescription ?? 'Warm Intelligence' },\n { value: 'salesmind', label: l?.brandSalesmind ?? 'SalesMind', description: l?.brandSalesmindDescription ?? 'Pink-red + Gold' },\n { value: 'custom', label: l?.brandCustom ?? 'Custom', description: l?.brandCustomDescription ?? 'Your color' },\n ];\n\n const navOptions: { value: NavPlacement; label: string }[] = [\n { value: 'left', label: l?.navLeft ?? 'Left Sidebar' },\n { value: 'right', label: l?.navRight ?? 'Right Sidebar' },\n { value: 'bottom', label: l?.navBottom ?? 'Bottom Tabs' },\n ];\n\n const densityOptions: { value: Density; label: string; description: string }[] = [\n { value: 'comfortable', label: l?.densityComfortable ?? 'Comfortable', description: l?.densityComfortableDescription ?? 'Generous spacing' },\n { value: 'compact', label: l?.densityCompact ?? 'Compact', description: l?.densityCompactDescription ?? 'Higher density' },\n ];\n\n const radiusOptions: { value: Radius; label: string; description: string }[] = [\n { value: 'playful', label: l?.radiusPlayful ?? 'Playful', description: l?.radiusPlayfulDescription ?? 'Rounded corners' },\n { value: 'sharp', label: l?.radiusSharp ?? 'Sharp', description: l?.radiusSharpDescription ?? 'Technical feel' },\n ];\n\n return (\n <div ref={ref} className={clsx('ds-appearance-panel', className)}>\n <h3 className=\"ds-appearance-panel__title\">{l?.title ?? 'Appearance Settings'}</h3>\n\n {/* Theme Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.themeHeading ?? 'Theme'}</legend>\n <div className=\"ds-appearance-panel__options\">\n {themeOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n theme === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"theme\"\n value={option.value}\n checked={theme === option.value}\n onChange={() => setTheme(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n </label>\n ))}\n </div>\n </fieldset>\n\n {/* Brand Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.brandHeading ?? 'Brand'}</legend>\n <div className=\"ds-appearance-panel__options\">\n {brandOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n brand === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"brand\"\n value={option.value}\n checked={brand === option.value}\n onChange={() => setBrand(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-content\">\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n <span className=\"ds-appearance-panel__option-description\">\n {option.description}\n </span>\n </span>\n </label>\n ))}\n </div>\n\n {/* Color Picker (shown only for Custom brand) */}\n {brand === 'custom' && (\n <div className=\"ds-appearance-panel__color-picker\">\n <label htmlFor={colorPickerId} className=\"ds-appearance-panel__color-label\">\n {l?.accentColorLabel ?? 'Accent Color'}\n </label>\n <div className=\"ds-appearance-panel__color-input-wrapper\">\n <input\n type=\"color\"\n id={colorPickerId}\n value={customColor}\n onChange={(e) => setCustomColor(e.target.value)}\n className=\"ds-appearance-panel__color-input\"\n />\n <span className=\"ds-appearance-panel__color-value\">\n {customColor.toUpperCase()}\n </span>\n </div>\n </div>\n )}\n </fieldset>\n\n {/* Density Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.densityHeading ?? 'Density'}</legend>\n <div className=\"ds-appearance-panel__options ds-appearance-panel__options--row\">\n {densityOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n 'ds-appearance-panel__option--toggle',\n density === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"density\"\n value={option.value}\n checked={density === option.value}\n onChange={() => setDensity(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-content\">\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n <span className=\"ds-appearance-panel__option-description\">\n {option.description}\n </span>\n </span>\n </label>\n ))}\n </div>\n </fieldset>\n\n {/* Geometry Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.geometryHeading ?? 'Geometry'}</legend>\n <div className=\"ds-appearance-panel__options ds-appearance-panel__options--row\">\n {radiusOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n 'ds-appearance-panel__option--toggle',\n radius === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"radius\"\n value={option.value}\n checked={radius === option.value}\n onChange={() => setRadius(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-content\">\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n <span className=\"ds-appearance-panel__option-description\">\n {option.description}\n </span>\n </span>\n </label>\n ))}\n </div>\n </fieldset>\n\n {/* Navigation Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.navHeading ?? 'Navigation Layout'}</legend>\n <div className=\"ds-appearance-panel__options\">\n {navOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n navPlacement === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"nav\"\n value={option.value}\n checked={navPlacement === option.value}\n onChange={() => setNavPlacement(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n </label>\n ))}\n </div>\n </fieldset>\n\n {/* Reset Button */}\n <button type=\"button\" onClick={resetToDefaults} className=\"ds-appearance-panel__reset\">\n {l?.resetLabel ?? 'Reset to Defaults'}\n </button>\n </div>\n );\n },\n);\n\nAppearancePanel.displayName = 'AppearancePanel';\n"]}
@@ -10,13 +10,19 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
10
  var clsx__default = /*#__PURE__*/_interopDefault(clsx);
11
11
 
12
12
  var SectionHeader = react.forwardRef(
13
- ({ title, subtitle, eyebrow, align = "center", className, ...props }, ref) => {
13
+ ({ title, subtitle, eyebrow, align = "center", size = "default", className, ...props }, ref) => {
14
14
  if (!title && !subtitle && !eyebrow) return null;
15
15
  return /* @__PURE__ */ jsxRuntime.jsxs(
16
16
  "header",
17
17
  {
18
18
  ref,
19
- className: clsx__default.default("ds-section-header", `ds-section-header--${align}`, className),
19
+ className: clsx__default.default(
20
+ "ds-section-header",
21
+ `ds-section-header--${align}`,
22
+ size === "compact" && "ds-section-header--compact",
23
+ size === "large" && "ds-section-header--large",
24
+ className
25
+ ),
20
26
  ...props,
21
27
  children: [
22
28
  eyebrow && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ds-section-header__eyebrow", children: eyebrow }),
@@ -66,4 +72,4 @@ SectionShell.displayName = "SectionShell";
66
72
  exports.SectionHeader = SectionHeader;
67
73
  exports.SectionShell = SectionShell;
68
74
  //# sourceMappingURL=out.js.map
69
- //# sourceMappingURL=chunk-EM7JHRYW.cjs.map
75
+ //# sourceMappingURL=chunk-BJZ2DKS5.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/SectionShell/SectionShell.tsx"],"names":[],"mappings":";;;;;AAAA,SAAgB,kBAAkC;AAClD,OAAO,UAAU;AAqBX,SAWc,KAXd;AALC,IAAM,gBAAgB;AAAA,EAC3B,CAAC,EAAE,OAAO,UAAU,SAAS,QAAQ,UAAU,OAAO,WAAW,WAAW,GAAG,MAAM,GAAG,QAAQ;AAC9F,QAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAS,QAAO;AAE5C,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,sBAAsB,KAAK;AAAA,UAC3B,SAAS,aAAa;AAAA,UACtB,SAAS,WAAW;AAAA,UACpB;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEH;AAAA,qBAAW,oBAAC,UAAK,WAAU,8BAA8B,mBAAQ;AAAA,UACjE,SAAS,oBAAC,QAAG,WAAU,4BAA4B,iBAAM;AAAA,UACzD,YAAY,oBAAC,OAAE,WAAU,+BAA+B,oBAAS;AAAA;AAAA;AAAA,IACpE;AAAA,EAEJ;AACF;AACA,cAAc,cAAc;AAcrB,IAAM,eAAe;AAAA,EAC1B,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,UAAU;AAAA,IACV;AAAA,IACA,iBAAiB;AAAA,IACjB,GAAG;AAAA,EACL,GACA,QACG;AACH,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,kBAAkB,UAAU;AAAA,UAC5B,uBAAuB,OAAO;AAAA,UAC9B;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEJ;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,kBAAkB,UAAU,SAAU;AAAA,YAC5C,OAAO,kBAAkB,kBAAkB;AAAA,YAE1C;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AACA,aAAa,cAAc","sourcesContent":["import React, { forwardRef, HTMLAttributes } from 'react';\nimport clsx from 'clsx';\nimport { Container } from '../LayoutPrimitives';\nimport './SectionShell.css';\n\n/* ============================================================================\n Section Header Component\n ============================================================================ */\n\nexport interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n title?: React.ReactNode;\n subtitle?: React.ReactNode;\n eyebrow?: React.ReactNode;\n align?: 'left' | 'center' | 'right';\n size?: 'compact' | 'default' | 'large';\n}\n\nexport const SectionHeader = forwardRef<HTMLDivElement, SectionHeaderProps>(\n ({ title, subtitle, eyebrow, align = 'center', size = 'default', className, ...props }, ref) => {\n if (!title && !subtitle && !eyebrow) return null;\n\n return (\n <header\n ref={ref}\n className={clsx(\n 'ds-section-header',\n `ds-section-header--${align}`,\n size === 'compact' && 'ds-section-header--compact',\n size === 'large' && 'ds-section-header--large',\n className,\n )}\n {...props}\n >\n {eyebrow && <span className=\"ds-section-header__eyebrow\">{eyebrow}</span>}\n {title && <h2 className=\"ds-section-header__title\">{title}</h2>}\n {subtitle && <p className=\"ds-section-header__subtitle\">{subtitle}</p>}\n </header>\n );\n },\n);\nSectionHeader.displayName = 'SectionHeader';\n\n/* ============================================================================\n Section Shell Component\n ============================================================================ */\n\nexport interface SectionShellProps extends HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n background?: 'default' | 'muted' | 'brand' | 'transparent' | 'dark';\n padding?: 'none' | 'sm' | 'md' | 'lg';\n containerSize?: 'sm' | 'md' | 'lg' | 'xl' | 'fluid'; // Maps to Container max-width\n containerFluid?: boolean;\n}\n\nexport const SectionShell = forwardRef<HTMLDivElement, SectionShellProps>(\n (\n {\n className,\n children,\n background = 'default',\n padding = 'md',\n containerSize,\n containerFluid = false,\n ...props\n },\n ref,\n ) => {\n return (\n <section\n ref={ref}\n className={clsx(\n 'ds-section',\n `ds-section--bg-${background}`,\n `ds-section--padding-${padding}`,\n className,\n )}\n {...props}\n >\n <Container\n size={containerSize === 'fluid' ? 'full' : (containerSize as 'sm' | 'md' | 'lg' | 'xl' | undefined)}\n fluid={containerFluid || containerSize === 'fluid'}\n >\n {children}\n </Container>\n </section>\n );\n },\n);\nSectionShell.displayName = 'SectionShell';\n"]}
@@ -0,0 +1,200 @@
1
+ // src/tokens/motion.ts
2
+ var DURATION = {
3
+ micro: 0.15,
4
+ // 150ms
5
+ short: 0.25,
6
+ // 250ms
7
+ medium: 0.5,
8
+ // 500ms
9
+ long: 1
10
+ // 1000ms
11
+ };
12
+ var EASING = {
13
+ standard: [0.16, 1, 0.3, 1],
14
+ // Smooth, premium feel
15
+ emphasis: [0.34, 1.56, 0.64, 1],
16
+ // Slight spring/overshoot
17
+ exit: [0.4, 0, 0.2, 1],
18
+ // Quick, decisive exit
19
+ linear: [0, 0, 1, 1]
20
+ };
21
+ var TRANSITION = {
22
+ standard: {
23
+ duration: DURATION.medium,
24
+ ease: EASING.standard
25
+ },
26
+ emphasis: {
27
+ duration: DURATION.medium,
28
+ ease: EASING.emphasis
29
+ },
30
+ quick: {
31
+ duration: DURATION.short,
32
+ ease: EASING.standard
33
+ },
34
+ spring: {
35
+ type: "spring",
36
+ stiffness: 200,
37
+ damping: 20
38
+ }
39
+ };
40
+ var DISTANCE = {
41
+ sm: 4,
42
+ md: 12,
43
+ lg: 24,
44
+ xl: 48
45
+ };
46
+ var VARIANTS = {
47
+ fadeIn: {
48
+ hidden: { opacity: 0 },
49
+ visible: { opacity: 1, transition: { duration: DURATION.medium, ease: EASING.standard } }
50
+ },
51
+ fadeUp: {
52
+ hidden: { opacity: 0, y: 12 },
53
+ visible: { opacity: 1, y: 0, transition: { duration: DURATION.medium, ease: EASING.standard } }
54
+ },
55
+ fadeDown: {
56
+ hidden: { opacity: 0, y: -12 },
57
+ visible: { opacity: 1, y: 0, transition: { duration: DURATION.medium, ease: EASING.standard } }
58
+ },
59
+ scaleIn: {
60
+ hidden: { opacity: 0, scale: 0.95 },
61
+ visible: {
62
+ opacity: 1,
63
+ scale: 1,
64
+ transition: { duration: DURATION.short, ease: EASING.emphasis }
65
+ }
66
+ },
67
+ slideLeft: {
68
+ hidden: { opacity: 0, x: DISTANCE.lg },
69
+ visible: { opacity: 1, x: 0, transition: { duration: DURATION.medium, ease: EASING.standard } }
70
+ },
71
+ slideRight: {
72
+ hidden: { opacity: 0, x: -DISTANCE.lg },
73
+ visible: { opacity: 1, x: 0, transition: { duration: DURATION.medium, ease: EASING.standard } }
74
+ },
75
+ staggerContainer: {
76
+ hidden: { opacity: 0 },
77
+ visible: {
78
+ opacity: 1,
79
+ transition: {
80
+ staggerChildren: 0.08,
81
+ delayChildren: 0.1
82
+ }
83
+ }
84
+ },
85
+ pulse: {
86
+ hidden: { scale: 1 },
87
+ visible: {
88
+ scale: [1, 1.05, 1],
89
+ transition: { duration: 1.5, repeat: Infinity, ease: "easeInOut" }
90
+ }
91
+ },
92
+ impact: {
93
+ hidden: { scale: 1 },
94
+ trigger: {
95
+ scale: [1, 0.95, 1.05, 1],
96
+ transition: { duration: 0.4, ease: "backOut" }
97
+ }
98
+ }
99
+ };
100
+ var HERO_ENTRANCE = {
101
+ container: {
102
+ variants: {
103
+ hidden: { opacity: 1 },
104
+ visible: {
105
+ opacity: 1,
106
+ transition: {
107
+ staggerChildren: 0.12,
108
+ delayChildren: 0.05
109
+ }
110
+ }
111
+ }
112
+ },
113
+ child: {
114
+ variants: VARIANTS.fadeUp
115
+ },
116
+ delays: {
117
+ eyebrow: 0,
118
+ title: 0.05,
119
+ subtitle: 0.17,
120
+ cta: 0.29,
121
+ media: 0.41
122
+ }
123
+ };
124
+ var SECTION_REVEAL = {
125
+ container: {
126
+ variants: VARIANTS.staggerContainer
127
+ },
128
+ content: {
129
+ variants: VARIANTS.fadeUp
130
+ },
131
+ viewportMargin: "-15%"
132
+ };
133
+ var CARD_HOVER = {
134
+ rest: { y: 0, scale: 1 },
135
+ hover: {
136
+ y: -4,
137
+ scale: 1.01,
138
+ transition: { duration: DURATION.short, ease: EASING.standard }
139
+ }
140
+ };
141
+ var PANEL_CROSSFADE = {
142
+ initial: { opacity: 0, y: 8 },
143
+ animate: {
144
+ opacity: 1,
145
+ y: 0,
146
+ transition: { duration: DURATION.short, ease: EASING.standard }
147
+ },
148
+ exit: {
149
+ opacity: 0,
150
+ y: -8,
151
+ transition: { duration: DURATION.micro, ease: EASING.exit }
152
+ }
153
+ };
154
+ var TAB_SLIDE = {
155
+ transition: TRANSITION.spring,
156
+ layout: true
157
+ };
158
+ var PRESETS = {
159
+ heroEntrance: HERO_ENTRANCE,
160
+ sectionReveal: SECTION_REVEAL,
161
+ cardHover: CARD_HOVER,
162
+ panelCrossfade: PANEL_CROSSFADE,
163
+ tabSlide: TAB_SLIDE
164
+ };
165
+ var REDUCED_VARIANTS = {
166
+ fadeOnly: {
167
+ hidden: { opacity: 0 },
168
+ visible: { opacity: 1, transition: { duration: DURATION.short } }
169
+ },
170
+ none: {
171
+ hidden: { opacity: 1 },
172
+ visible: { opacity: 1 }
173
+ }
174
+ };
175
+ var REDUCED_PANEL_CROSSFADE = {
176
+ initial: { opacity: 0 },
177
+ animate: { opacity: 1, transition: { duration: DURATION.micro } },
178
+ exit: { opacity: 0, transition: { duration: DURATION.micro } }
179
+ };
180
+ var VARIANT_MAP = {
181
+ fadeIn: VARIANTS.fadeIn,
182
+ fadeUp: VARIANTS.fadeUp,
183
+ fadeDown: VARIANTS.fadeDown,
184
+ scaleIn: VARIANTS.scaleIn,
185
+ slideLeft: VARIANTS.slideLeft,
186
+ slideRight: VARIANTS.slideRight
187
+ };
188
+ var MOTION = {
189
+ DURATION,
190
+ EASING,
191
+ TRANSITION,
192
+ VARIANTS,
193
+ DISTANCE,
194
+ PRESETS,
195
+ REDUCED_VARIANTS
196
+ };
197
+
198
+ export { CARD_HOVER, DISTANCE, DURATION, EASING, HERO_ENTRANCE, MOTION, PANEL_CROSSFADE, PRESETS, REDUCED_PANEL_CROSSFADE, REDUCED_VARIANTS, SECTION_REVEAL, TAB_SLIDE, TRANSITION, VARIANTS, VARIANT_MAP };
199
+ //# sourceMappingURL=out.js.map
200
+ //# sourceMappingURL=chunk-BUTQSDQH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tokens/motion.ts"],"names":[],"mappings":";AAOO,IAAM,WAAW;AAAA,EACtB,OAAO;AAAA;AAAA,EACP,OAAO;AAAA;AAAA,EACP,QAAQ;AAAA;AAAA,EACR,MAAM;AAAA;AACR;AAKO,IAAM,SAAS;AAAA,EACpB,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC;AAAA;AAAA,EAC1B,UAAU,CAAC,MAAM,MAAM,MAAM,CAAC;AAAA;AAAA,EAC9B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;AAAA;AAAA,EACrB,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC;AACrB;AAKO,IAAM,aAAa;AAAA,EACxB,UAAU;AAAA,IACR,UAAU,SAAS;AAAA,IACnB,MAAM,OAAO;AAAA,EACf;AAAA,EACA,UAAU;AAAA,IACR,UAAU,SAAS;AAAA,IACnB,MAAM,OAAO;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,UAAU,SAAS;AAAA,IACnB,MAAM,OAAO;AAAA,EACf;AAAA,EACA,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,EACX;AACF;AAKO,IAAM,WAAW;AAAA,EACtB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAKO,IAAM,WAAW;AAAA,EACtB,QAAQ;AAAA,IACN,QAAQ,EAAE,SAAS,EAAE;AAAA,IACrB,SAAS,EAAE,SAAS,GAAG,YAAY,EAAE,UAAU,SAAS,QAAQ,MAAM,OAAO,SAAS,EAAE;AAAA,EAC1F;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ,EAAE,SAAS,GAAG,GAAG,GAAG;AAAA,IAC5B,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG,YAAY,EAAE,UAAU,SAAS,QAAQ,MAAM,OAAO,SAAS,EAAE;AAAA,EAChG;AAAA,EACA,UAAU;AAAA,IACR,QAAQ,EAAE,SAAS,GAAG,GAAG,IAAI;AAAA,IAC7B,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG,YAAY,EAAE,UAAU,SAAS,QAAQ,MAAM,OAAO,SAAS,EAAE;AAAA,EAChG;AAAA,EACA,SAAS;AAAA,IACP,QAAQ,EAAE,SAAS,GAAG,OAAO,KAAK;AAAA,IAClC,SAAS;AAAA,MACP,SAAS;AAAA,MACT,OAAO;AAAA,MACP,YAAY,EAAE,UAAU,SAAS,OAAO,MAAM,OAAO,SAAS;AAAA,IAChE;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT,QAAQ,EAAE,SAAS,GAAG,GAAG,SAAS,GAAG;AAAA,IACrC,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG,YAAY,EAAE,UAAU,SAAS,QAAQ,MAAM,OAAO,SAAS,EAAE;AAAA,EAChG;AAAA,EACA,YAAY;AAAA,IACV,QAAQ,EAAE,SAAS,GAAG,GAAG,CAAC,SAAS,GAAG;AAAA,IACtC,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG,YAAY,EAAE,UAAU,SAAS,QAAQ,MAAM,OAAO,SAAS,EAAE;AAAA,EAChG;AAAA,EACA,kBAAkB;AAAA,IAChB,QAAQ,EAAE,SAAS,EAAE;AAAA,IACrB,SAAS;AAAA,MACP,SAAS;AAAA,MACT,YAAY;AAAA,QACV,iBAAiB;AAAA,QACjB,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,QAAQ,EAAE,OAAO,EAAE;AAAA,IACnB,SAAS;AAAA,MACP,OAAO,CAAC,GAAG,MAAM,CAAC;AAAA,MAClB,YAAY,EAAE,UAAU,KAAK,QAAQ,UAAU,MAAM,YAAY;AAAA,IACnE;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ,EAAE,OAAO,EAAE;AAAA,IACnB,SAAS;AAAA,MACP,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC;AAAA,MACxB,YAAY,EAAE,UAAU,KAAK,MAAM,UAAU;AAAA,IAC/C;AAAA,EACF;AACF;AAGO,IAAM,gBAAgB;AAAA,EAC3B,WAAW;AAAA,IACT,UAAU;AAAA,MACR,QAAQ,EAAE,SAAS,EAAE;AAAA,MACrB,SAAS;AAAA,QACP,SAAS;AAAA,QACT,YAAY;AAAA,UACV,iBAAiB;AAAA,UACjB,eAAe;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,UAAU,SAAS;AAAA,EACrB;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,IACP,UAAU;AAAA,IACV,KAAK;AAAA,IACL,OAAO;AAAA,EACT;AACF;AAEO,IAAM,iBAAiB;AAAA,EAC5B,WAAW;AAAA,IACT,UAAU,SAAS;AAAA,EACrB;AAAA,EACA,SAAS;AAAA,IACP,UAAU,SAAS;AAAA,EACrB;AAAA,EACA,gBAAgB;AAClB;AAEO,IAAM,aAAa;AAAA,EACxB,MAAM,EAAE,GAAG,GAAG,OAAO,EAAE;AAAA,EACvB,OAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO;AAAA,IACP,YAAY,EAAE,UAAU,SAAS,OAAO,MAAM,OAAO,SAAS;AAAA,EAChE;AACF;AAEO,IAAM,kBAAkB;AAAA,EAC7B,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,EAC5B,SAAS;AAAA,IACP,SAAS;AAAA,IACT,GAAG;AAAA,IACH,YAAY,EAAE,UAAU,SAAS,OAAO,MAAM,OAAO,SAAS;AAAA,EAChE;AAAA,EACA,MAAM;AAAA,IACJ,SAAS;AAAA,IACT,GAAG;AAAA,IACH,YAAY,EAAE,UAAU,SAAS,OAAO,MAAM,OAAO,KAAK;AAAA,EAC5D;AACF;AAEO,IAAM,YAAY;AAAA,EACvB,YAAY,WAAW;AAAA,EACvB,QAAQ;AACV;AAEO,IAAM,UAAU;AAAA,EACrB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,UAAU;AACZ;AAEO,IAAM,mBAAmB;AAAA,EAC9B,UAAU;AAAA,IACR,QAAQ,EAAE,SAAS,EAAE;AAAA,IACrB,SAAS,EAAE,SAAS,GAAG,YAAY,EAAE,UAAU,SAAS,MAAM,EAAE;AAAA,EAClE;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ,EAAE,SAAS,EAAE;AAAA,IACrB,SAAS,EAAE,SAAS,EAAE;AAAA,EACxB;AACF;AAEO,IAAM,0BAA0B;AAAA,EACrC,SAAS,EAAE,SAAS,EAAE;AAAA,EACtB,SAAS,EAAE,SAAS,GAAG,YAAY,EAAE,UAAU,SAAS,MAAM,EAAE;AAAA,EAChE,MAAM,EAAE,SAAS,GAAG,YAAY,EAAE,UAAU,SAAS,MAAM,EAAE;AAC/D;AAIO,IAAM,cAAc;AAAA,EACzB,QAAQ,SAAS;AAAA,EACjB,QAAQ,SAAS;AAAA,EACjB,UAAU,SAAS;AAAA,EACnB,SAAS,SAAS;AAAA,EAClB,WAAW,SAAS;AAAA,EACpB,YAAY,SAAS;AACvB;AAEO,IAAM,SAAS;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF","sourcesContent":["/* ============================================================================\n MOTION TOKENS & FRAMER CONFIG\n ============================================================================ */\n\n/**\n * Duration tokens (seconds) for Framer Motion\n */\nexport const DURATION = {\n micro: 0.15, // 150ms\n short: 0.25, // 250ms\n medium: 0.5, // 500ms\n long: 1.0, // 1000ms\n} as const;\n\n/**\n * Easing definitions (cubic-bezier arrays) for Framer Motion\n */\nexport const EASING = {\n standard: [0.16, 1, 0.3, 1], // Smooth, premium feel\n emphasis: [0.34, 1.56, 0.64, 1], // Slight spring/overshoot\n exit: [0.4, 0, 0.2, 1], // Quick, decisive exit\n linear: [0, 0, 1, 1],\n} as const;\n\n/**\n * Standard transitions for Framer Motion\n */\nexport const TRANSITION = {\n standard: {\n duration: DURATION.medium,\n ease: EASING.standard,\n },\n emphasis: {\n duration: DURATION.medium,\n ease: EASING.emphasis,\n },\n quick: {\n duration: DURATION.short,\n ease: EASING.standard,\n },\n spring: {\n type: 'spring',\n stiffness: 200,\n damping: 20,\n },\n} as const;\n\n/**\n * Layout Tokens\n */\nexport const DISTANCE = {\n sm: 4,\n md: 12,\n lg: 24,\n xl: 48,\n} as const;\n\n/**\n * Reusable Variants for Framer Motion\n */\nexport const VARIANTS = {\n fadeIn: {\n hidden: { opacity: 0 },\n visible: { opacity: 1, transition: { duration: DURATION.medium, ease: EASING.standard } },\n },\n fadeUp: {\n hidden: { opacity: 0, y: 12 },\n visible: { opacity: 1, y: 0, transition: { duration: DURATION.medium, ease: EASING.standard } },\n },\n fadeDown: {\n hidden: { opacity: 0, y: -12 },\n visible: { opacity: 1, y: 0, transition: { duration: DURATION.medium, ease: EASING.standard } },\n },\n scaleIn: {\n hidden: { opacity: 0, scale: 0.95 },\n visible: {\n opacity: 1,\n scale: 1,\n transition: { duration: DURATION.short, ease: EASING.emphasis },\n },\n },\n slideLeft: {\n hidden: { opacity: 0, x: DISTANCE.lg },\n visible: { opacity: 1, x: 0, transition: { duration: DURATION.medium, ease: EASING.standard } },\n },\n slideRight: {\n hidden: { opacity: 0, x: -DISTANCE.lg },\n visible: { opacity: 1, x: 0, transition: { duration: DURATION.medium, ease: EASING.standard } },\n },\n staggerContainer: {\n hidden: { opacity: 0 },\n visible: {\n opacity: 1,\n transition: {\n staggerChildren: 0.08,\n delayChildren: 0.1,\n },\n },\n },\n pulse: {\n hidden: { scale: 1 },\n visible: {\n scale: [1, 1.05, 1],\n transition: { duration: 1.5, repeat: Infinity, ease: 'easeInOut' },\n },\n },\n impact: {\n hidden: { scale: 1 },\n trigger: {\n scale: [1, 0.95, 1.05, 1],\n transition: { duration: 0.4, ease: 'backOut' },\n },\n },\n} as const;\n\n/** Stagger: eyebrow → title → subtitle → CTAs → media */\nexport const HERO_ENTRANCE = {\n container: {\n variants: {\n hidden: { opacity: 1 },\n visible: {\n opacity: 1,\n transition: {\n staggerChildren: 0.12,\n delayChildren: 0.05,\n },\n },\n },\n },\n child: {\n variants: VARIANTS.fadeUp,\n },\n delays: {\n eyebrow: 0,\n title: 0.05,\n subtitle: 0.17,\n cta: 0.29,\n media: 0.41,\n },\n} as const;\n\nexport const SECTION_REVEAL = {\n container: {\n variants: VARIANTS.staggerContainer,\n },\n content: {\n variants: VARIANTS.fadeUp,\n },\n viewportMargin: '-15%' as const,\n} as const;\n\nexport const CARD_HOVER = {\n rest: { y: 0, scale: 1 },\n hover: {\n y: -4,\n scale: 1.01,\n transition: { duration: DURATION.short, ease: EASING.standard },\n },\n} as const;\n\nexport const PANEL_CROSSFADE = {\n initial: { opacity: 0, y: 8 },\n animate: {\n opacity: 1,\n y: 0,\n transition: { duration: DURATION.short, ease: EASING.standard },\n },\n exit: {\n opacity: 0,\n y: -8,\n transition: { duration: DURATION.micro, ease: EASING.exit },\n },\n} as const;\n\nexport const TAB_SLIDE = {\n transition: TRANSITION.spring,\n layout: true as const,\n} as const;\n\nexport const PRESETS = {\n heroEntrance: HERO_ENTRANCE,\n sectionReveal: SECTION_REVEAL,\n cardHover: CARD_HOVER,\n panelCrossfade: PANEL_CROSSFADE,\n tabSlide: TAB_SLIDE,\n} as const;\n\nexport const REDUCED_VARIANTS = {\n fadeOnly: {\n hidden: { opacity: 0 },\n visible: { opacity: 1, transition: { duration: DURATION.short } },\n },\n none: {\n hidden: { opacity: 1 },\n visible: { opacity: 1 },\n },\n} as const;\n\nexport const REDUCED_PANEL_CROSSFADE = {\n initial: { opacity: 0 },\n animate: { opacity: 1, transition: { duration: DURATION.micro } },\n exit: { opacity: 0, transition: { duration: DURATION.micro } },\n} as const;\n\nexport type AnimationVariant = 'fadeIn' | 'fadeUp' | 'fadeDown' | 'scaleIn' | 'slideLeft' | 'slideRight';\n\nexport const VARIANT_MAP = {\n fadeIn: VARIANTS.fadeIn,\n fadeUp: VARIANTS.fadeUp,\n fadeDown: VARIANTS.fadeDown,\n scaleIn: VARIANTS.scaleIn,\n slideLeft: VARIANTS.slideLeft,\n slideRight: VARIANTS.slideRight,\n} satisfies Record<AnimationVariant, unknown>;\n\nexport const MOTION = {\n DURATION,\n EASING,\n TRANSITION,\n VARIANTS,\n DISTANCE,\n PRESETS,\n REDUCED_VARIANTS,\n} as const;\n"]}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkMQRB634A_cjs = require('./chunk-MQRB634A.cjs');
4
- var chunkEM7JHRYW_cjs = require('./chunk-EM7JHRYW.cjs');
4
+ var chunkBJZ2DKS5_cjs = require('./chunk-BJZ2DKS5.cjs');
5
5
  var chunkMDB2WCRQ_cjs = require('./chunk-MDB2WCRQ.cjs');
6
6
  var react = require('react');
7
7
  var clsx = require('clsx');
@@ -28,6 +28,7 @@ var HeroSection = react.forwardRef(
28
28
  withGrid = false,
29
29
  withGlow = false,
30
30
  align,
31
+ padding = "lg",
31
32
  className,
32
33
  children,
33
34
  ...props
@@ -50,7 +51,7 @@ var HeroSection = react.forwardRef(
50
51
  floatingElement && /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx__default.default("ds-hero__float", `ds-hero__float--${floatingPosition}`), children: floatingElement })
51
52
  ] });
52
53
  return /* @__PURE__ */ jsxRuntime.jsx(
53
- chunkEM7JHRYW_cjs.SectionShell,
54
+ chunkBJZ2DKS5_cjs.SectionShell,
54
55
  {
55
56
  ref,
56
57
  className: clsx__default.default(
@@ -60,7 +61,7 @@ var HeroSection = react.forwardRef(
60
61
  withGlow && "ds-hero--bg-glow",
61
62
  className
62
63
  ),
63
- padding: "lg",
64
+ padding,
64
65
  ...props,
65
66
  children: isSplit ? /* @__PURE__ */ jsxRuntime.jsxs(
66
67
  "div",
@@ -126,8 +127,8 @@ var FeatureSection = react.forwardRef(
126
127
  className,
127
128
  ...props
128
129
  }, ref) => {
129
- return /* @__PURE__ */ jsxRuntime.jsxs(chunkEM7JHRYW_cjs.SectionShell, { ref, className: clsx__default.default("ds-feature-section", className), ...props, children: [
130
- /* @__PURE__ */ jsxRuntime.jsx(chunkEM7JHRYW_cjs.SectionHeader, { title, subtitle, eyebrow, align: alignHeader }),
130
+ return /* @__PURE__ */ jsxRuntime.jsxs(chunkBJZ2DKS5_cjs.SectionShell, { ref, className: clsx__default.default("ds-feature-section", className), ...props, children: [
131
+ /* @__PURE__ */ jsxRuntime.jsx(chunkBJZ2DKS5_cjs.SectionHeader, { title, subtitle, eyebrow, align: alignHeader }),
131
132
  variant === "grid" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx__default.default("ds-feature-grid", `ds-feature-grid--${columns}-col`), children: features.map((feature, index) => /* @__PURE__ */ jsxRuntime.jsx(FeatureCard, { item: feature }, index)) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ds-feature-zigzag", children: features.map((feature, index) => /* @__PURE__ */ jsxRuntime.jsx(FeatureRow, { item: feature }, index)) })
132
133
  ] });
133
134
  }
@@ -167,15 +168,15 @@ var CTASection = react.forwardRef(
167
168
  ] }),
168
169
  children
169
170
  ] });
170
- return /* @__PURE__ */ jsxRuntime.jsx(chunkEM7JHRYW_cjs.SectionShell, { ref, className: clsx__default.default(className), ...props, children: isBoxed ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ds-cta-card", children: Content }) : Content });
171
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkBJZ2DKS5_cjs.SectionShell, { ref, className: clsx__default.default(className), ...props, children: isBoxed ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ds-cta-card", children: Content }) : Content });
171
172
  }
172
173
  );
173
174
  CTASection.displayName = "CTASection";
174
175
  var StatsSection = react.forwardRef(
175
- ({ stats, title, subtitle, eyebrow, className, ...props }, ref) => {
176
- return /* @__PURE__ */ jsxRuntime.jsxs(chunkEM7JHRYW_cjs.SectionShell, { ref, className: clsx__default.default("ds-stats-section", className), ...props, children: [
177
- /* @__PURE__ */ jsxRuntime.jsx(chunkEM7JHRYW_cjs.SectionHeader, { title, subtitle, eyebrow }),
178
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ds-stats-grid", children: stats.map((stat, idx) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ds-stat-card", children: [
176
+ ({ stats, columns = 4, title, subtitle, eyebrow, className, ...props }, ref) => {
177
+ return /* @__PURE__ */ jsxRuntime.jsxs(chunkBJZ2DKS5_cjs.SectionShell, { ref, className: clsx__default.default("ds-stats-section", className), ...props, children: [
178
+ /* @__PURE__ */ jsxRuntime.jsx(chunkBJZ2DKS5_cjs.SectionHeader, { title, subtitle, eyebrow }),
179
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ds-stats-grid", style: { "--stats-columns": columns }, children: stats.map((stat, idx) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ds-stat-card", children: [
179
180
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ds-stat-value", children: [
180
181
  stat.prefix,
181
182
  stat.value,
@@ -193,4 +194,4 @@ exports.FeatureSection = FeatureSection;
193
194
  exports.HeroSection = HeroSection;
194
195
  exports.StatsSection = StatsSection;
195
196
  //# sourceMappingURL=out.js.map
196
- //# sourceMappingURL=chunk-LSR7JYVH.cjs.map
197
+ //# sourceMappingURL=chunk-H2KQ3WSH.cjs.map