modal_stack 0.1.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 (37) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +37 -0
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +748 -0
  6. data/Rakefile +12 -0
  7. data/app/assets/javascripts/modal_stack.js +756 -0
  8. data/app/assets/stylesheets/modal_stack/bootstrap.css +232 -0
  9. data/app/assets/stylesheets/modal_stack/tailwind.css +303 -0
  10. data/app/assets/stylesheets/modal_stack/vanilla.css +219 -0
  11. data/app/javascript/modal_stack/controllers/modal_stack_controller.js +149 -0
  12. data/app/javascript/modal_stack/controllers/modal_stack_link_controller.js +34 -0
  13. data/app/javascript/modal_stack/index.js +15 -0
  14. data/app/javascript/modal_stack/install.js +15 -0
  15. data/app/javascript/modal_stack/orchestrator.js +98 -0
  16. data/app/javascript/modal_stack/orchestrator.test.js +260 -0
  17. data/app/javascript/modal_stack/runtime.js +217 -0
  18. data/app/javascript/modal_stack/runtime.test.js +134 -0
  19. data/app/javascript/modal_stack/state.js +315 -0
  20. data/app/javascript/modal_stack/state.test.js +508 -0
  21. data/app/views/layouts/modal.html.erb +6 -0
  22. data/lib/generators/modal_stack/install/install_generator.rb +224 -0
  23. data/lib/generators/modal_stack/install/templates/initializer.rb +57 -0
  24. data/lib/modal_stack/capybara/minitest.rb +9 -0
  25. data/lib/modal_stack/capybara/rspec.rb +9 -0
  26. data/lib/modal_stack/capybara.rb +85 -0
  27. data/lib/modal_stack/configuration.rb +90 -0
  28. data/lib/modal_stack/controller_extensions.rb +73 -0
  29. data/lib/modal_stack/engine.rb +44 -0
  30. data/lib/modal_stack/helpers/modal_link_helper.rb +65 -0
  31. data/lib/modal_stack/helpers/modal_stack_assets_helper.rb +45 -0
  32. data/lib/modal_stack/helpers/modal_stack_container_helper.rb +36 -0
  33. data/lib/modal_stack/initializer_version_check.rb +33 -0
  34. data/lib/modal_stack/turbo_streams_extension.rb +73 -0
  35. data/lib/modal_stack/version.rb +5 -0
  36. data/lib/modal_stack.rb +36 -0
  37. metadata +130 -0
@@ -0,0 +1,232 @@
1
+ /*
2
+ * modal_stack — Bootstrap preset
3
+ *
4
+ * Built on top of Bootstrap 5's CSS custom properties so the modal
5
+ * stack picks up your theme colors / radius / shadows automatically:
6
+ * --bs-body-bg, --bs-body-color, --bs-modal-bg,
7
+ * --bs-modal-border-radius, --bs-box-shadow-lg, --bs-backdrop-bg.
8
+ *
9
+ * Override modal_stack-specific tokens on :root to break free of BS:
10
+ * :root { --modal-stack-radius: 4px; }
11
+ *
12
+ * Variants: [data-variant="modal" | "drawer" | "bottom_sheet" | "confirmation"]
13
+ * Drawer side: [data-side="left" | "right"]
14
+ * Sizes: [data-modal-stack-size="sm" | "md" | "lg" | "xl"]
15
+ */
16
+
17
+ :root {
18
+ --modal-stack-z-base: var(--bs-modal-zindex, 1055);
19
+ --modal-stack-duration: 220ms;
20
+ --modal-stack-ease: cubic-bezier(0.16, 1, 0.3, 1);
21
+ --modal-stack-radius: var(--bs-modal-border-radius, 0.5rem);
22
+ --modal-stack-bg: var(--bs-modal-bg, #fff);
23
+ --modal-stack-fg: var(--bs-body-color, #212529);
24
+ --modal-stack-shadow: var(--bs-box-shadow-lg, 0 1rem 3rem rgba(0, 0, 0, 0.175));
25
+ --modal-stack-backdrop: rgba(var(--bs-backdrop-color, 0, 0, 0), var(--bs-backdrop-opacity, 0.5));
26
+ --modal-stack-backdrop-blur: 0;
27
+ --modal-stack-panel-padding: var(--bs-modal-padding, 1rem);
28
+ --modal-stack-size-sm: 300px;
29
+ --modal-stack-size-md: 500px;
30
+ --modal-stack-size-lg: 800px;
31
+ --modal-stack-size-xl: 1140px;
32
+ --modal-stack-drawer-width: 400px;
33
+ }
34
+
35
+ body[data-modal-stack-locked] {
36
+ overflow: hidden;
37
+ padding-right: var(--modal-stack-scrollbar-width, 0);
38
+ }
39
+
40
+ #modal-stack-root {
41
+ position: fixed;
42
+ inset: 0;
43
+ width: 100vw;
44
+ height: 100vh;
45
+ margin: 0;
46
+ padding: 0;
47
+ border: 0;
48
+ background: transparent;
49
+ max-width: none;
50
+ max-height: none;
51
+ overflow: visible;
52
+ z-index: var(--modal-stack-z-base);
53
+ opacity: 0;
54
+ transition:
55
+ opacity var(--modal-stack-duration) var(--modal-stack-ease),
56
+ overlay var(--modal-stack-duration) var(--modal-stack-ease) allow-discrete,
57
+ display var(--modal-stack-duration) var(--modal-stack-ease) allow-discrete;
58
+ }
59
+
60
+ #modal-stack-root[open] { opacity: 1; }
61
+
62
+ @starting-style {
63
+ #modal-stack-root[open] { opacity: 0; }
64
+ }
65
+
66
+ #modal-stack-root::backdrop {
67
+ background: rgba(0, 0, 0, 0);
68
+ backdrop-filter: blur(0);
69
+ transition:
70
+ background var(--modal-stack-duration) var(--modal-stack-ease),
71
+ backdrop-filter var(--modal-stack-duration) var(--modal-stack-ease),
72
+ overlay var(--modal-stack-duration) var(--modal-stack-ease) allow-discrete,
73
+ display var(--modal-stack-duration) var(--modal-stack-ease) allow-discrete;
74
+ }
75
+
76
+ #modal-stack-root[open]::backdrop {
77
+ background: var(--modal-stack-backdrop);
78
+ backdrop-filter: blur(var(--modal-stack-backdrop-blur));
79
+ }
80
+
81
+ @starting-style {
82
+ #modal-stack-root[open]::backdrop {
83
+ background: rgba(0, 0, 0, 0);
84
+ backdrop-filter: blur(0);
85
+ }
86
+ }
87
+
88
+ [data-modal-stack-target="layer"] {
89
+ position: absolute;
90
+ top: 50%;
91
+ left: 50%;
92
+ width: var(--modal-stack-size-md);
93
+ max-width: 92vw;
94
+ max-height: min(85vh, 720px);
95
+ overflow-y: auto;
96
+ background: var(--modal-stack-bg);
97
+ color: var(--modal-stack-fg);
98
+ border-radius: var(--modal-stack-radius);
99
+ box-shadow: var(--modal-stack-shadow);
100
+ padding: 0;
101
+ transform: translate(-50%, -50%);
102
+ transition:
103
+ transform var(--modal-stack-duration) var(--modal-stack-ease),
104
+ opacity var(--modal-stack-duration) var(--modal-stack-ease),
105
+ filter var(--modal-stack-duration) var(--modal-stack-ease);
106
+ }
107
+
108
+ @starting-style {
109
+ [data-modal-stack-target="layer"] {
110
+ opacity: 0;
111
+ transform: translate(-50%, -44%) scale(0.97);
112
+ }
113
+ }
114
+
115
+ [data-modal-stack-target="layer"][data-leaving] {
116
+ opacity: 0;
117
+ transform: translate(-50%, -56%) scale(0.97);
118
+ pointer-events: none;
119
+ }
120
+
121
+ [data-modal-stack-target="layer"][inert] {
122
+ opacity: 0.5;
123
+ filter: blur(0.5px);
124
+ }
125
+
126
+ [data-modal-stack-target="layer"][data-modal-stack-size="sm"] { width: var(--modal-stack-size-sm); }
127
+ [data-modal-stack-target="layer"][data-modal-stack-size="md"] { width: var(--modal-stack-size-md); }
128
+ [data-modal-stack-target="layer"][data-modal-stack-size="lg"] { width: var(--modal-stack-size-lg); }
129
+ [data-modal-stack-target="layer"][data-modal-stack-size="xl"] { width: var(--modal-stack-size-xl); }
130
+
131
+ [data-modal-stack-target="layer"][data-depth="2"] {
132
+ transform: translate(-50%, -53%) scale(1.015);
133
+ }
134
+
135
+ [data-modal-stack-target="layer"][data-depth="3"] {
136
+ transform: translate(-50%, -56%) scale(1.03);
137
+ }
138
+
139
+ [data-modal-stack-target="layer"][data-depth="4"] {
140
+ transform: translate(-50%, -59%) scale(1.045);
141
+ }
142
+
143
+ /* --- Drawer (Bootstrap offcanvas-flavored) ----------------------- */
144
+
145
+ [data-modal-stack-target="layer"][data-variant="drawer"] {
146
+ top: 0;
147
+ height: 100vh;
148
+ max-height: none;
149
+ width: var(--modal-stack-drawer-width);
150
+ max-width: 90vw;
151
+ }
152
+
153
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="right"] {
154
+ left: auto;
155
+ right: 0;
156
+ transform: translateX(0);
157
+ border-radius: var(--modal-stack-radius) 0 0 var(--modal-stack-radius);
158
+ }
159
+
160
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="left"] {
161
+ left: 0;
162
+ transform: translateX(0);
163
+ border-radius: 0 var(--modal-stack-radius) var(--modal-stack-radius) 0;
164
+ }
165
+
166
+ @starting-style {
167
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="right"] {
168
+ opacity: 0;
169
+ transform: translateX(100%);
170
+ }
171
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="left"] {
172
+ opacity: 0;
173
+ transform: translateX(-100%);
174
+ }
175
+ }
176
+
177
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="right"][data-leaving] {
178
+ opacity: 0;
179
+ transform: translateX(100%);
180
+ }
181
+
182
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="left"][data-leaving] {
183
+ opacity: 0;
184
+ transform: translateX(-100%);
185
+ }
186
+
187
+ /* --- Bottom sheet ------------------------------------------------ */
188
+
189
+ [data-modal-stack-target="layer"][data-variant="bottom_sheet"] {
190
+ top: auto;
191
+ bottom: 0;
192
+ left: 0;
193
+ width: 100vw;
194
+ max-width: none;
195
+ transform: translate(0, 0);
196
+ border-radius: var(--modal-stack-radius) var(--modal-stack-radius) 0 0;
197
+ max-height: 90vh;
198
+ }
199
+
200
+ @starting-style {
201
+ [data-modal-stack-target="layer"][data-variant="bottom_sheet"] {
202
+ opacity: 0;
203
+ transform: translateY(100%);
204
+ }
205
+ }
206
+
207
+ [data-modal-stack-target="layer"][data-variant="bottom_sheet"][data-leaving] {
208
+ opacity: 0;
209
+ transform: translateY(100%);
210
+ }
211
+
212
+ /* --- Confirmation ----------------------------------------------- */
213
+
214
+ [data-modal-stack-target="layer"][data-variant="confirmation"] {
215
+ width: var(--modal-stack-size-sm);
216
+ }
217
+
218
+ /* --- Panel slot ------------------------------------------------- */
219
+
220
+ .modal-stack__panel {
221
+ padding: var(--modal-stack-panel-padding);
222
+ display: grid;
223
+ gap: 0.5rem;
224
+ }
225
+
226
+ @media (prefers-reduced-motion: reduce) {
227
+ #modal-stack-root,
228
+ #modal-stack-root::backdrop,
229
+ [data-modal-stack-target="layer"] {
230
+ transition-duration: 1ms !important;
231
+ }
232
+ }
@@ -0,0 +1,303 @@
1
+ /*
2
+ * modal_stack — Tailwind preset
3
+ *
4
+ * Structural CSS for the <dialog id="modal-stack-root"> + layered
5
+ * `[data-modal-stack-target="layer"]` setup driven by the JS runtime.
6
+ * Visual tokens are exposed as CSS custom properties on `:root` so they
7
+ * can be overridden globally, per scope, or via Tailwind's
8
+ * `:root { --modal-stack-* }` declaration.
9
+ *
10
+ * Variants: [data-variant="modal" | "drawer" | "bottom_sheet" | "confirmation"]
11
+ * Drawer side: [data-side="left" | "right" | "top" | "bottom"]
12
+ * Sizes: [data-modal-stack-size="sm" | "md" | "lg" | "xl"]
13
+ *
14
+ * Entry / exit transitions:
15
+ * - @starting-style + transition-behavior: allow-discrete (Chrome 117+,
16
+ * Safari 17.4+, Firefox 129+).
17
+ * - The runtime sets [data-leaving] before unmounting a layer so the
18
+ * same transition rules apply on exit.
19
+ */
20
+
21
+ :root {
22
+ --modal-stack-z-base: 1000;
23
+ --modal-stack-duration: 220ms;
24
+ --modal-stack-ease: cubic-bezier(0.16, 1, 0.3, 1);
25
+ --modal-stack-radius: 14px;
26
+ --modal-stack-bg: #ffffff;
27
+ --modal-stack-fg: #0f172a;
28
+ --modal-stack-shadow: 0 30px 60px -20px rgba(15, 23, 42, 0.35);
29
+ --modal-stack-backdrop: rgba(15, 23, 42, 0.55);
30
+ --modal-stack-backdrop-blur: 2px;
31
+ --modal-stack-panel-padding: 24px;
32
+ --modal-stack-size-sm: 24rem; /* 384px */
33
+ --modal-stack-size-md: 34rem; /* 544px */
34
+ --modal-stack-size-lg: 48rem; /* 768px */
35
+ --modal-stack-size-xl: 64rem; /* 1024px */
36
+ --modal-stack-drawer-width: 28rem; /* 448px */
37
+ --modal-stack-drawer-height: 22rem; /* 352px */
38
+ }
39
+
40
+ /* --- Body lock when the stack is open ------------------------------- */
41
+
42
+ body[data-modal-stack-locked] {
43
+ overflow: hidden;
44
+ /* Compensate for the scrollbar width to avoid a layout shift. */
45
+ padding-right: var(--modal-stack-scrollbar-width, 0);
46
+ }
47
+
48
+ /* --- The single dialog root ---------------------------------------- */
49
+
50
+ #modal-stack-root {
51
+ position: fixed;
52
+ inset: 0;
53
+ width: 100vw;
54
+ height: 100vh;
55
+ margin: 0;
56
+ padding: 0;
57
+ border: 0;
58
+ background: transparent;
59
+ max-width: none;
60
+ max-height: none;
61
+ overflow: visible;
62
+ z-index: var(--modal-stack-z-base);
63
+ opacity: 0;
64
+ transition:
65
+ opacity var(--modal-stack-duration) var(--modal-stack-ease),
66
+ overlay var(--modal-stack-duration) var(--modal-stack-ease) allow-discrete,
67
+ display var(--modal-stack-duration) var(--modal-stack-ease) allow-discrete;
68
+ }
69
+
70
+ #modal-stack-root[open] {
71
+ opacity: 1;
72
+ }
73
+
74
+ @starting-style {
75
+ #modal-stack-root[open] {
76
+ opacity: 0;
77
+ }
78
+ }
79
+
80
+ #modal-stack-root::backdrop {
81
+ background: rgba(15, 23, 42, 0);
82
+ backdrop-filter: blur(0);
83
+ transition:
84
+ background var(--modal-stack-duration) var(--modal-stack-ease),
85
+ backdrop-filter var(--modal-stack-duration) var(--modal-stack-ease),
86
+ overlay var(--modal-stack-duration) var(--modal-stack-ease) allow-discrete,
87
+ display var(--modal-stack-duration) var(--modal-stack-ease) allow-discrete;
88
+ }
89
+
90
+ #modal-stack-root[open]::backdrop {
91
+ background: var(--modal-stack-backdrop);
92
+ backdrop-filter: blur(var(--modal-stack-backdrop-blur));
93
+ }
94
+
95
+ @starting-style {
96
+ #modal-stack-root[open]::backdrop {
97
+ background: rgba(15, 23, 42, 0);
98
+ backdrop-filter: blur(0);
99
+ }
100
+ }
101
+
102
+ /* --- Layer (one per modal, vertically stacked Z-axis) -------------- */
103
+
104
+ [data-modal-stack-target="layer"] {
105
+ position: absolute;
106
+ top: 50%;
107
+ left: 50%;
108
+ width: var(--modal-stack-size-md);
109
+ max-width: 92vw;
110
+ max-height: min(85vh, 720px);
111
+ overflow-y: auto;
112
+ background: var(--modal-stack-bg);
113
+ color: var(--modal-stack-fg);
114
+ border-radius: var(--modal-stack-radius);
115
+ box-shadow: var(--modal-stack-shadow);
116
+ padding: 0;
117
+ transform: translate(-50%, -50%);
118
+ transition:
119
+ transform var(--modal-stack-duration) var(--modal-stack-ease),
120
+ opacity var(--modal-stack-duration) var(--modal-stack-ease),
121
+ filter var(--modal-stack-duration) var(--modal-stack-ease);
122
+ }
123
+
124
+ @starting-style {
125
+ [data-modal-stack-target="layer"] {
126
+ opacity: 0;
127
+ transform: translate(-50%, -44%) scale(0.97);
128
+ }
129
+ }
130
+
131
+ [data-modal-stack-target="layer"][data-leaving] {
132
+ opacity: 0;
133
+ transform: translate(-50%, -56%) scale(0.97);
134
+ pointer-events: none;
135
+ }
136
+
137
+ [data-modal-stack-target="layer"][inert] {
138
+ opacity: 0.5;
139
+ filter: blur(0.5px);
140
+ }
141
+
142
+ /* --- Sizes via [data-modal-stack-size] ----------------------------- */
143
+
144
+ [data-modal-stack-target="layer"][data-modal-stack-size="sm"] { width: var(--modal-stack-size-sm); }
145
+ [data-modal-stack-target="layer"][data-modal-stack-size="md"] { width: var(--modal-stack-size-md); }
146
+ [data-modal-stack-target="layer"][data-modal-stack-size="lg"] { width: var(--modal-stack-size-lg); }
147
+ [data-modal-stack-target="layer"][data-modal-stack-size="xl"] { width: var(--modal-stack-size-xl); }
148
+
149
+ /* --- Subtle depth offset for stacked layers ----------------------- */
150
+
151
+ [data-modal-stack-target="layer"][data-depth="2"] {
152
+ transform: translate(-50%, -53%) scale(1.015);
153
+ }
154
+
155
+ [data-modal-stack-target="layer"][data-depth="3"] {
156
+ transform: translate(-50%, -56%) scale(1.03);
157
+ }
158
+
159
+ [data-modal-stack-target="layer"][data-depth="4"] {
160
+ transform: translate(-50%, -59%) scale(1.045);
161
+ }
162
+
163
+ /* --- Drawer ------------------------------------------------------- */
164
+
165
+ [data-modal-stack-target="layer"][data-variant="drawer"] {
166
+ left: 0;
167
+ top: 0;
168
+ max-width: 100vw;
169
+ max-height: 100vh;
170
+ }
171
+
172
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="right"],
173
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="left"] {
174
+ top: 0;
175
+ height: 100vh;
176
+ max-height: none;
177
+ width: var(--modal-stack-drawer-width);
178
+ max-width: 90vw;
179
+ }
180
+
181
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="right"] {
182
+ left: auto;
183
+ right: 0;
184
+ transform: translateX(0);
185
+ border-radius: var(--modal-stack-radius) 0 0 var(--modal-stack-radius);
186
+ }
187
+
188
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="left"] {
189
+ left: 0;
190
+ transform: translateX(0);
191
+ border-radius: 0 var(--modal-stack-radius) var(--modal-stack-radius) 0;
192
+ }
193
+
194
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="top"] {
195
+ left: 0;
196
+ top: 0;
197
+ width: 100vw;
198
+ max-width: none;
199
+ height: var(--modal-stack-drawer-height);
200
+ max-height: 85vh;
201
+ transform: translateY(0);
202
+ border-radius: 0 0 var(--modal-stack-radius) var(--modal-stack-radius);
203
+ }
204
+
205
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="bottom"] {
206
+ left: 0;
207
+ top: auto;
208
+ bottom: 0;
209
+ width: 100vw;
210
+ max-width: none;
211
+ height: var(--modal-stack-drawer-height);
212
+ max-height: 85vh;
213
+ transform: translateY(0);
214
+ border-radius: var(--modal-stack-radius) var(--modal-stack-radius) 0 0;
215
+ }
216
+
217
+ @starting-style {
218
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="right"] {
219
+ opacity: 0;
220
+ transform: translateX(100%);
221
+ }
222
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="left"] {
223
+ opacity: 0;
224
+ transform: translateX(-100%);
225
+ }
226
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="top"] {
227
+ opacity: 0;
228
+ transform: translateY(-100%);
229
+ }
230
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="bottom"] {
231
+ opacity: 0;
232
+ transform: translateY(100%);
233
+ }
234
+ }
235
+
236
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="right"][data-leaving] {
237
+ opacity: 0;
238
+ transform: translateX(100%);
239
+ }
240
+
241
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="left"][data-leaving] {
242
+ opacity: 0;
243
+ transform: translateX(-100%);
244
+ }
245
+
246
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="top"][data-leaving] {
247
+ opacity: 0;
248
+ transform: translateY(-100%);
249
+ }
250
+
251
+ [data-modal-stack-target="layer"][data-variant="drawer"][data-side="bottom"][data-leaving] {
252
+ opacity: 0;
253
+ transform: translateY(100%);
254
+ }
255
+
256
+ /* --- Bottom sheet ------------------------------------------------- */
257
+
258
+ [data-modal-stack-target="layer"][data-variant="bottom_sheet"] {
259
+ top: auto;
260
+ bottom: 0;
261
+ left: 0;
262
+ width: 100vw;
263
+ max-width: none;
264
+ transform: translate(0, 0);
265
+ border-radius: var(--modal-stack-radius) var(--modal-stack-radius) 0 0;
266
+ max-height: 90vh;
267
+ }
268
+
269
+ @starting-style {
270
+ [data-modal-stack-target="layer"][data-variant="bottom_sheet"] {
271
+ opacity: 0;
272
+ transform: translateY(100%);
273
+ }
274
+ }
275
+
276
+ [data-modal-stack-target="layer"][data-variant="bottom_sheet"][data-leaving] {
277
+ opacity: 0;
278
+ transform: translateY(100%);
279
+ }
280
+
281
+ /* --- Confirmation ------------------------------------------------- */
282
+
283
+ [data-modal-stack-target="layer"][data-variant="confirmation"] {
284
+ width: var(--modal-stack-size-sm);
285
+ }
286
+
287
+ /* --- Panel slot (the modal_stack_container output) --------------- */
288
+
289
+ .modal-stack__panel {
290
+ padding: var(--modal-stack-panel-padding);
291
+ display: grid;
292
+ gap: 14px;
293
+ }
294
+
295
+ /* --- Reduced motion ---------------------------------------------- */
296
+
297
+ @media (prefers-reduced-motion: reduce) {
298
+ #modal-stack-root,
299
+ #modal-stack-root::backdrop,
300
+ [data-modal-stack-target="layer"] {
301
+ transition-duration: 1ms !important;
302
+ }
303
+ }