srcdev-nuxt-components 9.1.41 → 9.1.43

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.
@@ -1,15 +1,53 @@
1
+ import { computed } from "vue";
1
2
  import type { Meta, StoryFn } from "@nuxtjs/storybook";
2
- import DataGridComponent from "../DataGrid.vue";
3
+ import AutoGridComponent from "../AutoGrid.vue";
3
4
 
4
- const meta: Meta<typeof DataGridComponent> = {
5
- title: "Atoms/Grids/DataGrid",
6
- component: DataGridComponent,
5
+ interface AutoGridArgs {
6
+ tag: "div" | "section" | "article" | "main";
7
+ isResponsive: boolean;
8
+ styleClassPassthrough: string[];
9
+ minColSizeSmall: string;
10
+ minColSizeDefault: string;
11
+ minColSizeLarge: string;
12
+ gap: string;
13
+ }
14
+
15
+ const meta: Meta<AutoGridArgs> = {
16
+ title: "Atoms/Grids/AutoGrid",
17
+ component: AutoGridComponent,
7
18
  argTypes: {
8
19
  tag: {
9
20
  control: { type: "select" },
10
21
  options: ["div", "section", "article", "main"],
11
22
  description: "HTML tag to render as",
12
- table: { category: "Semantic" },
23
+ table: { category: "Props" },
24
+ },
25
+ isResponsive: {
26
+ control: { type: "boolean" },
27
+ description:
28
+ "Enables container-query breakpoints: `--auto-grid-min-col-size-small` below 768px, default 768px+, large 1024px+. Requires a `container-type: inline-size` ancestor.",
29
+ table: { category: "Props" },
30
+ },
31
+ minColSizeSmall: {
32
+ control: { type: "text" },
33
+ description: "`--auto-grid-min-col-size-small` — minimum column width in responsive mode below 768px",
34
+ table: { category: "CSS Tokens" },
35
+ },
36
+ minColSizeDefault: {
37
+ control: { type: "text" },
38
+ description:
39
+ "`--auto-grid-min-col-size-default` — controls column width when `isResponsive` is **off**. Also used as the mid-size step in responsive mode (768px+).",
40
+ table: { category: "CSS Tokens" },
41
+ },
42
+ minColSizeLarge: {
43
+ control: { type: "text" },
44
+ description: "`--auto-grid-min-col-size-large` — minimum column width in responsive mode 1024px+",
45
+ table: { category: "CSS Tokens" },
46
+ },
47
+ gap: {
48
+ control: { type: "text" },
49
+ description: "`--auto-grid-gap` — gap between grid items",
50
+ table: { category: "CSS Tokens" },
13
51
  },
14
52
  styleClassPassthrough: {
15
53
  table: { disable: true },
@@ -17,13 +55,18 @@ const meta: Meta<typeof DataGridComponent> = {
17
55
  },
18
56
  args: {
19
57
  tag: "div",
58
+ isResponsive: false,
59
+ minColSizeSmall: "250px",
60
+ minColSizeDefault: "300px",
61
+ minColSizeLarge: "350px",
62
+ gap: "1rem",
20
63
  styleClassPassthrough: [],
21
64
  },
22
65
  parameters: {
23
66
  docs: {
24
67
  description: {
25
68
  component:
26
- "A responsive auto-fit grid container. Uses CSS custom properties `--data-grid-columns` and `--data-grid-gap` to control layout. Renders named slots provided by the consumer.",
69
+ "A responsive auto-fit grid container. Override `--auto-grid-min-col-size-default` and `--auto-grid-gap` to control layout. Enable `isResponsive` for container-query-based column steps using `--auto-grid-min-col-size-small` and `--auto-grid-min-col-size-large`.",
27
70
  },
28
71
  },
29
72
  },
@@ -33,22 +76,24 @@ export default meta;
33
76
 
34
77
  const cardStyle =
35
78
  "padding: 2.4rem; background: white; border-radius: 0.8rem; box-shadow: 0 2px 8px rgba(0,0,0,0.08); display: flex; flex-direction: column; gap: 0.8rem;";
36
- const labelStyle = "font-size: 1.2rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: #6b7280;";
79
+ const labelStyle =
80
+ "font-size: 1.2rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: #6b7280;";
37
81
  const valueStyle = "font-size: 2.4rem; font-weight: 700; color: #111827;";
38
82
 
39
- interface DataGridArgs {
40
- tag: "div" | "section" | "article" | "main";
41
- styleClassPassthrough: string[];
42
- }
43
-
44
- const Template: StoryFn<DataGridArgs> = (args) => ({
45
- components: { DataGridComponent },
83
+ const Template: StoryFn<AutoGridArgs> = (args) => ({
84
+ components: { AutoGridComponent },
46
85
  setup() {
47
- return { args };
86
+ const cssTokenStyle = computed(() => ({
87
+ "--auto-grid-min-col-size-small": args.minColSizeSmall,
88
+ "--auto-grid-min-col-size-default": args.minColSizeDefault,
89
+ "--auto-grid-min-col-size-large": args.minColSizeLarge,
90
+ "--auto-grid-gap": args.gap,
91
+ }));
92
+ return { args, cssTokenStyle };
48
93
  },
49
94
  template: `
50
- <div style="padding: 3.2rem; background: #f9fafb;">
51
- <DataGridComponent :tag="args.tag" :style-class-passthrough="args.styleClassPassthrough">
95
+ <div style="padding: 3.2rem; background: #f9fafb; container-type: inline-size;">
96
+ <AutoGridComponent :tag="args.tag" :is-responsive="args.isResponsive" :style="cssTokenStyle" :style-class-passthrough="args.styleClassPassthrough">
52
97
  <template #item-1>
53
98
  <div style="${cardStyle}">
54
99
  <span style="${labelStyle}">Revenue</span>
@@ -73,7 +118,7 @@ const Template: StoryFn<DataGridArgs> = (args) => ({
73
118
  <span style="${valueStyle}">4.9</span>
74
119
  </div>
75
120
  </template>
76
- </DataGridComponent>
121
+ </AutoGridComponent>
77
122
  </div>
78
123
  `,
79
124
  });
@@ -82,7 +127,18 @@ export const Default = Template.bind({});
82
127
  Default.parameters = {
83
128
  docs: {
84
129
  description: {
85
- story: "Default grid with four stat cards. Columns auto-fit to available space at a minimum of 250px each.",
130
+ story: "Default grid with four stat cards. Columns auto-fit to available space at a minimum of 300px each.",
131
+ },
132
+ },
133
+ };
134
+
135
+ export const Responsive = Template.bind({});
136
+ Responsive.args = { isResponsive: true };
137
+ Responsive.parameters = {
138
+ docs: {
139
+ description: {
140
+ story:
141
+ "With `isResponsive` enabled, column width steps through three sizes based on container width. Resize the story viewport to see the breakpoints in action.",
86
142
  },
87
143
  },
88
144
  };
@@ -91,10 +147,10 @@ export const TwoItems = Template.bind({});
91
147
  TwoItems.storyName = "Two Items";
92
148
  TwoItems.decorators = [
93
149
  () => ({
94
- components: { DataGridComponent },
150
+ components: { AutoGridComponent },
95
151
  template: `
96
- <div style="padding: 3.2rem; background: #f9fafb;">
97
- <DataGridComponent>
152
+ <div style="padding: 3.2rem; background: #f9fafb; container-type: inline-size;">
153
+ <AutoGridComponent>
98
154
  <template #item-1>
99
155
  <div style="${cardStyle}">
100
156
  <span style="${labelStyle}">Revenue</span>
@@ -107,7 +163,7 @@ TwoItems.decorators = [
107
163
  <span style="${valueStyle}">142</span>
108
164
  </div>
109
165
  </template>
110
- </DataGridComponent>
166
+ </AutoGridComponent>
111
167
  </div>
112
168
  `,
113
169
  }),
@@ -116,15 +172,15 @@ TwoItems.parameters = {
116
172
  docs: { description: { story: "Grid with two items — auto-fit spreads them to fill available columns." } },
117
173
  };
118
174
 
119
- export const NarrowContainer: StoryFn<DataGridArgs> = (args) => ({
120
- components: { DataGridComponent },
175
+ export const NarrowContainer: StoryFn<AutoGridArgs> = (args) => ({
176
+ components: { AutoGridComponent },
121
177
  setup() {
122
178
  return { args };
123
179
  },
124
180
  template: `
125
181
  <div style="padding: 3.2rem; background: #f9fafb;">
126
- <div style="max-width: 400px;">
127
- <DataGridComponent :tag="args.tag">
182
+ <div style="max-width: 400px; container-type: inline-size;">
183
+ <AutoGridComponent :tag="args.tag">
128
184
  <template #item-1>
129
185
  <div style="${cardStyle}">
130
186
  <span style="${labelStyle}">Revenue</span>
@@ -143,7 +199,7 @@ export const NarrowContainer: StoryFn<DataGridArgs> = (args) => ({
143
199
  <span style="${valueStyle}">38</span>
144
200
  </div>
145
201
  </template>
146
- </DataGridComponent>
202
+ </AutoGridComponent>
147
203
  </div>
148
204
  </div>
149
205
  `,
@@ -151,19 +207,19 @@ export const NarrowContainer: StoryFn<DataGridArgs> = (args) => ({
151
207
  NarrowContainer.parameters = {
152
208
  docs: {
153
209
  description: {
154
- story: "In a 400px container the auto-fit columns stack to a single column once items fall below 250px.",
210
+ story: "In a 400px container the auto-fit columns stack to a single column once items fall below 300px.",
155
211
  },
156
212
  },
157
213
  };
158
214
 
159
- export const CustomColumns: StoryFn<DataGridArgs> = (args) => ({
160
- components: { DataGridComponent },
215
+ export const CustomColumns: StoryFn<AutoGridArgs> = (args) => ({
216
+ components: { AutoGridComponent },
161
217
  setup() {
162
218
  return { args };
163
219
  },
164
220
  template: `
165
221
  <div style="padding: 3.2rem; background: #f9fafb;">
166
- <DataGridComponent style="--data-grid-columns: repeat(3, 1fr); --data-grid-gap: 2.4rem;" :tag="args.tag">
222
+ <AutoGridComponent style="grid-template-columns: repeat(3, 1fr); --auto-grid-gap: 2.4rem;" :tag="args.tag">
167
223
  <template #item-1>
168
224
  <div style="${cardStyle}">
169
225
  <span style="${labelStyle}">Revenue</span>
@@ -182,7 +238,7 @@ export const CustomColumns: StoryFn<DataGridArgs> = (args) => ({
182
238
  <span style="${valueStyle}">38</span>
183
239
  </div>
184
240
  </template>
185
- </DataGridComponent>
241
+ </AutoGridComponent>
186
242
  </div>
187
243
  `,
188
244
  });
@@ -190,19 +246,19 @@ CustomColumns.parameters = {
190
246
  docs: {
191
247
  description: {
192
248
  story:
193
- "Override `--data-grid-columns` and `--data-grid-gap` via inline style to force a fixed 3-column layout with wider gaps.",
249
+ "Override `grid-template-columns` and `--auto-grid-gap` via inline style to force a fixed 3-column layout with wider gaps.",
194
250
  },
195
251
  },
196
252
  };
197
253
 
198
- export const SemanticSection: StoryFn<DataGridArgs> = (args) => ({
199
- components: { DataGridComponent },
254
+ export const SemanticSection: StoryFn<AutoGridArgs> = (args) => ({
255
+ components: { AutoGridComponent },
200
256
  setup() {
201
257
  return { args };
202
258
  },
203
259
  template: `
204
- <div style="padding: 3.2rem; background: #f9fafb;">
205
- <DataGridComponent tag="section">
260
+ <div style="padding: 3.2rem; background: #f9fafb; container-type: inline-size;">
261
+ <AutoGridComponent tag="section">
206
262
  <template #item-1>
207
263
  <div style="${cardStyle}">
208
264
  <span style="${labelStyle}">Revenue</span>
@@ -221,7 +277,7 @@ export const SemanticSection: StoryFn<DataGridArgs> = (args) => ({
221
277
  <span style="${valueStyle}">38</span>
222
278
  </div>
223
279
  </template>
224
- </DataGridComponent>
280
+ </AutoGridComponent>
225
281
  </div>
226
282
  `,
227
283
  });
@@ -1,26 +1,27 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import { mountSuspended } from "@nuxt/test-utils/runtime";
3
- import DataGrid from "../DataGrid.vue";
3
+ import AutoGrid from "../AutoGrid.vue";
4
4
 
5
- describe("DataGrid", () => {
5
+ describe("AutoGrid", () => {
6
6
  // ─── Mount ───────────────────────────────────────────────────────────────
7
7
 
8
8
  it("mounts without error", async () => {
9
- const wrapper = await mountSuspended(DataGrid);
9
+ const wrapper = await mountSuspended(AutoGrid);
10
10
  expect(wrapper.vm).toBeTruthy();
11
11
  });
12
12
 
13
13
  // ─── Snapshots ───────────────────────────────────────────────────────────
14
14
 
15
15
  it("renders correct HTML structure (default props)", async () => {
16
- const wrapper = await mountSuspended(DataGrid);
16
+ const wrapper = await mountSuspended(AutoGrid);
17
17
  expect(wrapper.html()).toMatchSnapshot();
18
18
  });
19
19
 
20
20
  it("renders correct HTML structure (all props and slots set)", async () => {
21
- const wrapper = await mountSuspended(DataGrid, {
21
+ const wrapper = await mountSuspended(AutoGrid, {
22
22
  props: {
23
23
  tag: "section",
24
+ isResponsive: true,
24
25
  styleClassPassthrough: ["custom-class"],
25
26
  },
26
27
  slots: {
@@ -35,58 +36,77 @@ describe("DataGrid", () => {
35
36
  // ─── Root element ────────────────────────────────────────────────────────
36
37
 
37
38
  it("renders a <div> as the root element by default", async () => {
38
- const wrapper = await mountSuspended(DataGrid);
39
+ const wrapper = await mountSuspended(AutoGrid);
39
40
  expect(wrapper.element.tagName).toBe("DIV");
40
41
  });
41
42
 
42
- it("always has the data-grid class", async () => {
43
- const wrapper = await mountSuspended(DataGrid);
44
- expect(wrapper.classes()).toContain("data-grid");
43
+ it("always has the auto-grid class", async () => {
44
+ const wrapper = await mountSuspended(AutoGrid);
45
+ expect(wrapper.classes()).toContain("auto-grid");
45
46
  });
46
47
 
47
48
  // ─── Tag prop ────────────────────────────────────────────────────────────
48
49
 
49
50
  it("renders a <section> when tag is section", async () => {
50
- const wrapper = await mountSuspended(DataGrid, { props: { tag: "section" } });
51
+ const wrapper = await mountSuspended(AutoGrid, { props: { tag: "section" } });
51
52
  expect(wrapper.element.tagName).toBe("SECTION");
52
53
  });
53
54
 
54
55
  it("renders an <article> when tag is article", async () => {
55
- const wrapper = await mountSuspended(DataGrid, { props: { tag: "article" } });
56
+ const wrapper = await mountSuspended(AutoGrid, { props: { tag: "article" } });
56
57
  expect(wrapper.element.tagName).toBe("ARTICLE");
57
58
  });
58
59
 
59
60
  it("renders a <main> when tag is main", async () => {
60
- const wrapper = await mountSuspended(DataGrid, { props: { tag: "main" } });
61
+ const wrapper = await mountSuspended(AutoGrid, { props: { tag: "main" } });
61
62
  expect(wrapper.element.tagName).toBe("MAIN");
62
63
  });
63
64
 
64
65
  // ─── Aria ─────────────────────────────────────────────────────────────────
65
66
 
66
67
  it("does not set aria-labelledby when tag is div", async () => {
67
- const wrapper = await mountSuspended(DataGrid, { props: { tag: "div" } });
68
+ const wrapper = await mountSuspended(AutoGrid, { props: { tag: "div" } });
68
69
  expect(wrapper.attributes("aria-labelledby")).toBeUndefined();
69
70
  });
70
71
 
71
72
  it("sets aria-labelledby when tag is section", async () => {
72
- const wrapper = await mountSuspended(DataGrid, { props: { tag: "section" } });
73
+ const wrapper = await mountSuspended(AutoGrid, { props: { tag: "section" } });
73
74
  expect(wrapper.attributes("aria-labelledby")).toBeTruthy();
74
75
  });
75
76
 
76
77
  it("sets aria-labelledby when tag is article", async () => {
77
- const wrapper = await mountSuspended(DataGrid, { props: { tag: "article" } });
78
+ const wrapper = await mountSuspended(AutoGrid, { props: { tag: "article" } });
78
79
  expect(wrapper.attributes("aria-labelledby")).toBeTruthy();
79
80
  });
80
81
 
81
82
  it("sets aria-labelledby when tag is main", async () => {
82
- const wrapper = await mountSuspended(DataGrid, { props: { tag: "main" } });
83
+ const wrapper = await mountSuspended(AutoGrid, { props: { tag: "main" } });
83
84
  expect(wrapper.attributes("aria-labelledby")).toBeTruthy();
84
85
  });
85
86
 
87
+ // ─── isResponsive ────────────────────────────────────────────────────────
88
+
89
+ it("does not have is-responsive class by default", async () => {
90
+ const wrapper = await mountSuspended(AutoGrid);
91
+ expect(wrapper.classes()).not.toContain("is-responsive");
92
+ });
93
+
94
+ it("adds is-responsive class when isResponsive is true", async () => {
95
+ const wrapper = await mountSuspended(AutoGrid, { props: { isResponsive: true } });
96
+ expect(wrapper.classes()).toContain("is-responsive");
97
+ });
98
+
99
+ it("removes is-responsive class when isResponsive changes to false", async () => {
100
+ const wrapper = await mountSuspended(AutoGrid, { props: { isResponsive: true } });
101
+ expect(wrapper.classes()).toContain("is-responsive");
102
+ await wrapper.setProps({ isResponsive: false });
103
+ expect(wrapper.classes()).not.toContain("is-responsive");
104
+ });
105
+
86
106
  // ─── Slots ───────────────────────────────────────────────────────────────
87
107
 
88
108
  it("renders a named slot", async () => {
89
- const wrapper = await mountSuspended(DataGrid, {
109
+ const wrapper = await mountSuspended(AutoGrid, {
90
110
  slots: { "item-1": "<div class='card'>Card 1</div>" },
91
111
  });
92
112
  expect(wrapper.find(".card").exists()).toBe(true);
@@ -94,7 +114,7 @@ describe("DataGrid", () => {
94
114
  });
95
115
 
96
116
  it("renders multiple named slots", async () => {
97
- const wrapper = await mountSuspended(DataGrid, {
117
+ const wrapper = await mountSuspended(AutoGrid, {
98
118
  slots: {
99
119
  "item-1": "<div class='card-1'>Card 1</div>",
100
120
  "item-2": "<div class='card-2'>Card 2</div>",
@@ -107,21 +127,21 @@ describe("DataGrid", () => {
107
127
  });
108
128
 
109
129
  it("renders no slot content when no slots are provided", async () => {
110
- const wrapper = await mountSuspended(DataGrid);
130
+ const wrapper = await mountSuspended(AutoGrid);
111
131
  expect(wrapper.text()).toBe("");
112
132
  });
113
133
 
114
134
  // ─── styleClassPassthrough ───────────────────────────────────────────────
115
135
 
116
136
  it("applies a single styleClassPassthrough string to the root", async () => {
117
- const wrapper = await mountSuspended(DataGrid, {
137
+ const wrapper = await mountSuspended(AutoGrid, {
118
138
  props: { styleClassPassthrough: "my-grid" },
119
139
  });
120
140
  expect(wrapper.classes()).toContain("my-grid");
121
141
  });
122
142
 
123
143
  it("applies multiple styleClassPassthrough classes from an array", async () => {
124
- const wrapper = await mountSuspended(DataGrid, {
144
+ const wrapper = await mountSuspended(AutoGrid, {
125
145
  props: { styleClassPassthrough: ["my-grid", "mbe-32"] },
126
146
  });
127
147
  expect(wrapper.classes()).toContain("my-grid");
@@ -129,7 +149,7 @@ describe("DataGrid", () => {
129
149
  });
130
150
 
131
151
  it("updates classes when styleClassPassthrough prop changes", async () => {
132
- const wrapper = await mountSuspended(DataGrid, {
152
+ const wrapper = await mountSuspended(AutoGrid, {
133
153
  props: { styleClassPassthrough: ["original"] },
134
154
  });
135
155
  expect(wrapper.classes()).toContain("original");
@@ -0,0 +1,11 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`AutoGrid > renders correct HTML structure (all props and slots set) 1`] = `
4
+ "<section class="auto-grid custom-class is-responsive" aria-labelledby="v-0-0">
5
+ <div>Item 1</div>
6
+ <div>Item 2</div>
7
+ <div>Item 3</div>
8
+ </section>"
9
+ `;
10
+
11
+ exports[`AutoGrid > renders correct HTML structure (default props) 1`] = `"<div class="auto-grid"></div>"`;
@@ -1,11 +1,11 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`DataGrid > renders correct HTML structure (all props and slots set) 1`] = `
4
- "<section class="data-grid custom-class" aria-labelledby="v-0-0">
3
+ exports[`AutoGrid > renders correct HTML structure (all props and slots set) 1`] = `
4
+ "<section class="auto-grid custom-class" aria-labelledby="v-0-0">
5
5
  <div>Item 1</div>
6
6
  <div>Item 2</div>
7
7
  <div>Item 3</div>
8
8
  </section>"
9
9
  `;
10
10
 
11
- exports[`DataGrid > renders correct HTML structure (default props) 1`] = `"<div class="data-grid"></div>"`;
11
+ exports[`AutoGrid > renders correct HTML structure (default props) 1`] = `"<div class="auto-grid"></div>"`;
@@ -1,12 +1,13 @@
1
1
  <template>
2
2
  <div :class="['samaritan-prompt', elementClasses]">
3
- <div class="samaritan-prompt__content" :style="{ opacity: textOpacity }">
3
+ <div class="samaritan-prompt__content" :style="{ opacity: textOpacity }" aria-hidden="true">
4
4
  <div class="samaritan-prompt__stage">
5
5
  <span class="samaritan-prompt__text">{{ displayText }}</span>
6
6
  </div>
7
7
  <div class="samaritan-prompt__underline"></div>
8
8
  </div>
9
9
  <span class="samaritan-prompt__cursor" :style="{ opacity: cursorOpacity }" aria-hidden="true">▲</span>
10
+ <span class="samaritan-prompt__sr-text" aria-live="polite" aria-atomic="true">{{ announcedText }}</span>
10
11
  </div>
11
12
  </template>
12
13
 
@@ -53,6 +54,7 @@ const props = withDefaults(defineProps<Props>(), {
53
54
  const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
54
55
 
55
56
  const displayText = ref("");
57
+ const announcedText = ref("");
56
58
  const textOpacity = ref(1);
57
59
  const cursorVisible = ref(true);
58
60
  const activeFadeDuration = ref(props.fadeDuration);
@@ -85,7 +87,9 @@ const runTypewriter = async (config: ResolvedConfig) => {
85
87
  await wait(typeSpeed);
86
88
  }
87
89
 
90
+ announcedText.value = text;
88
91
  await wait(holdDuration);
92
+ announcedText.value = "";
89
93
 
90
94
  while (displayText.value.length > 0) {
91
95
  displayText.value = displayText.value.slice(0, -1);
@@ -112,8 +116,10 @@ const runWordPulse = async (config: ResolvedConfig) => {
112
116
  await wait(120);
113
117
 
114
118
  textOpacity.value = 1;
119
+ announcedText.value = text;
115
120
  await wait(wordDuration);
116
121
 
122
+ announcedText.value = "";
117
123
  textOpacity.value = 0;
118
124
  await wait(fadeDuration);
119
125
 
@@ -221,6 +227,30 @@ onUnmounted(stop);
221
227
  animation: samaritan-pulse 2.5s ease-in-out infinite;
222
228
  transition: opacity 400ms ease;
223
229
  }
230
+
231
+ .samaritan-prompt__sr-text {
232
+ position: absolute;
233
+ width: 1px;
234
+ height: 1px;
235
+ padding: 0;
236
+ margin: -1px;
237
+ overflow: hidden;
238
+ clip: rect(0, 0, 0, 0);
239
+ white-space: nowrap;
240
+ border: 0;
241
+ }
242
+ }
243
+
244
+ @media (prefers-reduced-motion: reduce) {
245
+ .samaritan-prompt {
246
+ .samaritan-prompt__content {
247
+ transition: none;
248
+ }
249
+
250
+ .samaritan-prompt__cursor {
251
+ animation: none;
252
+ }
253
+ }
224
254
  }
225
255
 
226
256
  @keyframes samaritan-pulse {