@donotdev/adv-comps 0.0.2 → 0.0.4

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.
@@ -0,0 +1,248 @@
1
+ /* packages/adv-comps/src/components/Roadmap/Roadmap.css */
2
+
3
+ .dndev-roadmap {
4
+ width: 100%;
5
+ position: relative;
6
+ }
7
+
8
+ /* =========================
9
+ DESKTOP LAYOUT
10
+ ========================= */
11
+
12
+ .dndev-roadmap-desktop {
13
+ position: relative;
14
+ }
15
+
16
+ /* Progress line container - from center of first icon to center of last icon */
17
+ .dndev-roadmap-timeline {
18
+ position: absolute;
19
+ top: calc(var(--touch-target) / 2); /* Center of node */
20
+ left: calc(100% / var(--step-count) / 2); /* Center of first grid cell */
21
+ right: calc(100% / var(--step-count) / 2); /* Center of last grid cell */
22
+ height: 4px;
23
+ z-index: 0;
24
+ }
25
+
26
+ .dndev-roadmap-timeline-bg {
27
+ position: absolute;
28
+ inset: 0;
29
+ background: var(--muted);
30
+ border-radius: var(--radius-full);
31
+ }
32
+
33
+ .dndev-roadmap-timeline-progress {
34
+ position: absolute;
35
+ top: 0;
36
+ left: 0;
37
+ height: 100%;
38
+ background: linear-gradient(
39
+ to right,
40
+ var(--primary),
41
+ var(--accent),
42
+ var(--primary)
43
+ );
44
+ border-radius: var(--radius-full);
45
+ transition: width var(--dur-slow) var(--ease-in-out);
46
+ }
47
+
48
+ /* Grid for steps */
49
+ .dndev-roadmap-grid {
50
+ display: grid;
51
+ gap: var(--gap-lg);
52
+ position: relative;
53
+ z-index: 1;
54
+ }
55
+
56
+ /* Individual step container */
57
+ .dndev-roadmap-step {
58
+ display: flex;
59
+ flex-direction: column;
60
+ align-items: center;
61
+ cursor: pointer;
62
+ }
63
+
64
+ /* Timeline node (icon circle) */
65
+ .dndev-roadmap-node {
66
+ width: var(--touch-target);
67
+ height: var(--touch-target);
68
+ border-radius: var(--radius-full);
69
+ border: var(--border-huge) solid var(--muted);
70
+ background: var(--background);
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ transition: all var(--dur-normal) var(--ease-in-out);
75
+ margin-bottom: var(--gap-lg);
76
+ flex-shrink: 0;
77
+ }
78
+
79
+ .dndev-roadmap-node[data-active='true'] {
80
+ border-color: var(--accent);
81
+ box-shadow: 0 0 20px color-mix(in oklab, var(--accent) 40%, transparent);
82
+ transform: scale(1.1);
83
+ }
84
+
85
+ .dndev-roadmap-node svg {
86
+ width: var(--icon-md);
87
+ height: var(--icon-md);
88
+ color: var(--muted-foreground);
89
+ transition: color var(--dur-normal) var(--ease-in-out);
90
+ }
91
+
92
+ .dndev-roadmap-node[data-active='true'] svg {
93
+ color: var(--accent);
94
+ }
95
+
96
+ /* Card styling - extra top padding for badge overlap, push footer to bottom */
97
+ .dndev-roadmap-card {
98
+ position: relative;
99
+ height: 100%;
100
+ padding-top: calc(var(--gap-lg) + var(--gap-sm)) !important;
101
+ align-content: space-between;
102
+ }
103
+
104
+ .dndev-roadmap-step:hover .dndev-roadmap-card,
105
+ .dndev-roadmap-card[data-active='true'] {
106
+ border-color: color-mix(in oklab, var(--accent) 50%, var(--border));
107
+ transform: translateY(calc(-1 * var(--gap-sm)));
108
+ box-shadow: var(--shadow-xl);
109
+ }
110
+
111
+ /* Phase badge - absolute overlay top-start */
112
+ .dndev-roadmap-phase {
113
+ position: absolute;
114
+ top: var(--gap-sm);
115
+ left: var(--gap-sm);
116
+ font-size: var(--font-size-xs);
117
+ font-weight: var(--font-weight-bold);
118
+ text-transform: uppercase;
119
+ letter-spacing: 0.05em;
120
+ padding: 2px var(--gap-sm); /* Tight vertical padding for badge */
121
+ border-radius: var(--radius-interactive);
122
+ background: var(--accent);
123
+ color: var(--accent-foreground);
124
+ }
125
+
126
+ /* Description - sm, foreground, start */
127
+ .dndev-roadmap-description {
128
+ font-size: var(--font-size-sm);
129
+ color: var(--foreground);
130
+ line-height: var(--line-height);
131
+ margin: 0;
132
+ margin-bottom: var(--gap-md);
133
+ text-align: start;
134
+ }
135
+
136
+ /* =========================
137
+ MOBILE LAYOUT
138
+ ========================= */
139
+
140
+ .dndev-roadmap-mobile {
141
+ position: relative;
142
+ padding-left: 0;
143
+ padding-bottom: var(--gap-lg);
144
+ }
145
+
146
+ /* Vertical timeline line - centered, with animated progress */
147
+ .dndev-roadmap-timeline-vertical {
148
+ position: absolute;
149
+ left: 50%;
150
+ top: 0;
151
+ bottom: 0;
152
+ width: 4px;
153
+ background: var(--muted);
154
+ transform: translateX(-50%);
155
+ z-index: 0;
156
+ border-radius: var(--radius-full);
157
+ }
158
+
159
+ .dndev-roadmap-timeline-vertical-progress {
160
+ position: absolute;
161
+ top: 0;
162
+ left: 0;
163
+ width: 100%;
164
+ background: linear-gradient(
165
+ to bottom,
166
+ var(--primary),
167
+ var(--accent),
168
+ var(--primary)
169
+ );
170
+ border-radius: var(--radius-full);
171
+ transition: height var(--dur-slow) var(--ease-in-out);
172
+ }
173
+
174
+ /* Step container - flex column to stack Node -> Card */
175
+ .dndev-roadmap-step-mobile {
176
+ position: relative;
177
+ display: flex;
178
+ flex-direction: column;
179
+ align-items: center;
180
+ width: 100%;
181
+ cursor: pointer;
182
+ }
183
+
184
+ .dndev-roadmap-step-mobile:last-child {
185
+ margin-bottom: 0;
186
+ }
187
+
188
+ /* Mobile node - relative positioning, centered, with top margin from previous card */
189
+ .dndev-roadmap-node-mobile {
190
+ position: relative;
191
+ left: auto;
192
+ top: auto;
193
+ margin-top: var(--gap-md); /* Space from previous card's bottom */
194
+ margin-bottom: var(--gap-md); /* Space before current card */
195
+ width: var(--touch-target);
196
+ height: var(--touch-target);
197
+ border-radius: var(--radius-full);
198
+ border: var(--border-huge) solid var(--muted);
199
+ background: var(--background);
200
+ display: flex;
201
+ align-items: center;
202
+ justify-content: center;
203
+ transition: all var(--dur-normal) var(--ease-in-out);
204
+ z-index: 1;
205
+ }
206
+
207
+ /* First step's icon has no top margin */
208
+ .dndev-roadmap-step-mobile:first-child .dndev-roadmap-node-mobile {
209
+ margin-top: 0;
210
+ }
211
+
212
+ .dndev-roadmap-node-mobile[data-active='true'] {
213
+ border-color: var(--accent);
214
+ box-shadow: 0 0 15px color-mix(in oklab, var(--accent) 30%, transparent);
215
+ }
216
+
217
+ .dndev-roadmap-node-mobile svg {
218
+ width: var(--icon-md);
219
+ height: var(--icon-md);
220
+ color: var(--muted-foreground);
221
+ }
222
+
223
+ .dndev-roadmap-node-mobile[data-active='true'] svg {
224
+ color: var(--accent);
225
+ }
226
+
227
+ /* Mobile card - full width, with active state */
228
+ .dndev-roadmap-card-mobile {
229
+ position: relative;
230
+ width: 100%;
231
+ padding-top: calc(var(--gap-lg) + var(--gap-sm)) !important;
232
+ align-content: space-between;
233
+ background: var(--card);
234
+ z-index: 1;
235
+ transition: all var(--dur-normal) var(--ease-in-out);
236
+ }
237
+
238
+ .dndev-roadmap-card-mobile[data-active='true'] {
239
+ border-color: color-mix(in oklab, var(--accent) 50%, var(--border));
240
+ box-shadow: var(--shadow-lg);
241
+ }
242
+
243
+ /* Only apply hover on devices that support it */
244
+ @media (hover: hover) {
245
+ .dndev-roadmap-card-mobile:hover {
246
+ border-color: color-mix(in oklab, var(--accent) 30%, var(--border));
247
+ }
248
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @fileoverview Roadmap Component
3
+ * @description Timeline component with horizontal (desktop) / vertical (mobile) layout.
4
+ * Features animated progress line, glowing nodes, and lift-on-hover cards.
5
+ *
6
+ * @version 0.0.2
7
+ * @since 0.0.1
8
+ * @author AMBROISE PARK Consulting
9
+ */
10
+ import RoadmapContent from './RoadmapContent';
11
+ import type { ComponentProps } from 'react';
12
+ export type { RoadmapProps, RoadmapStep } from './RoadmapContent';
13
+ declare const Roadmap: (props: ComponentProps<typeof RoadmapContent>) => import("react/jsx-runtime").JSX.Element;
14
+ export default Roadmap;
15
+ //# sourceMappingURL=Roadmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Roadmap.d.ts","sourceRoot":"","sources":["../../../src/components/Roadmap/Roadmap.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5C,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAElE,QAAA,MAAM,OAAO,GAAoB,OAAO,cAAc,CAAC,OAAO,cAAc,CAAC,4CAE5E,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // packages/adv-comps/src/components/Roadmap/Roadmap.tsx
3
+ /**
4
+ * @fileoverview Roadmap Component
5
+ * @description Timeline component with horizontal (desktop) / vertical (mobile) layout.
6
+ * Features animated progress line, glowing nodes, and lift-on-hover cards.
7
+ *
8
+ * @version 0.0.2
9
+ * @since 0.0.1
10
+ * @author AMBROISE PARK Consulting
11
+ */
12
+ import RoadmapContent from './RoadmapContent';
13
+ const Roadmap = function Roadmap(props) {
14
+ return _jsx(RoadmapContent, { ...props });
15
+ };
16
+ export default Roadmap;
@@ -0,0 +1,28 @@
1
+ import type { LucideIcon } from 'lucide-react';
2
+ import { type CardContent, type CardVariant } from '@donotdev/components';
3
+ import './Roadmap.css';
4
+ export interface RoadmapStep {
5
+ /** Phase label (e.g., "Week 1", "Days 1-2") */
6
+ phase: string;
7
+ /** Lucide icon for the timeline node */
8
+ icon: LucideIcon;
9
+ /** Step title */
10
+ title: string;
11
+ /** Step subtitle */
12
+ subtitle: string;
13
+ /** Optional description paragraph */
14
+ description?: string;
15
+ /** Optional content - shown in popover on click */
16
+ content?: CardContent;
17
+ }
18
+ export interface RoadmapProps {
19
+ /** Array of roadmap steps */
20
+ steps: RoadmapStep[];
21
+ /** Optional className */
22
+ className?: string;
23
+ /** Card variant (default, glass, etc.) */
24
+ variant?: CardVariant;
25
+ }
26
+ declare const RoadmapContent: ({ steps, className, variant, }: RoadmapProps) => import("react/jsx-runtime").JSX.Element;
27
+ export default RoadmapContent;
28
+ //# sourceMappingURL=RoadmapContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoadmapContent.d.ts","sourceRoot":"","sources":["../../../src/components/Roadmap/RoadmapContent.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,eAAe,CAAC;AAEvB,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,IAAI,EAAE,UAAU,CAAC;IACjB,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,6BAA6B;IAC7B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,QAAA,MAAM,cAAc,GAA2B,gCAI5C,YAAY,4CAkGd,CAAC;AAsDF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,47 @@
1
+ // packages/adv-comps/src/components/Roadmap/RoadmapContent.tsx
2
+ /**
3
+ * @fileoverview Roadmap Content Component
4
+ * @description Timeline component with horizontal (desktop) / vertical (mobile) layout.
5
+ * Features animated progress line, glowing nodes, and cards with content at bottom.
6
+ *
7
+ * @version 0.0.4
8
+ * @since 0.0.1
9
+ * @author AMBROISE PARK Consulting
10
+ */
11
+ 'use client';
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { useState, useEffect } from 'react';
14
+ import { cn, Card, renderCardContent, useIntersectionObserver, } from '@donotdev/components';
15
+ import { useBreakpoint } from '@donotdev/core';
16
+ import './Roadmap.css';
17
+ const RoadmapContent = function RoadmapContent({ steps, className, variant, }) {
18
+ const [activeStep, setActiveStep] = useState(0);
19
+ const isLaptop = useBreakpoint('isLaptopOrDesktop');
20
+ const progressPercentage = steps.length > 1 ? (activeStep / (steps.length - 1)) * 100 : 0;
21
+ // Desktop layout
22
+ if (isLaptop) {
23
+ return (_jsx("div", { className: cn('dndev-roadmap', className), children: _jsxs("div", { className: "dndev-roadmap-desktop", style: { ['--step-count']: steps.length }, children: [_jsxs("div", { className: "dndev-roadmap-timeline", children: [_jsx("div", { className: "dndev-roadmap-timeline-bg" }), _jsx("div", { className: "dndev-roadmap-timeline-progress", style: { width: `${progressPercentage}%` } })] }), _jsx("div", { className: "dndev-roadmap-grid", style: { gridTemplateColumns: `repeat(${steps.length}, 1fr)` }, children: steps.map((step, index) => {
24
+ const Icon = step.icon;
25
+ const isActive = index <= activeStep;
26
+ const isCurrent = index === activeStep;
27
+ return (_jsxs("div", { className: "dndev-roadmap-step", onMouseEnter: () => setActiveStep(index), children: [_jsx("div", { className: "dndev-roadmap-node", "data-active": isActive, children: _jsx(Icon, {}) }), _jsxs(Card, { title: step.title, subtitle: step.subtitle, variant: variant, className: "dndev-roadmap-card", "data-active": isCurrent, footer: step.content ? (_jsx("div", { className: "dndev-roadmap-content", children: renderCardContent(step.content) })) : undefined, children: [_jsx("span", { className: "dndev-roadmap-phase", children: step.phase }), step.description && (_jsx("p", { className: "dndev-roadmap-description", children: step.description }))] })] }, index));
28
+ }) })] }) }));
29
+ }
30
+ // Mobile layout with scroll-based activation
31
+ return (_jsx("div", { className: cn('dndev-roadmap', className), children: _jsxs("div", { className: "dndev-roadmap-mobile", children: [_jsx("div", { className: "dndev-roadmap-timeline-vertical", children: _jsx("div", { className: "dndev-roadmap-timeline-vertical-progress", style: { height: `${progressPercentage}%` } }) }), steps.map((step, index) => (_jsx(RoadmapStepMobile, { step: step, index: index, isActive: index <= activeStep, variant: variant, onEnter: () => setActiveStep(index) }, index)))] }) }));
32
+ };
33
+ // Mobile step with IntersectionObserver for scroll-based activation
34
+ const RoadmapStepMobile = ({ step, index, isActive, variant, onEnter }) => {
35
+ const { ref, isIntersecting } = useIntersectionObserver({
36
+ threshold: 0.5,
37
+ rootMargin: '0px 0px -20% 0px',
38
+ });
39
+ useEffect(() => {
40
+ if (typeof window !== 'undefined' && isIntersecting) {
41
+ onEnter();
42
+ }
43
+ }, [isIntersecting, onEnter]);
44
+ const Icon = step.icon;
45
+ return (_jsxs("div", { ref: ref, className: "dndev-roadmap-step-mobile", children: [_jsx("div", { className: "dndev-roadmap-node-mobile", "data-active": isActive, children: _jsx(Icon, {}) }), _jsxs(Card, { title: step.title, subtitle: step.subtitle, variant: variant, className: "dndev-roadmap-card-mobile", "data-active": isActive, footer: step.content ? (_jsx("div", { className: "dndev-roadmap-content", children: renderCardContent(step.content) })) : undefined, children: [_jsx("span", { className: "dndev-roadmap-phase", children: step.phase }), step.description && (_jsx("p", { className: "dndev-roadmap-description", children: step.description }))] })] }));
46
+ };
47
+ export default RoadmapContent;
@@ -0,0 +1,3 @@
1
+ export { default } from './Roadmap';
2
+ export type { RoadmapProps, RoadmapStep } from './Roadmap';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Roadmap/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ // packages/adv-comps/src/components/Roadmap/index.ts
2
+ export { default } from './Roadmap';
@@ -39,17 +39,6 @@
39
39
  }
40
40
  }
41
41
 
42
- &:hover {
43
- transform: translateX(0)
44
- translateY(
45
- calc(
46
- -1 * ((var(--dynamic-height) - 3.5rem) + var(--gap-lg)) *
47
- max(var(--i) - var(--e), 0)
48
- )
49
- )
50
- translateY(-8px);
51
- }
52
-
53
42
  @media (prefers-reduced-motion: reduce) {
54
43
  transition: none;
55
44
  transform: none !important;
@@ -60,14 +49,15 @@
60
49
  STACKED CARDS - STACK CONTENT
61
50
  =========================== */
62
51
 
63
- .stack-content {
52
+ /* Override Card's grid for stack-content - needs flex for custom layout */
53
+ .dndev-card > .stack-content {
54
+ display: flex;
55
+ flex-direction: column;
56
+ gap: var(--gap-sm);
64
57
  height: calc(100% - 3.5rem);
65
58
  overflow-y: auto;
66
59
  scrollbar-width: none;
67
60
  -ms-overflow-style: none;
68
- display: flex;
69
- flex-direction: column;
70
- gap: var(--gap-sm);
71
61
 
72
62
  &::-webkit-scrollbar {
73
63
  display: none;
@@ -142,11 +132,14 @@
142
132
  .dndev-stacked-cards-left {
143
133
  display: flex;
144
134
  flex-direction: column;
145
- gap: var(--gap-sm);
146
- padding-inline: var(--gap-md);
135
+ gap: var(--gap-md);
147
136
  text-align: start;
148
137
  }
149
138
 
139
+ .dndev-stacked-cards-left .dndev-card-header + p {
140
+ margin-top: 0;
141
+ }
142
+
150
143
  .dndev-stacked-cards-separator {
151
144
  display: block;
152
145
 
@@ -172,7 +165,6 @@
172
165
  flex-direction: column;
173
166
  justify-content: center;
174
167
  gap: var(--gap-sm);
175
- padding-inline: var(--gap-md);
176
168
  text-align: start;
177
169
  }
178
170
 
@@ -76,6 +76,14 @@ export type StackedCardsProps = {
76
76
  variant?: SurfaceVariantProps['variant'];
77
77
  /** Optional aria-label for the list */
78
78
  ariaLabel?: string;
79
+ /**
80
+ * Intersection threshold for revealing next card (0.0 - 1.0)
81
+ * - 0.0 = reveals when any part is visible
82
+ * - 0.5 = reveals when 50% visible (default)
83
+ * - 1.0 = reveals when 100% visible (full card must be in view)
84
+ * @default 0.5
85
+ */
86
+ threshold?: number;
79
87
  className?: string;
80
88
  style?: CSSProperties;
81
89
  };
@@ -1 +1 @@
1
- {"version":3,"file":"StackedCardsContent.d.ts","sourceRoot":"","sources":["../../../src/components/StackedCards/StackedCardsContent.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAaf,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,sBAAsB,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAkChE;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG;IAC5C;;;;;;;;;;;;;;;;;;OAkBG;IACH,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAE/C;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iDAAiD;IACjD,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB;;OAEG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACzC,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAUF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,QAAA,MAAM,mBAAmB,EAAE,aAAa,CAAC,iBAAiB,CAoDzD,CAAC;AAgJF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"StackedCardsContent.d.ts","sourceRoot":"","sources":["../../../src/components/StackedCards/StackedCardsContent.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAcf,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAkChE;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG;IAC5C;;;;;;;;;;;;;;;;;;OAkBG;IACH,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAE/C;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iDAAiD;IACjD,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB;;OAEG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACzC,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,QAAA,MAAM,mBAAmB,EAAE,aAAa,CAAC,iBAAiB,CAsDzD,CAAC;AAkIF,eAAe,mBAAmB,CAAC"}
@@ -9,7 +9,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
9
  * @author AMBROISE PARK Consulting
10
10
  */
11
11
  import { memo, useEffect, useRef, useState, } from 'react';
12
- import { cn, Button, IconBox, Separator, SEPARATOR_VARIANT, Text, useIntersectionObserver, getVariantDataAttrs, surfaceVariants, } from '@donotdev/components';
12
+ import { cn, Button, Separator, SEPARATOR_VARIANT, Text, useIntersectionObserver, getVariantDataAttrs, surfaceVariants, renderCardHeader, renderCardContent, } from '@donotdev/components';
13
13
  /**
14
14
  * Stacked Cards Animation Configuration
15
15
  *
@@ -26,7 +26,7 @@ const STACKED_CARDS_CONFIG = {
26
26
  *
27
27
  * TO REQUIRE MORE SCROLL: Increase this value (0.3 → 0.5 → 0.7)
28
28
  */
29
- intersectionThreshold: 0.3,
29
+ intersectionThreshold: 0.5,
30
30
  /**
31
31
  * Intersection Observer root margin (bottom)
32
32
  * Format: 'top right bottom left'
@@ -39,12 +39,6 @@ const STACKED_CARDS_CONFIG = {
39
39
  // Removed viewportTopThreshold and viewportBottomThreshold
40
40
  // IntersectionObserver handles all visibility detection (more performant, single source of truth)
41
41
  };
42
- // Icon renderer component
43
- const IconRenderer = memo(({ icon }) => {
44
- if (!icon)
45
- return null;
46
- return _jsx(IconBox, { icon: icon, ariaHidden: true });
47
- });
48
42
  /**
49
43
  * StackedCardsContent Component - Animated waterfall card stacking
50
44
  *
@@ -119,7 +113,7 @@ const IconRenderer = memo(({ icon }) => {
119
113
  * ];
120
114
  * ```
121
115
  */
122
- const StackedCardsContent = ({ items, className, ariaLabel, variant, style, }) => {
116
+ const StackedCardsContent = ({ items, className, ariaLabel, variant, style, threshold = STACKED_CARDS_CONFIG.intersectionThreshold, }) => {
123
117
  const [entered, setEntered] = useState(0);
124
118
  const containerRef = useRef(null);
125
119
  // Calculate maximum height from all items to ensure all cards have the same height
@@ -135,12 +129,12 @@ const StackedCardsContent = ({ items, className, ariaLabel, variant, style, }) =
135
129
  const maxOrder = heightOrder[max] || 2;
136
130
  return currentOrder > maxOrder ? current : max;
137
131
  }, 'medium');
138
- return (_jsx("div", { className: cn('dndev-relative dndev-stacked-cards-container', className), ref: containerRef, "aria-label": ariaLabel, style: { ['--e']: entered.toString() }, children: items.map((item, index) => (_jsx(StackedCardsItem, { item: item, index: index, entered: entered, onEnter: () => setEntered(index), totalItems: items.length, cardProps: { variant, style }, maxEstimatedHeight: maxEstimatedHeight, maxCustomHeight: maxCustomHeight }, index))) }));
132
+ return (_jsx("div", { className: cn('dndev-relative dndev-stacked-cards-container', className), ref: containerRef, "aria-label": ariaLabel, style: { ['--e']: entered.toString() }, children: items.map((item, index) => (_jsx(StackedCardsItem, { item: item, index: index, entered: entered, onEnter: () => setEntered(index), totalItems: items.length, cardProps: { variant, style }, maxEstimatedHeight: maxEstimatedHeight, maxCustomHeight: maxCustomHeight, threshold: threshold }, index))) }));
139
133
  };
140
134
  // Individual stacked card item with working logic matching the CSS
141
- const StackedCardsItem = ({ item, index, entered, onEnter, totalItems, cardProps, maxEstimatedHeight, maxCustomHeight, }) => {
135
+ const StackedCardsItem = ({ item, index, entered, onEnter, totalItems, cardProps, maxEstimatedHeight, maxCustomHeight, threshold, }) => {
142
136
  const { ref, isIntersecting } = useIntersectionObserver({
143
- threshold: STACKED_CARDS_CONFIG.intersectionThreshold,
137
+ threshold,
144
138
  rootMargin: STACKED_CARDS_CONFIG.intersectionRootMargin,
145
139
  });
146
140
  useEffect(() => {
@@ -148,11 +142,9 @@ const StackedCardsItem = ({ item, index, entered, onEnter, totalItems, cardProps
148
142
  onEnter();
149
143
  }
150
144
  }, [isIntersecting, onEnter]);
151
- const contentArray = Array.isArray(item.content)
152
- ? item.content
153
- : item.content
154
- ? [item.content]
155
- : [];
145
+ const header = renderCardHeader(item.icon, item.title, item.subtitle);
146
+ const contentNode = renderCardContent(item.content);
147
+ const hasContent = !!contentNode;
156
148
  return (_jsx("section", { ref: ref, className: "dndev-relative", style: {
157
149
  zIndex: totalItems - index - 1,
158
150
  }, children: _jsx("div", { className: cn('dndev-relative dndev-overflow-hidden stack', 'dndev-min-w-0'), "data-size": maxCustomHeight ? undefined : maxEstimatedHeight, "data-stacked": index > entered ? 'true' : 'false', style: {
@@ -162,10 +154,7 @@ const StackedCardsItem = ({ item, index, entered, onEnter, totalItems, cardProps
162
154
  ['--dynamic-height']: `${maxCustomHeight}px`,
163
155
  }),
164
156
  ...cardProps.style,
165
- }, children: _jsxs("div", { className: cn(surfaceVariants({ variant: cardProps.variant }), 'dndev-relative dndev-overflow-hidden dndev-h-full'), ...getVariantDataAttrs({ variant: cardProps.variant }), style: {
166
- padding: 'var(--gap-sm)',
167
- ...cardProps.style,
168
- }, children: [_jsxs("div", { className: "stack-content", children: [_jsxs("div", { className: "dndev-stacked-cards-body", children: [_jsxs("div", { className: "dndev-stacked-cards-left", children: [_jsxs("div", { className: "dndev-stacked-cards-header", children: [item.icon && _jsx(IconRenderer, { icon: item.icon }), item.title && _jsx(Text, { as: "h3", children: item.title })] }), item.subtitle && (_jsx(Text, { as: "p", level: "h4", variant: "primary", children: item.subtitle })), item.description && (_jsx(Text, { as: "p", level: "h4", variant: "muted", children: item.description }))] }), _jsx(Separator, { orientation: "vertical", variant: SEPARATOR_VARIANT.ACCENT, className: "dndev-stacked-cards-separator" }), contentArray.length > 0 && (_jsx("div", { className: "dndev-stacked-cards-right", children: contentArray.map((point, idx) => (_jsx(Text, { as: "div", level: "body", variant: "muted", children: point }, idx))) }))] }), item.cta && (_jsx("div", { className: "dndev-stacked-cards-cta", children: _jsx(Button, { onClick: item.onClick, variant: item.cta.variant || 'primary', icon: item.cta.icon, children: item.cta.text }) })), _jsx("div", { className: "dndev-stacked-cards-spacer" })] }), _jsx("div", { className: "dndev-stacked-cards-number", children: item.number
157
+ }, children: _jsxs("div", { className: cn('dndev-card', surfaceVariants({ variant: cardProps.variant }), 'dndev-relative dndev-overflow-hidden dndev-h-full'), ...getVariantDataAttrs({ variant: cardProps.variant }), "data-role": "card", "data-clickable": item.onClick ? 'true' : undefined, onClick: item.onClick, style: cardProps.style, children: [_jsxs("div", { className: "stack-content", children: [_jsxs("div", { className: "dndev-stacked-cards-body", children: [_jsxs("div", { className: "dndev-stacked-cards-left", children: [header, item.description && (_jsx(Text, { as: "p", level: "small", variant: "muted", children: item.description }))] }), _jsx(Separator, { orientation: "vertical", variant: SEPARATOR_VARIANT.ACCENT, className: "dndev-stacked-cards-separator" }), hasContent && (_jsx("div", { className: "dndev-stacked-cards-right", children: contentNode }))] }), item.cta && (_jsx("div", { className: "dndev-stacked-cards-cta", children: _jsx(Button, { onClick: item.onClick, variant: item.cta.variant || 'primary', icon: item.cta.icon, children: item.cta.text }) })), _jsx("div", { className: "dndev-stacked-cards-spacer" })] }), _jsx("div", { className: "dndev-stacked-cards-number", children: item.number
169
158
  ? String(item.number)
170
159
  : String(index + 1).padStart(2, '0') })] }) }) }));
171
160
  };
package/dist/index.css CHANGED
@@ -1 +1 @@
1
- :root{--crawl-perspective: 600px;--crawl-tilt: 40deg;--crawl-body-size: clamp(1.6rem, 1rem + 2.5vw, 3rem);--crawl-title-size: clamp(3rem, 1.5rem + 6vw, 8rem);--crawl-intro-font-size: clamp(2rem, 1rem + 3vw, 4rem);--crawl-content-line: 1.2;--crawl-body-margin: .9em;--crawl-title-margin: 3em;--crawl-text-color: #ffc909;--crawl-intro-color: #4a9eff;--crawl-text-shadow: 0 0 12px rgba(255, 201, 9, 1);--crawl-intro-shadow: 0 0 30px rgba(74, 158, 255, .9), 0 0 60px rgba(74, 158, 255, .6), 0 0 90px rgba(74, 158, 255, .4), 0 0 120px rgba(74, 158, 255, .2);--crawl-intro-duration: 2s}.dndev-crawl-container{position:relative;background:#000;contain:layout style paint;perspective:var(--crawl-perspective);backface-visibility:hidden;width:150vw;left:50%;transform:translate3d(-50%,0,0);margin:0;margin-top:0!important;padding:0;max-width:none;min-height:calc(100dvh - var(--header-height));overflow:hidden}.dndev-container>.dndev-crawl-container:first-child{margin-top:0!important}.dndev-container:has(>.dndev-crawl-container:first-child){margin-top:0!important}.dndev-crawl-stars{position:absolute;inset:0;z-index:1;contain:layout style paint;pointer-events:none}.dndev-crawl-stars-layer-1,.dndev-crawl-stars-layer-2,.dndev-crawl-stars-layer-3{position:absolute;inset:0;width:100%;height:100%;background-image:url("data:image/svg+xml,%3Csvg width='500' height='300' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='23' cy='17' r='1' fill='white' opacity='1'/%3E%3Ccircle cx='47' cy='89' r='1' fill='white' opacity='0.8'/%3E%3Ccircle cx='91' cy='43' r='0.5' fill='white' opacity='1'/%3E%3Ccircle cx='131' cy='67' r='1' fill='white' opacity='0.6'/%3E%3Ccircle cx='163' cy='19' r='0.5' fill='%23ddd' opacity='0.8'/%3E%3Ccircle cx='197' cy='73' r='1' fill='white' opacity='1'/%3E%3Ccircle cx='211' cy='41' r='0.5' fill='white' opacity='0.7'/%3E%3Ccircle cx='233' cy='97' r='1' fill='%23eee' opacity='0.9'/%3E%3Ccircle cx='251' cy='13' r='0.5' fill='white' opacity='1'/%3E%3Ccircle cx='277' cy='59' r='1' fill='white' opacity='0.5'/%3E%3Ccircle cx='293' cy='83' r='0.5' fill='%23ddd' opacity='0.8'/%3E%3Ccircle cx='317' cy='31' r='1' fill='white' opacity='1'/%3E%3Ccircle cx='337' cy='71' r='0.5' fill='white' opacity='0.8'/%3E%3Ccircle cx='359' cy='7' r='1' fill='%23eee' opacity='0.9'/%3E%3Ccircle cx='373' cy='53' r='0.5' fill='white' opacity='1'/%3E%3Ccircle cx='389' cy='79' r='1' fill='white' opacity='0.6'/%3E%3Ccircle cx='401' cy='23' r='0.5' fill='%23ddd' opacity='0.8'/%3E%3Ccircle cx='419' cy='61' r='1' fill='white' opacity='1'/%3E%3Ccircle cx='433' cy='37' r='0.5' fill='white' opacity='0.7'/%3E%3Ccircle cx='449' cy='87' r='1' fill='%23eee' opacity='0.9'/%3E%3C/svg%3E");background-repeat:repeat;pointer-events:none}.dndev-crawl-stars-layer-1{--layer-base-opacity: 1;opacity:1;background-size:400px 250px;animation:dndev-stars-twinkle 4s ease-in-out infinite;animation-delay:0s}.dndev-crawl-stars-layer-2{--layer-base-opacity: .7;opacity:.7;background-size:300px 200px;animation:dndev-stars-twinkle 2.5s ease-in-out infinite;animation-delay:1s}.dndev-crawl-stars-layer-3{--layer-base-opacity: .5;opacity:.5;background-size:200px 150px;animation:dndev-stars-twinkle 1.8s ease-in-out infinite;animation-delay:2s}@keyframes dndev-stars-twinkle{0%,to{opacity:var(--layer-base-opacity)}50%{opacity:calc(var(--layer-base-opacity) * 1.43)}}.dndev-crawl-3d-container{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;z-index:10;perspective:var(--crawl-perspective);transform-style:preserve-3d;contain:layout style;backface-visibility:hidden;will-change:auto}.dndev-crawl-text{width:100%;height:100%;display:flex;align-items:center;justify-content:center;position:relative;transform:rotateX(var(--crawl-tilt)) translateZ(0);transform-style:preserve-3d;backface-visibility:hidden;contain:layout style}.dndev-crawl-content{color:var(--crawl-text-color);font-size:var(--crawl-body-size);line-height:var(--crawl-content-line);font-weight:700;text-align:center;text-shadow:var(--crawl-text-shadow);position:relative;z-index:2;width:60%;max-width:60%;margin-left:auto;margin-right:auto;padding:0;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.dndev-crawl-title,.dndev-crawl-content h1,.dndev-crawl-content h2,.dndev-crawl-content p{color:var(--crawl-text-color);font-weight:700;text-align:center;text-shadow:var(--crawl-text-shadow);@media(width<=1023px){text-shadow:none}}.dndev-crawl-title,.dndev-crawl-content h1,.dndev-crawl-content h2{font-size:var(--crawl-title-size);margin-bottom:var(--crawl-title-margin);padding:0;margin-left:0;margin-right:0}.dndev-crawl-content p{font-size:var(--crawl-body-size);margin-bottom:var(--crawl-body-margin)}@media(width>=1024px){.dndev-crawl-title{white-space:nowrap}}.dndev-crawl-intro{background:linear-gradient(180deg,#000c,#0006,#000c)}.dndev-crawl-intro-content{color:var(--crawl-intro-color);font-size:var(--crawl-intro-font-size);font-weight:900;text-align:center;text-shadow:var(--crawl-intro-shadow);letter-spacing:.1em;line-height:1.2;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;width:60%;max-width:60%;margin:0 auto;overflow-wrap:break-word;-webkit-hyphens:auto;hyphens:auto;white-space:normal}.dndev-crawl-intro-mobile{animation:dndev-intro-fade-mobile var(--crawl-intro-duration) ease-in-out forwards}.dndev-crawl-intro-desktop{animation:dndev-intro-fade-desktop calc(var(--crawl-intro-duration) * 2) ease-in-out forwards}@keyframes dndev-crawl-animation{0%{transform:rotateX(var(--crawl-tilt)) translate3d(0,100dvh,0)}to{transform:rotateX(var(--crawl-tilt)) translate3d(0,calc(-1 * var(--crawl-content-height)),0)}}@media(prefers-reduced-motion:reduce){.dndev-crawl-text{animation:none!important}.dndev-crawl-3d-container{transform:rotateX(0) translateZ(0)!important}.dndev-crawl-content{position:static!important;transform:none!important;animation:none!important}.dndev-crawl-intro-mobile,.dndev-crawl-intro-desktop{animation:none!important}}@media(prefers-contrast:high){.dndev-crawl-stars{filter:contrast(1.5) brightness(1.2)}}.dndev-crawl-reduced-motion{animation:none!important;transform:none!important;.dndev-crawl-content{position:static!important;transform:none!important}.dndev-crawl-stars-layer-1,.dndev-crawl-stars-layer-2,.dndev-crawl-stars-layer-3{animation:none!important}}.stack{width:100%;height:var(--dynamic-height);contain:layout;transform-origin:center top;transform:translate(0) translateY(calc(-1 * ((var(--dynamic-height) - 3.5rem) + var(--gap-lg)) * max(var(--i) - var(--e),0)));transition:transform var(--dur-heavy) var(--ease-heavy);will-change:var(--will-change-transform);&[data-size=small]{--dynamic-height: 24rem;@media(width>=1024px){--dynamic-height: 16rem}}&[data-size=medium]{--dynamic-height: 28rem;@media(width>=1024px){--dynamic-height: 20rem}}&[data-size=large]{--dynamic-height: 36rem;@media(width>=1024px){--dynamic-height: 28rem}}&:hover{transform:translate(0) translateY(calc(-1 * ((var(--dynamic-height) - 3.5rem) + var(--gap-lg)) * max(var(--i) - var(--e),0))) translateY(-8px)}@media(prefers-reduced-motion:reduce){transition:none;transform:none!important}}.stack-content{height:calc(100% - 3.5rem);overflow-y:auto;scrollbar-width:none;-ms-overflow-style:none;display:flex;flex-direction:column;gap:var(--gap-sm);&::-webkit-scrollbar{display:none}}.stack[data-stacked=true] .stack-content{opacity:0;pointer-events:none}.stack[data-stacked=true] .dndev-stacked-cards-number{opacity:1}.dndev-stacked-cards-spacer{height:3.5rem}.dndev-stacked-cards-number{position:absolute;left:var(--gap-lg);bottom:0;height:3.5rem;display:flex;align-items:center;font-size:var(--font-size-sm);font-weight:500;color:var(--muted-foreground);z-index:10;opacity:1;transition:opacity var(--dur-heavy) var(--ease-heavy)}.dndev-stacked-cards-container{display:flex;flex-direction:column;width:100%;max-width:min(100%,var(--content-width, 60rem));margin-inline:auto;gap:var(--gap-lg);position:relative;z-index:0}.dndev-stacked-cards-header{display:flex;align-items:center;gap:var(--gap-sm)}.dndev-stacked-cards-body{display:flex;flex-direction:column;gap:var(--gap-sm);width:100%;align-items:start;@media(width>=1024px){display:grid;grid-template-columns:1fr auto 1fr;width:100%;align-items:center}}.dndev-stacked-cards-left{display:flex;flex-direction:column;gap:var(--gap-sm);padding-inline:var(--gap-md);text-align:start}.dndev-stacked-cards-separator{display:block;@media(width<1024px){width:80%!important;height:2px!important;margin-inline:auto;margin-block:var(--gap-sm);align-self:center}@media(width>=1024px){width:1px!important;height:100%!important;align-self:stretch}}.dndev-stacked-cards-right{display:flex;flex-direction:column;justify-content:center;gap:var(--gap-sm);padding-inline:var(--gap-md);text-align:start}.dndev-stacked-cards-cta{padding-top:var(--gap-sm)}[data-marquee-track]{will-change:var(--will-change-transform);animation:universal-marquee var(--marquee-duration, 0ms) var(--marquee-easing, linear) infinite;animation-direction:var(--marquee-direction, normal);&[data-marquee-direction=vertical]{--transform-start: translateY(0);--transform-end: translateY(calc(-1 * var(--marquee-distance, 0px)))}&[data-marquee-behavior=bounce]{animation-name:universal-float;--transform-start: translateX(0);--transform-mid: translateX(calc(-1 * var(--marquee-distance, 0px)));--opacity-start: 1;--opacity-mid: 1}@media(prefers-reduced-motion:reduce){animation:none!important;transform:none!important}.group:hover &,.group:focus-within &{animation-play-state:paused}}.dndev-reveal-container{contain:layout style;will-change:contents;&.dndev-reveal-visible .dndev-reveal-item{opacity:1;transform:translateZ(0);animation:dndev-reveal-cleanup var(--reveal-duration) var(--reveal-easing) forwards;@media(prefers-reduced-motion:reduce){transition:none!important;opacity:1!important;transform:none!important;will-change:auto}}}.dndev-reveal-item{opacity:0;transform:translateZ(0);will-change:transform,opacity;backface-visibility:hidden;transition:opacity var(--reveal-duration) var(--reveal-easing),transform var(--reveal-duration) var(--reveal-easing);transition-delay:var(--reveal-delay, 0ms);&[data-direction=left]{transform:translate3d(calc(-1 * var(--reveal-distance)),0,0)}&[data-direction=right]{transform:translate3d(var(--reveal-distance),0,0)}&[data-direction=top]{transform:translate3d(0,calc(-1 * var(--reveal-distance)),0)}&[data-direction=bottom]{transform:translate3d(0,var(--reveal-distance),0)}&[data-direction=fade-in]{transform:translateZ(0)}&[data-visible=true]{opacity:1;transform:translateZ(0)}@media(prefers-reduced-motion:reduce){transition:none!important;opacity:1!important;transform:none!important;will-change:auto}}.breath-lung-442{animation:none;will-change:clip-path;&.active{animation:breath-cycle-442 var(--breath-cycle-duration, 16s) ease-in-out var(--breath-cycles, 3)}&.paused{animation-play-state:paused}}.breath-lung-sigh{animation:none;will-change:clip-path;&.active{animation:breath-cycle-sigh var(--breath-cycle-duration, 10s) ease-in-out var(--breath-cycles, 3)}&.paused{animation-play-state:paused}}.network-node{fill:var(--foreground);animation:universal-float 4s ease-in-out infinite;--opacity-start: .3;--opacity-mid: .8;--transform-start: scale(1);--transform-mid: scale(1.1)}.network-line{stroke:var(--foreground);stroke-width:1;animation:universal-float 6s ease-in-out infinite;--opacity-start: .1;--opacity-mid: .5;--transform-start: scale(1);--transform-mid: scale(1)}.wave-flow{background:linear-gradient(45deg,transparent 30%,color-mix(in oklab,var(--accent) 20%,transparent) 50%,transparent 70%);animation:universal-float 8s ease-in-out infinite;--transform-start: translateX(-20%) rotate(0deg);--transform-mid: translateX(20%) rotate(3deg)}.particle-float{animation:universal-slide 10s linear infinite;--opacity-start: .2;--opacity-end: 0;--transform-start: translateY(0px) rotate(0deg);--transform-end: translateY(-100px) rotate(360deg)}.geometric-rotate{animation:universal-float 20s linear infinite;--opacity-start: .1;--opacity-mid: .2;--transform-start: rotate(0deg) scale(1);--transform-mid: rotate(180deg) scale(1.1)}.perspective-1000{perspective:1000px}.transform-style-preserve-3d{transform-style:preserve-3d}.dndev-animate-fade-in-up{animation:universal-slide var(--dur-heavy) ease-out forwards}.animation-delay-100{animation-delay:.1s}.dndev-marketing-stack{display:grid;gap:var(--gap-md)}.dndev-marketing-cluster{display:flex;gap:var(--gap-sm);align-items:center;justify-content:center}
1
+ .dndev-roadmap{width:100%;position:relative}.dndev-roadmap-desktop{position:relative}.dndev-roadmap-timeline{position:absolute;top:calc(var(--touch-target) / 2);left:calc(100% / var(--step-count) / 2);right:calc(100% / var(--step-count) / 2);height:4px;z-index:0}.dndev-roadmap-timeline-bg{position:absolute;inset:0;background:var(--muted);border-radius:var(--radius-full)}.dndev-roadmap-timeline-progress{position:absolute;top:0;left:0;height:100%;background:linear-gradient(to right,var(--primary),var(--accent),var(--primary));border-radius:var(--radius-full);transition:width var(--dur-slow) var(--ease-in-out)}.dndev-roadmap-grid{display:grid;gap:var(--gap-lg);position:relative;z-index:1}.dndev-roadmap-step{display:flex;flex-direction:column;align-items:center;cursor:pointer}.dndev-roadmap-node{width:var(--touch-target);height:var(--touch-target);border-radius:var(--radius-full);border:var(--border-huge) solid var(--muted);background:var(--background);display:flex;align-items:center;justify-content:center;transition:all var(--dur-normal) var(--ease-in-out);margin-bottom:var(--gap-lg);flex-shrink:0}.dndev-roadmap-node[data-active=true]{border-color:var(--accent);box-shadow:0 0 20px color-mix(in oklab,var(--accent) 40%,transparent);transform:scale(1.1)}.dndev-roadmap-node svg{width:var(--icon-md);height:var(--icon-md);color:var(--muted-foreground);transition:color var(--dur-normal) var(--ease-in-out)}.dndev-roadmap-node[data-active=true] svg{color:var(--accent)}.dndev-roadmap-card{position:relative;height:100%;padding-top:calc(var(--gap-lg) + var(--gap-sm))!important;align-content:space-between}.dndev-roadmap-step:hover .dndev-roadmap-card,.dndev-roadmap-card[data-active=true]{border-color:color-mix(in oklab,var(--accent) 50%,var(--border));transform:translateY(calc(-1 * var(--gap-sm)));box-shadow:var(--shadow-xl)}.dndev-roadmap-phase{position:absolute;top:var(--gap-sm);left:var(--gap-sm);font-size:var(--font-size-xs);font-weight:var(--font-weight-bold);text-transform:uppercase;letter-spacing:.05em;padding:2px var(--gap-sm);border-radius:var(--radius-interactive);background:var(--accent);color:var(--accent-foreground)}.dndev-roadmap-description{font-size:var(--font-size-sm);color:var(--foreground);line-height:var(--line-height);margin:0;margin-bottom:var(--gap-md);text-align:start}.dndev-roadmap-mobile{position:relative;padding-left:0;padding-bottom:var(--gap-lg)}.dndev-roadmap-timeline-vertical{position:absolute;left:50%;top:0;bottom:0;width:4px;background:var(--muted);transform:translate(-50%);z-index:0;border-radius:var(--radius-full)}.dndev-roadmap-timeline-vertical-progress{position:absolute;top:0;left:0;width:100%;background:linear-gradient(to bottom,var(--primary),var(--accent),var(--primary));border-radius:var(--radius-full);transition:height var(--dur-slow) var(--ease-in-out)}.dndev-roadmap-step-mobile{position:relative;display:flex;flex-direction:column;align-items:center;width:100%;cursor:pointer}.dndev-roadmap-step-mobile:last-child{margin-bottom:0}.dndev-roadmap-node-mobile{position:relative;left:auto;top:auto;margin-top:var(--gap-md);margin-bottom:var(--gap-md);width:var(--touch-target);height:var(--touch-target);border-radius:var(--radius-full);border:var(--border-huge) solid var(--muted);background:var(--background);display:flex;align-items:center;justify-content:center;transition:all var(--dur-normal) var(--ease-in-out);z-index:1}.dndev-roadmap-step-mobile:first-child .dndev-roadmap-node-mobile{margin-top:0}.dndev-roadmap-node-mobile[data-active=true]{border-color:var(--accent);box-shadow:0 0 15px color-mix(in oklab,var(--accent) 30%,transparent)}.dndev-roadmap-node-mobile svg{width:var(--icon-md);height:var(--icon-md);color:var(--muted-foreground)}.dndev-roadmap-node-mobile[data-active=true] svg{color:var(--accent)}.dndev-roadmap-card-mobile{position:relative;width:100%;padding-top:calc(var(--gap-lg) + var(--gap-sm))!important;align-content:space-between;background:var(--card);z-index:1;transition:all var(--dur-normal) var(--ease-in-out)}.dndev-roadmap-card-mobile[data-active=true]{border-color:color-mix(in oklab,var(--accent) 50%,var(--border));box-shadow:var(--shadow-lg)}@media(hover:hover){.dndev-roadmap-card-mobile:hover{border-color:color-mix(in oklab,var(--accent) 30%,var(--border))}}:root{--crawl-perspective: 600px;--crawl-tilt: 40deg;--crawl-body-size: clamp(1.6rem, 1rem + 2.5vw, 3rem);--crawl-title-size: clamp(3rem, 1.5rem + 6vw, 8rem);--crawl-intro-font-size: clamp(2rem, 1rem + 3vw, 4rem);--crawl-content-line: 1.2;--crawl-body-margin: .9em;--crawl-title-margin: 3em;--crawl-text-color: #ffc909;--crawl-intro-color: #4a9eff;--crawl-text-shadow: 0 0 12px rgba(255, 201, 9, 1);--crawl-intro-shadow: 0 0 30px rgba(74, 158, 255, .9), 0 0 60px rgba(74, 158, 255, .6), 0 0 90px rgba(74, 158, 255, .4), 0 0 120px rgba(74, 158, 255, .2);--crawl-intro-duration: 2s}.dndev-crawl-container{position:relative;background:#000;contain:layout style paint;perspective:var(--crawl-perspective);backface-visibility:hidden;width:150vw;left:50%;transform:translate3d(-50%,0,0);margin:0;margin-top:0!important;padding:0;max-width:none;min-height:calc(100dvh - var(--header-height));overflow:hidden}.dndev-container>.dndev-crawl-container:first-child{margin-top:0!important}.dndev-container:has(>.dndev-crawl-container:first-child){margin-top:0!important}.dndev-crawl-stars{position:absolute;inset:0;z-index:1;contain:layout style paint;pointer-events:none}.dndev-crawl-stars-layer-1,.dndev-crawl-stars-layer-2,.dndev-crawl-stars-layer-3{position:absolute;inset:0;width:100%;height:100%;background-image:url("data:image/svg+xml,%3Csvg width='500' height='300' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='23' cy='17' r='1' fill='white' opacity='1'/%3E%3Ccircle cx='47' cy='89' r='1' fill='white' opacity='0.8'/%3E%3Ccircle cx='91' cy='43' r='0.5' fill='white' opacity='1'/%3E%3Ccircle cx='131' cy='67' r='1' fill='white' opacity='0.6'/%3E%3Ccircle cx='163' cy='19' r='0.5' fill='%23ddd' opacity='0.8'/%3E%3Ccircle cx='197' cy='73' r='1' fill='white' opacity='1'/%3E%3Ccircle cx='211' cy='41' r='0.5' fill='white' opacity='0.7'/%3E%3Ccircle cx='233' cy='97' r='1' fill='%23eee' opacity='0.9'/%3E%3Ccircle cx='251' cy='13' r='0.5' fill='white' opacity='1'/%3E%3Ccircle cx='277' cy='59' r='1' fill='white' opacity='0.5'/%3E%3Ccircle cx='293' cy='83' r='0.5' fill='%23ddd' opacity='0.8'/%3E%3Ccircle cx='317' cy='31' r='1' fill='white' opacity='1'/%3E%3Ccircle cx='337' cy='71' r='0.5' fill='white' opacity='0.8'/%3E%3Ccircle cx='359' cy='7' r='1' fill='%23eee' opacity='0.9'/%3E%3Ccircle cx='373' cy='53' r='0.5' fill='white' opacity='1'/%3E%3Ccircle cx='389' cy='79' r='1' fill='white' opacity='0.6'/%3E%3Ccircle cx='401' cy='23' r='0.5' fill='%23ddd' opacity='0.8'/%3E%3Ccircle cx='419' cy='61' r='1' fill='white' opacity='1'/%3E%3Ccircle cx='433' cy='37' r='0.5' fill='white' opacity='0.7'/%3E%3Ccircle cx='449' cy='87' r='1' fill='%23eee' opacity='0.9'/%3E%3C/svg%3E");background-repeat:repeat;pointer-events:none}.dndev-crawl-stars-layer-1{--layer-base-opacity: 1;opacity:1;background-size:400px 250px;animation:dndev-stars-twinkle 4s ease-in-out infinite;animation-delay:0s}.dndev-crawl-stars-layer-2{--layer-base-opacity: .7;opacity:.7;background-size:300px 200px;animation:dndev-stars-twinkle 2.5s ease-in-out infinite;animation-delay:1s}.dndev-crawl-stars-layer-3{--layer-base-opacity: .5;opacity:.5;background-size:200px 150px;animation:dndev-stars-twinkle 1.8s ease-in-out infinite;animation-delay:2s}@keyframes dndev-stars-twinkle{0%,to{opacity:var(--layer-base-opacity)}50%{opacity:calc(var(--layer-base-opacity) * 1.43)}}.dndev-crawl-3d-container{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;z-index:10;perspective:var(--crawl-perspective);transform-style:preserve-3d;contain:layout style;backface-visibility:hidden;will-change:auto}.dndev-crawl-text{width:100%;height:100%;display:flex;align-items:center;justify-content:center;position:relative;transform:rotateX(var(--crawl-tilt)) translateZ(0);transform-style:preserve-3d;backface-visibility:hidden;contain:layout style}.dndev-crawl-content{color:var(--crawl-text-color);font-size:var(--crawl-body-size);line-height:var(--crawl-content-line);font-weight:700;text-align:center;text-shadow:var(--crawl-text-shadow);position:relative;z-index:2;width:60%;max-width:60%;margin-left:auto;margin-right:auto;padding:0;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.dndev-crawl-title,.dndev-crawl-content h1,.dndev-crawl-content h2,.dndev-crawl-content p{color:var(--crawl-text-color);font-weight:700;text-align:center;text-shadow:var(--crawl-text-shadow);@media(width<=1023px){text-shadow:none}}.dndev-crawl-title,.dndev-crawl-content h1,.dndev-crawl-content h2{font-size:var(--crawl-title-size);margin-bottom:var(--crawl-title-margin);padding:0;margin-left:0;margin-right:0}.dndev-crawl-content p{font-size:var(--crawl-body-size);margin-bottom:var(--crawl-body-margin)}@media(width>=1024px){.dndev-crawl-title{white-space:nowrap}}.dndev-crawl-intro{background:linear-gradient(180deg,#000c,#0006,#000c)}.dndev-crawl-intro-content{color:var(--crawl-intro-color);font-size:var(--crawl-intro-font-size);font-weight:900;text-align:center;text-shadow:var(--crawl-intro-shadow);letter-spacing:.1em;line-height:1.2;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;width:60%;max-width:60%;margin:0 auto;overflow-wrap:break-word;-webkit-hyphens:auto;hyphens:auto;white-space:normal}.dndev-crawl-intro-mobile{animation:dndev-intro-fade-mobile var(--crawl-intro-duration) ease-in-out forwards}.dndev-crawl-intro-desktop{animation:dndev-intro-fade-desktop calc(var(--crawl-intro-duration) * 2) ease-in-out forwards}@keyframes dndev-crawl-animation{0%{transform:rotateX(var(--crawl-tilt)) translate3d(0,100dvh,0)}to{transform:rotateX(var(--crawl-tilt)) translate3d(0,calc(-1 * var(--crawl-content-height)),0)}}@media(prefers-reduced-motion:reduce){.dndev-crawl-text{animation:none!important}.dndev-crawl-3d-container{transform:rotateX(0) translateZ(0)!important}.dndev-crawl-content{position:static!important;transform:none!important;animation:none!important}.dndev-crawl-intro-mobile,.dndev-crawl-intro-desktop{animation:none!important}}@media(prefers-contrast:high){.dndev-crawl-stars{filter:contrast(1.5) brightness(1.2)}}.dndev-crawl-reduced-motion{animation:none!important;transform:none!important;.dndev-crawl-content{position:static!important;transform:none!important}.dndev-crawl-stars-layer-1,.dndev-crawl-stars-layer-2,.dndev-crawl-stars-layer-3{animation:none!important}}.stack{width:100%;height:var(--dynamic-height);contain:layout;transform-origin:center top;transform:translate(0) translateY(calc(-1 * ((var(--dynamic-height) - 3.5rem) + var(--gap-lg)) * max(var(--i) - var(--e),0)));transition:transform var(--dur-heavy) var(--ease-heavy);will-change:var(--will-change-transform);&[data-size=small]{--dynamic-height: 24rem;@media(width>=1024px){--dynamic-height: 16rem}}&[data-size=medium]{--dynamic-height: 28rem;@media(width>=1024px){--dynamic-height: 20rem}}&[data-size=large]{--dynamic-height: 36rem;@media(width>=1024px){--dynamic-height: 28rem}}@media(prefers-reduced-motion:reduce){transition:none;transform:none!important}}.dndev-card>.stack-content{display:flex;flex-direction:column;gap:var(--gap-sm);height:calc(100% - 3.5rem);overflow-y:auto;scrollbar-width:none;-ms-overflow-style:none;&::-webkit-scrollbar{display:none}}.stack[data-stacked=true] .stack-content{opacity:0;pointer-events:none}.stack[data-stacked=true] .dndev-stacked-cards-number{opacity:1}.dndev-stacked-cards-spacer{height:3.5rem}.dndev-stacked-cards-number{position:absolute;left:var(--gap-lg);bottom:0;height:3.5rem;display:flex;align-items:center;font-size:var(--font-size-sm);font-weight:500;color:var(--muted-foreground);z-index:10;opacity:1;transition:opacity var(--dur-heavy) var(--ease-heavy)}.dndev-stacked-cards-container{display:flex;flex-direction:column;width:100%;max-width:min(100%,var(--content-width, 60rem));margin-inline:auto;gap:var(--gap-lg);position:relative;z-index:0}.dndev-stacked-cards-header{display:flex;align-items:center;gap:var(--gap-sm)}.dndev-stacked-cards-body{display:flex;flex-direction:column;gap:var(--gap-sm);width:100%;align-items:start;@media(width>=1024px){display:grid;grid-template-columns:1fr auto 1fr;width:100%;align-items:center}}.dndev-stacked-cards-left{display:flex;flex-direction:column;gap:var(--gap-md);text-align:start}.dndev-stacked-cards-left .dndev-card-header+p{margin-top:0}.dndev-stacked-cards-separator{display:block;@media(width<1024px){width:80%!important;height:2px!important;margin-inline:auto;margin-block:var(--gap-sm);align-self:center}@media(width>=1024px){width:1px!important;height:100%!important;align-self:stretch}}.dndev-stacked-cards-right{display:flex;flex-direction:column;justify-content:center;gap:var(--gap-sm);text-align:start}.dndev-stacked-cards-cta{padding-top:var(--gap-sm)}[data-marquee-track]{will-change:var(--will-change-transform);animation:universal-marquee var(--marquee-duration, 0ms) var(--marquee-easing, linear) infinite;animation-direction:var(--marquee-direction, normal);&[data-marquee-direction=vertical]{--transform-start: translateY(0);--transform-end: translateY(calc(-1 * var(--marquee-distance, 0px)))}&[data-marquee-behavior=bounce]{animation-name:universal-float;--transform-start: translateX(0);--transform-mid: translateX(calc(-1 * var(--marquee-distance, 0px)));--opacity-start: 1;--opacity-mid: 1}@media(prefers-reduced-motion:reduce){animation:none!important;transform:none!important}.group:hover &,.group:focus-within &{animation-play-state:paused}}.dndev-reveal-container{contain:layout style;will-change:contents;&.dndev-reveal-visible .dndev-reveal-item{opacity:1;transform:translateZ(0);animation:dndev-reveal-cleanup var(--reveal-duration) var(--reveal-easing) forwards;@media(prefers-reduced-motion:reduce){transition:none!important;opacity:1!important;transform:none!important;will-change:auto}}}.dndev-reveal-item{opacity:0;transform:translateZ(0);will-change:transform,opacity;backface-visibility:hidden;transition:opacity var(--reveal-duration) var(--reveal-easing),transform var(--reveal-duration) var(--reveal-easing);transition-delay:var(--reveal-delay, 0ms);&[data-direction=left]{transform:translate3d(calc(-1 * var(--reveal-distance)),0,0)}&[data-direction=right]{transform:translate3d(var(--reveal-distance),0,0)}&[data-direction=top]{transform:translate3d(0,calc(-1 * var(--reveal-distance)),0)}&[data-direction=bottom]{transform:translate3d(0,var(--reveal-distance),0)}&[data-direction=fade-in]{transform:translateZ(0)}&[data-visible=true]{opacity:1;transform:translateZ(0)}@media(prefers-reduced-motion:reduce){transition:none!important;opacity:1!important;transform:none!important;will-change:auto}}.breath-lung-442{animation:none;will-change:clip-path;&.active{animation:breath-cycle-442 var(--breath-cycle-duration, 16s) ease-in-out var(--breath-cycles, 3)}&.paused{animation-play-state:paused}}.breath-lung-sigh{animation:none;will-change:clip-path;&.active{animation:breath-cycle-sigh var(--breath-cycle-duration, 10s) ease-in-out var(--breath-cycles, 3)}&.paused{animation-play-state:paused}}.network-node{fill:var(--foreground);animation:universal-float 4s ease-in-out infinite;--opacity-start: .3;--opacity-mid: .8;--transform-start: scale(1);--transform-mid: scale(1.1)}.network-line{stroke:var(--foreground);stroke-width:1;animation:universal-float 6s ease-in-out infinite;--opacity-start: .1;--opacity-mid: .5;--transform-start: scale(1);--transform-mid: scale(1)}.wave-flow{background:linear-gradient(45deg,transparent 30%,color-mix(in oklab,var(--accent) 20%,transparent) 50%,transparent 70%);animation:universal-float 8s ease-in-out infinite;--transform-start: translateX(-20%) rotate(0deg);--transform-mid: translateX(20%) rotate(3deg)}.particle-float{animation:universal-slide 10s linear infinite;--opacity-start: .2;--opacity-end: 0;--transform-start: translateY(0px) rotate(0deg);--transform-end: translateY(-100px) rotate(360deg)}.geometric-rotate{animation:universal-float 20s linear infinite;--opacity-start: .1;--opacity-mid: .2;--transform-start: rotate(0deg) scale(1);--transform-mid: rotate(180deg) scale(1.1)}.perspective-1000{perspective:1000px}.transform-style-preserve-3d{transform-style:preserve-3d}.dndev-animate-fade-in-up{animation:universal-slide var(--dur-heavy) ease-out forwards}.animation-delay-100{animation-delay:.1s}.dndev-marketing-stack{display:grid;gap:var(--gap-md)}.dndev-marketing-cluster{display:flex;gap:var(--gap-sm);align-items:center;justify-content:center}
package/dist/index.d.ts CHANGED
@@ -12,6 +12,8 @@ export { default as Marquee } from './components/Marquee';
12
12
  export { default as InspectorGadget } from './components/InspectorGadget';
13
13
  export { default as StackedCards } from './components/StackedCards';
14
14
  export { default as Reveal } from './components/Reveal';
15
+ export { default as Roadmap } from './components/Roadmap';
16
+ export type { RoadmapProps, RoadmapStep } from './components/Roadmap';
15
17
  export * from './components/breathing';
16
18
  export { default as Carousel } from './Carousel';
17
19
  export { default as ComparisonGrid } from './ComparisonGrid';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAGH,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAExD,cAAc,wBAAwB,CAAC;AAEvC,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EACV,eAAe,EACf,SAAS,EACT,YAAY,EACZ,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnD,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAGH,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEtE,cAAc,wBAAwB,CAAC;AAEvC,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EACV,eAAe,EACf,SAAS,EACT,YAAY,EACZ,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnD,cAAc,UAAU,CAAC"}