@getvitops/generator 0.1.0

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 (75) hide show
  1. package/README.md +35 -0
  2. package/assets/bricks/elements/carousel.php +89 -0
  3. package/assets/bricks/elements/centered.php +128 -0
  4. package/assets/bricks/elements/color-scheme-toggle.php +61 -0
  5. package/assets/bricks/elements/copy-button.php +65 -0
  6. package/assets/bricks/elements/dismissable.php +93 -0
  7. package/assets/bricks/elements/entries.php +96 -0
  8. package/assets/bricks/elements/image-compare.php +132 -0
  9. package/assets/bricks/elements/multi-field.php +148 -0
  10. package/assets/bricks/elements/sitenav.php +298 -0
  11. package/assets/bricks/elements/split-link.php +170 -0
  12. package/assets/bricks/elements/split-panel.php +155 -0
  13. package/assets/bricks/elements/split.php +83 -0
  14. package/assets/bricks/load.php +129 -0
  15. package/assets/css/animation.css +526 -0
  16. package/assets/css/global.css +17 -0
  17. package/assets/css/index.css +58 -0
  18. package/assets/css/layout.css +723 -0
  19. package/assets/css/patterns/anchor-link.css +66 -0
  20. package/assets/css/patterns/banner.css +64 -0
  21. package/assets/css/patterns/carousel.css +269 -0
  22. package/assets/css/patterns/cluster.css +64 -0
  23. package/assets/css/patterns/code.css +17 -0
  24. package/assets/css/patterns/combobox.css +97 -0
  25. package/assets/css/patterns/comment.css +88 -0
  26. package/assets/css/patterns/copy.css +82 -0
  27. package/assets/css/patterns/details.css +87 -0
  28. package/assets/css/patterns/dialog.css +99 -0
  29. package/assets/css/patterns/drawer.css +108 -0
  30. package/assets/css/patterns/dropdown.css +45 -0
  31. package/assets/css/patterns/forms.css +335 -0
  32. package/assets/css/patterns/grouped.css +86 -0
  33. package/assets/css/patterns/horizontal-scroll.css +40 -0
  34. package/assets/css/patterns/icon.css +72 -0
  35. package/assets/css/patterns/lightbox.css +156 -0
  36. package/assets/css/patterns/list.css +272 -0
  37. package/assets/css/patterns/marquee.css +68 -0
  38. package/assets/css/patterns/masonry.css +40 -0
  39. package/assets/css/patterns/media.css +70 -0
  40. package/assets/css/patterns/nav.css +241 -0
  41. package/assets/css/patterns/notification.css +114 -0
  42. package/assets/css/patterns/overlay.css +28 -0
  43. package/assets/css/patterns/popover.css +68 -0
  44. package/assets/css/patterns/pull-quote.css +71 -0
  45. package/assets/css/patterns/scroll-based.css +227 -0
  46. package/assets/css/patterns/scroll-target.css +124 -0
  47. package/assets/css/patterns/separator.css +130 -0
  48. package/assets/css/patterns/sitenav.css +582 -0
  49. package/assets/css/patterns/split-link.css +113 -0
  50. package/assets/css/patterns/splitter.css +212 -0
  51. package/assets/css/patterns/stack.css +67 -0
  52. package/assets/css/patterns/sticky.css +127 -0
  53. package/assets/css/patterns/subgrid.css +178 -0
  54. package/assets/css/patterns/svg.css +166 -0
  55. package/assets/css/patterns/table.css +106 -0
  56. package/assets/css/patterns/tag.css +75 -0
  57. package/assets/css/patterns/text-effects.css +317 -0
  58. package/assets/css/patterns/tooltip.css +68 -0
  59. package/assets/css/patterns/tree.css +126 -0
  60. package/assets/css/utilities.css +351 -0
  61. package/assets/js/deferred.js +1 -0
  62. package/assets/js/elements.js +887 -0
  63. package/assets/js/polyfills/adoptedStyleSheets.js +1 -0
  64. package/assets/js/polyfills/css-anchor-positioning-fn.js +17 -0
  65. package/assets/js/polyfills/global.esm.js +1 -0
  66. package/assets/js/polyfills/popover.js +63 -0
  67. package/assets/js/polyfills/template-shadowroot.js +24 -0
  68. package/assets/js/polyfills/webcomponents-bundle.js +27 -0
  69. package/assets/js/polyfills.js +1 -0
  70. package/dist/index.d.mts +1425 -0
  71. package/dist/index.d.mts.map +1 -0
  72. package/dist/index.mjs +2611 -0
  73. package/dist/index.mjs.map +1 -0
  74. package/package.json +33 -0
  75. package/schema.json +508 -0
@@ -0,0 +1,166 @@
1
+ /**
2
+ * SVG — sizing/styling utilities and decorative helpers migrated from
3
+ * old-css-lib. Pure CSS. The bare-<svg> reset is kept intentionally light
4
+ * (no forced 1em sizing) so it doesn't fight component-owned icon sizing.
5
+ */
6
+
7
+ svg {
8
+ flex-shrink: 0;
9
+ fill: currentColor;
10
+ }
11
+
12
+ .svg-container {
13
+ --_svg-size: var(--svg-size, 1.5rem);
14
+
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ inline-size: var(--_svg-size);
19
+ block-size: var(--_svg-size);
20
+
21
+ > svg {
22
+ inline-size: 100%;
23
+ block-size: 100%;
24
+ }
25
+ }
26
+
27
+ .svg-stroke > svg {
28
+ fill: none;
29
+ stroke: var(--svg-stroke-color, currentColor);
30
+ stroke-width: var(--svg-stroke-width, 2);
31
+ stroke-linecap: var(--svg-stroke-linecap, round);
32
+ stroke-linejoin: var(--svg-stroke-linejoin, round);
33
+ }
34
+
35
+ /* ── Animated SVG ─────────────────────────────────────────────────────────── */
36
+ .svg-animated {
37
+ &.svg-animated--spin > svg {
38
+ animation: svg-spin 1s linear infinite;
39
+ }
40
+ &.svg-animated--pulse > svg {
41
+ animation: svg-pulse 1.5s ease-in-out infinite;
42
+ }
43
+ &.svg-animated--bounce > svg {
44
+ animation: svg-bounce 1s ease infinite;
45
+ }
46
+ &.svg-animated--draw > svg {
47
+ stroke-dasharray: var(--svg-dash-length, 100);
48
+ stroke-dashoffset: var(--svg-dash-length, 100);
49
+ animation: svg-draw 1.5s ease forwards;
50
+
51
+ @media (prefers-reduced-motion: reduce) {
52
+ stroke-dashoffset: 0;
53
+ animation: none;
54
+ }
55
+ }
56
+
57
+ @media (prefers-reduced-motion: reduce) {
58
+ &.svg-animated--spin > svg,
59
+ &.svg-animated--pulse > svg,
60
+ &.svg-animated--bounce > svg {
61
+ animation: none;
62
+ }
63
+ }
64
+ }
65
+
66
+ /* ── Background patterns ──────────────────────────────────────────────────── */
67
+ .svg-pattern {
68
+ --_pattern-size: var(--svg-pattern-size, 20px);
69
+ --_pattern-color: var(--svg-pattern-color, currentColor);
70
+
71
+ background-size: var(--_pattern-size) var(--_pattern-size);
72
+
73
+ &.svg-pattern--dots {
74
+ background-image: radial-gradient(var(--_pattern-color) 1px, transparent 1px);
75
+ }
76
+
77
+ &.svg-pattern--grid {
78
+ background-image:
79
+ linear-gradient(var(--_pattern-color) 1px, transparent 1px),
80
+ linear-gradient(90deg, var(--_pattern-color) 1px, transparent 1px);
81
+ }
82
+
83
+ &.svg-pattern--diagonal {
84
+ background-image: repeating-linear-gradient(
85
+ 45deg,
86
+ var(--_pattern-color),
87
+ var(--_pattern-color) 1px,
88
+ transparent 1px,
89
+ transparent 10px
90
+ );
91
+ }
92
+
93
+ &.svg-pattern--cross {
94
+ background-image:
95
+ linear-gradient(var(--_pattern-color) 1px, transparent 1px),
96
+ linear-gradient(90deg, var(--_pattern-color) 1px, transparent 1px);
97
+ background-position: center center;
98
+ }
99
+ }
100
+
101
+ /* ── Decorative shapes / dividers ─────────────────────────────────────────── */
102
+ .svg-shape {
103
+ display: block;
104
+ inline-size: 100%;
105
+ block-size: auto;
106
+
107
+ &.svg-shape--flip-x {
108
+ transform: scaleX(-1);
109
+ }
110
+ &.svg-shape--flip-y {
111
+ transform: scaleY(-1);
112
+ }
113
+ &.svg-shape--top {
114
+ position: absolute;
115
+ inset-block-start: 0;
116
+ inset-inline: 0;
117
+ }
118
+ &.svg-shape--bottom {
119
+ position: absolute;
120
+ inset-block-end: 0;
121
+ inset-inline: 0;
122
+ }
123
+ }
124
+
125
+ .svg-use {
126
+ display: inline-block;
127
+ vertical-align: middle;
128
+
129
+ > svg {
130
+ display: block;
131
+ inline-size: 100%;
132
+ block-size: 100%;
133
+ }
134
+ }
135
+
136
+ @keyframes svg-spin {
137
+ from {
138
+ transform: rotate(0deg);
139
+ }
140
+ to {
141
+ transform: rotate(360deg);
142
+ }
143
+ }
144
+ @keyframes svg-pulse {
145
+ 0%,
146
+ 100% {
147
+ opacity: 1;
148
+ }
149
+ 50% {
150
+ opacity: 0.5;
151
+ }
152
+ }
153
+ @keyframes svg-bounce {
154
+ 0%,
155
+ 100% {
156
+ transform: translateY(0);
157
+ }
158
+ 50% {
159
+ transform: translateY(-25%);
160
+ }
161
+ }
162
+ @keyframes svg-draw {
163
+ to {
164
+ stroke-dashoffset: 0;
165
+ }
166
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Table — pattern partial migrated from old-css-lib.
3
+ * Consumes the generated token cascade (src/css/generated/tokens.css).
4
+ */
5
+
6
+ /* ── Table — bare <table> or .table, with variants ────────────────────────── */
7
+ table,
8
+ .table {
9
+ --_b: var(--b-table, var(--b-table-group, var(--b-default)));
10
+ --_br: var(--br-table, var(--br-table-group, var(--br-default)));
11
+ --_fs: var(--fs-table, var(--fs-table-group, var(--fs-default)));
12
+ --_cell: var(--table-cell-padding, 0.75em 1em);
13
+
14
+ inline-size: 100%;
15
+ border-collapse: collapse;
16
+ border-spacing: 0;
17
+ font-size: var(--_fs);
18
+ text-align: start;
19
+
20
+ > caption {
21
+ caption-side: bottom;
22
+ padding-block-start: var(--table-caption-gap, 0.75em);
23
+ font-size: var(--table-caption-fs, 0.875em);
24
+ opacity: 0.7;
25
+ text-align: start;
26
+ }
27
+
28
+ > thead {
29
+ text-align: start;
30
+
31
+ > tr > th {
32
+ padding: var(--_cell);
33
+ font-weight: 600;
34
+ text-align: inherit;
35
+ border-block-end: var(--_b);
36
+ }
37
+ }
38
+
39
+ > tbody > tr > td {
40
+ padding: var(--_cell);
41
+ border-block-end: var(--_b);
42
+ vertical-align: baseline;
43
+ }
44
+
45
+ > tbody > tr:last-child > td {
46
+ border-block-end: none;
47
+ }
48
+
49
+ > tfoot > tr > td,
50
+ > tfoot > tr > th {
51
+ padding: var(--_cell);
52
+ font-weight: 600;
53
+ border-block-start: var(--_b);
54
+ }
55
+
56
+ &.table--bordered {
57
+ border: var(--_b);
58
+ border-radius: var(--_br);
59
+ overflow: hidden;
60
+
61
+ > thead > tr > th,
62
+ > tbody > tr > td,
63
+ > tfoot > tr > td,
64
+ > tfoot > tr > th {
65
+ border: var(--_b);
66
+ }
67
+ }
68
+
69
+ &.table--striped > tbody > tr:nth-child(even) {
70
+ background: oklch(0 0 0 / var(--table-stripe-opacity, 0.04));
71
+ }
72
+
73
+ &.table--hover > tbody > tr:hover {
74
+ background: oklch(0 0 0 / var(--table-hover-opacity, 0.08));
75
+ }
76
+
77
+ &.table--compact {
78
+ --_cell: var(--table-compact-padding, 0.375em 0.75em);
79
+ }
80
+
81
+ [data-numeric] {
82
+ text-align: end;
83
+ font-variant-numeric: tabular-nums;
84
+ }
85
+
86
+ &.table--fixed {
87
+ table-layout: fixed;
88
+ }
89
+
90
+ &.table--sticky-header > thead > tr > th {
91
+ position: sticky;
92
+ inset-block-start: 0;
93
+ z-index: var(--z-tier-raised);
94
+ background: inherit;
95
+ }
96
+ }
97
+
98
+ .table-wrapper {
99
+ overflow-x: auto;
100
+ -webkit-overflow-scrolling: touch;
101
+
102
+ > table,
103
+ > .table {
104
+ min-inline-size: var(--table-min-inline-size, 100%);
105
+ }
106
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Tag — pattern partial migrated from old-css-lib.
3
+ * Consumes the generated token cascade (src/css/generated/tokens.css).
4
+ */
5
+
6
+ /* ── Tag sub-parts — pair with generated .tag / .tag-<role> ───────────────── */
7
+ .tag__icon {
8
+ flex-shrink: 0;
9
+ inline-size: 1em;
10
+ block-size: 1em;
11
+ }
12
+
13
+ .tag__remove {
14
+ flex-shrink: 0;
15
+ margin-inline-start: 0.25em;
16
+ padding: 0.125em;
17
+ background: transparent;
18
+ border: none;
19
+ cursor: pointer;
20
+ opacity: 0.6;
21
+ line-height: 1;
22
+ transition: opacity 0.15s ease;
23
+
24
+ &:hover {
25
+ opacity: 1;
26
+ }
27
+ }
28
+
29
+ /* ── Badge indicator — numeric notification bubble (distinct from .badge) ──── */
30
+ .badge-indicator {
31
+ --_size: var(--badge-size, 1.25rem);
32
+ --_br: var(--br-badge, var(--br-badge-group, var(--br-default)));
33
+
34
+ display: inline-flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ min-inline-size: var(--_size);
38
+ block-size: var(--_size);
39
+ padding-inline: 0.25em;
40
+ font-size: var(--fs-badge, var(--fs-badge-group, var(--fs-default)));
41
+ font-weight: 600;
42
+ line-height: 1;
43
+ border-radius: var(--br-badge-indicator, var(--br-pill, 999px));
44
+ background: var(--color-danger-d);
45
+ color: #fff;
46
+
47
+ &.badge-indicator--dot {
48
+ --_size: 0.5rem;
49
+ padding: 0;
50
+ }
51
+
52
+ &.badge-indicator--positioned {
53
+ position: absolute;
54
+ inset-block-start: 0;
55
+ inset-inline-end: 0;
56
+ translate: 50% -50%;
57
+ }
58
+ }
59
+
60
+ /* ── Status dot pulse — modifier + keyframe over the generated .status-dot ─── */
61
+ .status-dot--pulse {
62
+ animation: status-pulse 2s ease-in-out infinite;
63
+ }
64
+
65
+ @keyframes status-pulse {
66
+ 0%,
67
+ 100% {
68
+ box-shadow: 0 0 0 0 currentColor;
69
+ opacity: 1;
70
+ }
71
+ 50% {
72
+ box-shadow: 0 0 0 4px currentColor;
73
+ opacity: 0.5;
74
+ }
75
+ }
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Text effects — typewriter, flip, rotate, gradient, highlight and stagger text
3
+ * animations migrated from old-css-lib. Pure-CSS value + keyframe layers; each
4
+ * degrades under prefers-reduced-motion. `.text-scramble` is a CSS shell — the
5
+ * per-character randomisation arrives with its Lit component.
6
+ */
7
+
8
+ /* ── Typing — typewriter reveal with blinking caret ───────────────────────── */
9
+ .typing {
10
+ --_typing-speed: var(--typing-speed, 3s);
11
+ --_typing-steps: var(--typing-steps, 20);
12
+ --_cursor-color: var(--typing-cursor-color, currentColor);
13
+ --_cursor-width: var(--typing-cursor-width, 2px);
14
+
15
+ display: inline-block;
16
+ overflow: hidden;
17
+ white-space: nowrap;
18
+ border-inline-end: var(--_cursor-width) solid var(--_cursor-color);
19
+ animation:
20
+ typing-text var(--_typing-speed) steps(var(--_typing-steps)) forwards,
21
+ typing-cursor 0.75s step-end infinite;
22
+
23
+ @media (prefers-reduced-motion: reduce) {
24
+ border-inline-end: none;
25
+ animation: none;
26
+ }
27
+
28
+ &.typing--loop {
29
+ animation:
30
+ typing-text var(--_typing-speed) steps(var(--_typing-steps)) infinite alternate,
31
+ typing-cursor 0.75s step-end infinite;
32
+ }
33
+
34
+ &.typing--no-cursor {
35
+ animation: typing-text var(--_typing-speed) steps(var(--_typing-steps)) forwards;
36
+ border-inline-end: none;
37
+ }
38
+ }
39
+
40
+ @keyframes typing-text {
41
+ from {
42
+ inline-size: 0;
43
+ }
44
+ to {
45
+ inline-size: 100%;
46
+ }
47
+ }
48
+ @keyframes typing-cursor {
49
+ 50% {
50
+ border-color: transparent;
51
+ }
52
+ }
53
+
54
+ /* ── Text flip — 3D rotating word list ────────────────────────────────────── */
55
+ .text-flip {
56
+ --_flip-duration: var(--text-flip-duration, 3s);
57
+ --_flip-items: var(--text-flip-items, 3);
58
+
59
+ display: inline-block;
60
+ position: relative;
61
+ perspective: 1000px;
62
+ overflow: hidden;
63
+ vertical-align: bottom;
64
+
65
+ .text-flip__item {
66
+ display: block;
67
+ animation: text-flip-rotate calc(var(--_flip-duration) * var(--_flip-items)) infinite;
68
+ backface-visibility: hidden;
69
+
70
+ @media (prefers-reduced-motion: reduce) {
71
+ animation: none;
72
+
73
+ &:not(:first-child) {
74
+ display: none;
75
+ }
76
+ }
77
+ }
78
+
79
+ .text-flip__item:nth-child(1) {
80
+ animation-delay: 0s;
81
+ }
82
+ .text-flip__item:nth-child(2) {
83
+ animation-delay: var(--_flip-duration);
84
+ }
85
+ .text-flip__item:nth-child(3) {
86
+ animation-delay: calc(var(--_flip-duration) * 2);
87
+ }
88
+ .text-flip__item:nth-child(4) {
89
+ animation-delay: calc(var(--_flip-duration) * 3);
90
+ }
91
+ .text-flip__item:nth-child(5) {
92
+ animation-delay: calc(var(--_flip-duration) * 4);
93
+ }
94
+
95
+ .text-flip__item:not(:first-child) {
96
+ position: absolute;
97
+ inset: 0;
98
+ }
99
+ }
100
+
101
+ @keyframes text-flip-rotate {
102
+ 0%,
103
+ 20% {
104
+ opacity: 1;
105
+ transform: rotateX(0);
106
+ }
107
+ 25%,
108
+ 100% {
109
+ opacity: 0;
110
+ transform: rotateX(-90deg);
111
+ }
112
+ }
113
+
114
+ /* ── Text rotate — fade/slide word list ───────────────────────────────────── */
115
+ .text-rotate {
116
+ --_rotate-duration: var(--text-rotate-duration, 2s);
117
+ --_rotate-items: var(--text-rotate-items, 3);
118
+
119
+ display: inline-block;
120
+ position: relative;
121
+ overflow: hidden;
122
+ vertical-align: bottom;
123
+
124
+ .text-rotate__item {
125
+ display: block;
126
+ opacity: 0;
127
+ animation: text-rotate-fade calc(var(--_rotate-duration) * var(--_rotate-items)) infinite;
128
+
129
+ @media (prefers-reduced-motion: reduce) {
130
+ opacity: 1;
131
+ animation: none;
132
+
133
+ &:not(:first-child) {
134
+ display: none;
135
+ }
136
+ }
137
+ }
138
+
139
+ .text-rotate__item:nth-child(1) {
140
+ animation-delay: 0s;
141
+ }
142
+ .text-rotate__item:nth-child(2) {
143
+ animation-delay: var(--_rotate-duration);
144
+ }
145
+ .text-rotate__item:nth-child(3) {
146
+ animation-delay: calc(var(--_rotate-duration) * 2);
147
+ }
148
+ .text-rotate__item:nth-child(4) {
149
+ animation-delay: calc(var(--_rotate-duration) * 3);
150
+ }
151
+ .text-rotate__item:nth-child(5) {
152
+ animation-delay: calc(var(--_rotate-duration) * 4);
153
+ }
154
+
155
+ .text-rotate__item:not(:first-child) {
156
+ position: absolute;
157
+ inset: 0;
158
+ }
159
+ }
160
+
161
+ @keyframes text-rotate-fade {
162
+ 0%,
163
+ 5% {
164
+ opacity: 0;
165
+ transform: translateY(100%);
166
+ }
167
+ 10%,
168
+ 30% {
169
+ opacity: 1;
170
+ transform: translateY(0);
171
+ }
172
+ 35%,
173
+ 100% {
174
+ opacity: 0;
175
+ transform: translateY(-100%);
176
+ }
177
+ }
178
+
179
+ /* ── Text scramble — CSS shell; randomisation lands via Lit ───────────────── */
180
+ .text-scramble {
181
+ display: inline-block;
182
+ font-family: var(--font-mono, monospace);
183
+
184
+ .text-scramble__char {
185
+ display: inline-block;
186
+ transition: opacity 0.1s ease;
187
+ }
188
+
189
+ .text-scramble__char--scrambled {
190
+ opacity: 0.3;
191
+ }
192
+ }
193
+
194
+ /* ── Animated gradient text ───────────────────────────────────────────────── */
195
+ .text-gradient-animate {
196
+ --_gradient-speed: var(--text-gradient-speed, 3s);
197
+ --_gradient-colors: var(
198
+ --text-gradient-colors,
199
+ oklch(0.7 0.25 0),
200
+ oklch(0.7 0.25 60),
201
+ oklch(0.7 0.25 120),
202
+ oklch(0.7 0.25 180),
203
+ oklch(0.7 0.25 240),
204
+ oklch(0.7 0.25 300),
205
+ oklch(0.7 0.25 360)
206
+ );
207
+
208
+ background: linear-gradient(90deg, var(--_gradient-colors));
209
+ background-size: 200% auto;
210
+ background-clip: text;
211
+ -webkit-background-clip: text;
212
+ -webkit-text-fill-color: transparent;
213
+ animation: text-gradient-shift var(--_gradient-speed) linear infinite;
214
+
215
+ @media (prefers-reduced-motion: reduce) {
216
+ animation: none;
217
+ }
218
+ }
219
+
220
+ @keyframes text-gradient-shift {
221
+ to {
222
+ background-position: 200% center;
223
+ }
224
+ }
225
+
226
+ /* ── Highlight sweep ──────────────────────────────────────────────────────── */
227
+ .text-highlight {
228
+ --_highlight-color: var(--text-highlight-color, var(--color-warning-l));
229
+ --_highlight-duration: var(--text-highlight-duration, 0.5s);
230
+ --_highlight-pad-block: var(--text-highlight-pad-block, 0.1em);
231
+ --_highlight-pad-inline: var(--text-highlight-pad-inline, 0);
232
+ --_highlight-radius: var(--text-highlight-radius, 0);
233
+ --_highlight-skew: var(--text-highlight-skew, 0deg);
234
+
235
+ background: linear-gradient(to right, var(--_highlight-color) 50%, transparent 50%);
236
+ background-size: 200% 100%;
237
+ background-position: 100% 0;
238
+ border-radius: var(--_highlight-radius);
239
+ /* Extend the sweep slightly past the glyphs so the band doesn't sit flush to
240
+ the characters; keep line layout intact by clawing the padding back. */
241
+ padding-block: var(--_highlight-pad-block);
242
+ padding-inline: var(--_highlight-pad-inline);
243
+ margin-block: calc(-1 * var(--_highlight-pad-block));
244
+ margin-inline: calc(-1 * var(--_highlight-pad-inline));
245
+ box-decoration-break: clone;
246
+ /* skew is a no-op on pure inline boxes; opt in with inline-block when the
247
+ phrase stays on one line and a slanted marker look is wanted. */
248
+ transform: skewX(var(--_highlight-skew));
249
+ transition: background-position var(--_highlight-duration) ease;
250
+
251
+ @media (prefers-reduced-motion: reduce) {
252
+ background-position: 0 0;
253
+ }
254
+
255
+ &.text-highlight--active,
256
+ &:hover {
257
+ background-position: 0 0;
258
+ }
259
+ }
260
+
261
+ /* ── Character stagger pop-in ─────────────────────────────────────────────── */
262
+ .text-stagger {
263
+ display: inline-flex;
264
+
265
+ .text-stagger__char {
266
+ display: inline-block;
267
+ animation: text-stagger-pop 0.5s ease backwards;
268
+ }
269
+
270
+ .text-stagger__char:nth-child(1) {
271
+ animation-delay: 0s;
272
+ }
273
+ .text-stagger__char:nth-child(2) {
274
+ animation-delay: 0.05s;
275
+ }
276
+ .text-stagger__char:nth-child(3) {
277
+ animation-delay: 0.1s;
278
+ }
279
+ .text-stagger__char:nth-child(4) {
280
+ animation-delay: 0.15s;
281
+ }
282
+ .text-stagger__char:nth-child(5) {
283
+ animation-delay: 0.2s;
284
+ }
285
+ .text-stagger__char:nth-child(6) {
286
+ animation-delay: 0.25s;
287
+ }
288
+ .text-stagger__char:nth-child(7) {
289
+ animation-delay: 0.3s;
290
+ }
291
+ .text-stagger__char:nth-child(8) {
292
+ animation-delay: 0.35s;
293
+ }
294
+ .text-stagger__char:nth-child(9) {
295
+ animation-delay: 0.4s;
296
+ }
297
+ .text-stagger__char:nth-child(10) {
298
+ animation-delay: 0.45s;
299
+ }
300
+
301
+ @media (prefers-reduced-motion: reduce) {
302
+ .text-stagger__char {
303
+ animation: none;
304
+ }
305
+ }
306
+ }
307
+
308
+ @keyframes text-stagger-pop {
309
+ from {
310
+ opacity: 0;
311
+ transform: translateY(20px) scale(0.8);
312
+ }
313
+ to {
314
+ opacity: 1;
315
+ transform: translateY(0) scale(1);
316
+ }
317
+ }