qss 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.
@@ -0,0 +1,614 @@
1
+ /*
2
+ * QSS Core — Quantized Spatial Styling DNA
3
+ * Driven by config/grammar.yml (via exe/qss-sync -> _qss_defaults.scss; a consumer overrides it)
4
+ */
5
+
6
+ @use "sass:math";
7
+ /* Core's own defaults (every setting !default). A consumer sets its values BEFORE importing this file. */
8
+ @import "qss/qss_defaults";
9
+
10
+ /* The QSS unit (qnt): one thousandth of the canvas width, computed by CSS alone. The canvas is a size container
11
+ and each of its children declares --qnt as 0.1cqw; registered as a <length>, it resolves there once and
12
+ inherits unchanged, so every descendant measures against its canvas, never a nearer container. Outside a
13
+ canvas (e.g. an overlay portal at the document root) the unit approximates from the viewport width. */
14
+ @property --qnt { syntax: "<length>"; inherits: true; initial-value: 1px; }
15
+
16
+ :root {
17
+ --qnt: 0.1vw;
18
+ /* Item 3: pure-CSS linear content unit, no JS, no clamp. Only icon-size[N] uses
19
+ this today -- see the content_scale note in _qss_variables.scss. */
20
+ --u: calc(100vw / #{map-get($qss-content-scale, "calibration-width")});
21
+ }
22
+
23
+ /* Item 1 (colors, SETTLED 2026-09-21): per-property alpha registered as typed custom
24
+ properties so alpha never leaks to descendants (inherits: false), each defaulting
25
+ to fully opaque (100) when no *-alpha[N] class is present. */
26
+ @property --bg-a { syntax: "<number>"; inherits: false; initial-value: 100; }
27
+ @property --border-a { syntax: "<number>"; inherits: false; initial-value: 100; }
28
+ @property --text-a { syntax: "<number>"; inherits: false; initial-value: 100; }
29
+
30
+ /* Item A (2026-09-23): accent color -- WHICH color a state-driven property takes,
31
+ an axis independent of the alpha properties above (HOW opaque). Set by the
32
+ accidental .accent-{bg,text,border}-{name} classes; read by the essential
33
+ state/group rules. inherits: false so a parent's accent never leaks into a child.
34
+ Unset fallback: transparent for bg/border; currentcolor for text, so a missing
35
+ accent class leaves text readable rather than invisible. Note an essential rule
36
+ with no accent class still claims the property (author origin beats UA styles). */
37
+ @property --accent-bg { syntax: "<color>"; inherits: false; initial-value: transparent; }
38
+ @property --accent-border { syntax: "<color>"; inherits: false; initial-value: transparent; }
39
+ @property --accent-text { syntax: "<color>"; inherits: false; initial-value: currentcolor; }
40
+
41
+ /* The QSS Stage (Ground Level) */
42
+ html, body {
43
+ margin: 0;
44
+ padding: 0;
45
+ width: 100%;
46
+ height: 100%;
47
+ overflow: hidden;
48
+ font-family: map-get($qss-fonts, "sans");
49
+ -webkit-font-smoothing: antialiased;
50
+ -moz-osx-font-smoothing: grayscale;
51
+ }
52
+
53
+ /*
54
+ * The Root Anchor
55
+ * Using ID specificity to ensure QSS adjectives win without !important
56
+ */
57
+ #{$qss-anchor} {
58
+ container-type: inline-size;
59
+ position: relative;
60
+ width: 100%;
61
+ height: 100%;
62
+ overflow: hidden;
63
+ background-color: transparent;
64
+ box-sizing: border-box;
65
+
66
+ > * { --qnt: 0.1cqw; }
67
+
68
+ /* The Base Nature of a Spatial Actor — ONLY inside the stage.
69
+ :where() keeps this reset at the anchor's weight alone, (1,0,0): below every core utility, which is
70
+ (1,1,0), so the compiled utilities work with no JS engine; still above a host app's plain classes. */
71
+ :where(.qss:not(.foreign *)) {
72
+ &, &::before, &::after {
73
+ position: absolute;
74
+ box-sizing: border-box;
75
+ margin: 0;
76
+ padding: 0;
77
+ border: 0;
78
+ display: block;
79
+ flex-shrink: 0;
80
+ font-family: map-get($qss-fonts, "sans");
81
+ font-size: inherit;
82
+ vertical-align: baseline;
83
+ text-decoration: none;
84
+ pointer-events: auto;
85
+ user-select: none;
86
+ min-width: calc(1 * var(--qnt));
87
+ min-height: calc(1 * var(--qnt));
88
+ width: auto;
89
+ height: auto;
90
+ }
91
+ }
92
+ }
93
+
94
+ /* Global Semantic Spatial DSL — Available everywhere (Hybrid Identity) */
95
+
96
+ /* Selector scope for every generated rule: the anchor, plus the consumer's overlay portal
97
+ root when one is configured ($qss-portal-root, grammar config.portal_root). */
98
+ $qss-scope: if($qss-portal-root == "", $qss-anchor, "#{$qss-anchor}, #{$qss-portal-root}");
99
+
100
+ @mixin qss-dsl-boost($selector) {
101
+ :is(#{$qss-scope}) #{$selector} {
102
+ @content;
103
+ }
104
+ }
105
+
106
+ /* Typography Adjectives */
107
+ @each $name, $stack in $qss-fonts {
108
+ @include qss-dsl-boost(".font-#{$name}") { font-family: #{$stack}; }
109
+ @include qss-dsl-boost(".font\\[#{$name}\\]") { font-family: #{$stack}; }
110
+ }
111
+ @include qss-dsl-boost(".font-black") { font-weight: 900; }
112
+ @include qss-dsl-boost(".font-bold") { font-weight: 700; }
113
+ @include qss-dsl-boost(".font-semibold") { font-weight: 600; }
114
+ @include qss-dsl-boost(".font-medium") { font-weight: 500; }
115
+ @include qss-dsl-boost(".font-normal") { font-weight: 400; }
116
+ @include qss-dsl-boost(".italic") { font-style: italic; }
117
+ @include qss-dsl-boost(".uppercase") { text-transform: uppercase; }
118
+ @include qss-dsl-boost(".lowercase") { text-transform: lowercase; }
119
+ @include qss-dsl-boost(".tracking-tighter") { letter-spacing: -0.05em; }
120
+ @include qss-dsl-boost(".tracking-tight") { letter-spacing: -0.025em; }
121
+ @include qss-dsl-boost(".tracking-wide") { letter-spacing: 0.025em; }
122
+ @include qss-dsl-boost(".tracking-widest") { letter-spacing: 0.1em; }
123
+ @include qss-dsl-boost(".leading-none") { line-height: 1; }
124
+ @include qss-dsl-boost(".tight") { line-height: 1; }
125
+ @include qss-dsl-boost(".leading-tight") { line-height: 1.25; }
126
+ @include qss-dsl-boost(".leading-normal") { line-height: 1.5; }
127
+
128
+ /* Spatial Coordinates & Dimensions */
129
+ @for $i from 0 through map-get($qss-quantization, "units") {
130
+ @include qss-dsl-boost(".pos-x\\[#{$i}\\]") { left: calc(#{$i} * var(--qnt)); }
131
+ @include qss-dsl-boost(".pos-y\\[#{$i}\\]") { top: calc(#{$i} * var(--qnt)); }
132
+ @include qss-dsl-boost(".w\\[#{$i}\\]") { width: calc(#{$i} * var(--qnt)); }
133
+ @include qss-dsl-boost(".h\\[#{$i}\\]") { height: calc(#{$i} * var(--qnt)); }
134
+ @include qss-dsl-boost(".pos-r\\[#{$i}\\]") { right: calc(#{$i} * var(--qnt)); }
135
+ @include qss-dsl-boost(".pos-b\\[#{$i}\\]") { bottom: calc(#{$i} * var(--qnt)); }
136
+ @include qss-dsl-boost(".min-w\\[#{$i}\\]") { min-width: calc(#{$i} * var(--qnt)); }
137
+ @include qss-dsl-boost(".min-h\\[#{$i}\\]") { min-height: calc(#{$i} * var(--qnt)); }
138
+ @include qss-dsl-boost(".px\\[#{$i}\\]") { padding-left: calc(#{$i} * var(--qnt)); padding-right: calc(#{$i} * var(--qnt)); }
139
+ @include qss-dsl-boost(".py\\[#{$i}\\]") { padding-top: calc(#{$i} * var(--qnt)); padding-bottom: calc(#{$i} * var(--qnt)); }
140
+ @include qss-dsl-boost(".p\\[#{$i}\\]") { padding: calc(#{$i} * var(--qnt)); }
141
+ @include qss-dsl-boost(".gap\\[#{$i}\\]") { gap: calc(#{$i} * var(--qnt)); }
142
+
143
+ /* Percentage-based scaling (0.1% increments) */
144
+ @include qss-dsl-boost(".w-pct\\[#{$i}\\]") { width: percentage($i * 0.001); }
145
+ @include qss-dsl-boost(".h-pct\\[#{$i}\\]") { height: percentage($i * 0.001); }
146
+ @include qss-dsl-boost(".pos-x-pct\\[#{$i}\\]") { left: percentage($i * 0.001); }
147
+ @include qss-dsl-boost(".pos-y-pct\\[#{$i}\\]") { top: percentage($i * 0.001); }
148
+
149
+ @if $i <= map-get($qss-quantization, "borders") {
150
+ @include qss-dsl-boost(".border\\[#{$i}\\]") { border-width: calc(#{$i} * var(--qnt)); border-style: solid; border-color: map-get($qss-palette, "slate-800"); }
151
+ @include qss-dsl-boost(".border-t\\[#{$i}\\]") { border-top-width: calc(#{$i} * var(--qnt)); border-top-style: solid; border-top-color: map-get($qss-palette, "slate-800"); }
152
+ @include qss-dsl-boost(".border-b\\[#{$i}\\]") { border-bottom-width: calc(#{$i} * var(--qnt)); border-bottom-style: solid; border-bottom-color: map-get($qss-palette, "slate-800"); }
153
+ @include qss-dsl-boost(".border-l\\[#{$i}\\]") { border-left-width: calc(#{$i} * var(--qnt)); border-left-style: solid; border-left-color: map-get($qss-palette, "slate-800"); }
154
+ @include qss-dsl-boost(".border-r\\[#{$i}\\]") { border-right-width: calc(#{$i} * var(--qnt)); border-right-style: solid; border-right-color: map-get($qss-palette, "slate-800"); }
155
+ @include qss-dsl-boost(".rounded\\[#{$i}\\]") { border-radius: calc(#{$i} * var(--qnt)); }
156
+ }
157
+ }
158
+
159
+ @include qss-dsl-boost(".rounded\\[full\\]") { border-radius: 9999px; }
160
+ @include qss-dsl-boost(".rounded-full") { border-radius: 9999px; }
161
+
162
+ /* Palette Generation -- each color is also a real custom property (--c-{name}),
163
+ not just a Sass compile-time value, so color-mix() can read it at the point of use. */
164
+ :root {
165
+ @each $name, $hex in $qss-palette {
166
+ --c-#{$name}: #{$hex};
167
+ }
168
+ }
169
+ @each $name, $hex in $qss-palette {
170
+ @include qss-dsl-boost(".qss-bg-#{$name}") { background-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--bg-a, 100) * 1%), transparent); }
171
+ @include qss-dsl-boost(".bg-#{$name}") { background-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--bg-a, 100) * 1%), transparent); }
172
+ @include qss-dsl-boost(".qss-text-#{$name}") { color: color-mix(in srgb, var(--c-#{$name}) calc(var(--text-a, 100) * 1%), transparent); }
173
+ @include qss-dsl-boost(".text-#{$name}") { color: color-mix(in srgb, var(--c-#{$name}) calc(var(--text-a, 100) * 1%), transparent); }
174
+ @include qss-dsl-boost(".qss-border-#{$name}") { border-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--border-a, 100) * 1%), transparent); }
175
+ @include qss-dsl-boost(".border-#{$name}") { border-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--border-a, 100) * 1%), transparent); }
176
+ }
177
+
178
+ @for $a from 0 through 100 {
179
+ @include qss-dsl-boost(".bg-alpha\\[#{$a}\\]") { --bg-a: #{$a}; }
180
+ @include qss-dsl-boost(".border-alpha\\[#{$a}\\]") { --border-a: #{$a}; }
181
+ @include qss-dsl-boost(".text-alpha\\[#{$a}\\]") { --text-a: #{$a}; }
182
+ }
183
+
184
+ /* Item A step 2 (2026-09-23): accidental accent-color classes -- one rule per palette
185
+ color per property, no state involved. They only SET --accent-*; the essential
186
+ {state}:bg-accent (etc.) rules below decide whether/when it is applied. Both qss- and
187
+ bare forms, matching the palette rules above (prefix decision still open). */
188
+ @each $name, $hex in $qss-palette {
189
+ @include qss-dsl-boost(".qss-accent-bg-#{$name}") { --accent-bg: var(--c-#{$name}); }
190
+ @include qss-dsl-boost(".accent-bg-#{$name}") { --accent-bg: var(--c-#{$name}); }
191
+ @include qss-dsl-boost(".qss-accent-text-#{$name}") { --accent-text: var(--c-#{$name}); }
192
+ @include qss-dsl-boost(".accent-text-#{$name}") { --accent-text: var(--c-#{$name}); }
193
+ @include qss-dsl-boost(".qss-accent-border-#{$name}") { --accent-border: var(--c-#{$name}); }
194
+ @include qss-dsl-boost(".accent-border-#{$name}") { --accent-border: var(--c-#{$name}); }
195
+ }
196
+
197
+ /* Logical Centering */
198
+ @include qss-dsl-boost(".qss-pos-x\\[center\\]") { left: 50%; transform: translateX(-50%); }
199
+ @include qss-dsl-boost(".pos-x\\[center\\]") { left: 50%; transform: translateX(-50%); }
200
+ @include qss-dsl-boost(".qss-pos-y\\[center\\]") { top: 50%; transform: translateY(-50%); }
201
+ @include qss-dsl-boost(".pos-y\\[center\\]") { top: 50%; transform: translateY(-50%); }
202
+ @include qss-dsl-boost(".qss-pos\\[center\\]") { left: 50%; top: 50%; transform: translate(-50%, -50%); }
203
+ @include qss-dsl-boost(".pos\\[center\\]") { left: 50%; top: 50%; transform: translate(-50%, -50%); }
204
+
205
+ /* Z-Group Priority */
206
+ @for $g from 0 through 10 {
207
+ @include qss-dsl-boost(".qss-z-group\\[#{$g}\\]") { z-index: #{$g}; }
208
+ @include qss-dsl-boost(".z-group\\[#{$g}\\]") { z-index: #{$g}; }
209
+ }
210
+
211
+ /* Dev Utilities */
212
+ @include qss-dsl-boost(".qss-dev-border") {
213
+ border: 1px solid map-get($qss-palette, "rose-500");
214
+ }
215
+ @include qss-dsl-boost(".dev-border") {
216
+ border: 1px solid map-get($qss-palette, "rose-500");
217
+ }
218
+
219
+ @include qss-dsl-boost(".qss-safety-gutter") {
220
+ padding: 2px;
221
+ background-color: map-get($qss-palette, "slate-900");
222
+ }
223
+
224
+ /* Layout Utilities — Semantic Spatial DSL */
225
+ @include qss-dsl-boost(".detached") { position: absolute; }
226
+ @include qss-dsl-boost(".qss-absolute") { position: absolute; }
227
+ @include qss-dsl-boost(".anchored") { position: relative; }
228
+ @include qss-dsl-boost(".qss-relative") { position: relative; }
229
+ @include qss-dsl-boost(".floating") { position: fixed; }
230
+ @include qss-dsl-boost(".qss-fixed") { position: fixed; }
231
+ @include qss-dsl-boost(".stuck") { position: sticky; }
232
+ @include qss-dsl-boost(".qss-sticky") { position: sticky; }
233
+
234
+ @include qss-dsl-boost(".horizontal") { display: flex; flex-direction: row; }
235
+ @include qss-dsl-boost(".qss-flex-row") { display: flex; flex-direction: row; }
236
+ @include qss-dsl-boost(".vertical") { display: flex; flex-direction: column; }
237
+ @include qss-dsl-boost(".qss-flex-col") { display: flex; flex-direction: column; }
238
+ @include qss-dsl-boost(".centered") { display: flex; align-items: center; justify-content: center; }
239
+ @include qss-dsl-boost(".qss-centered") { display: flex; align-items: center; justify-content: center; }
240
+ @include qss-dsl-boost(".v-start") { align-items: flex-start; }
241
+ @include qss-dsl-boost(".v-mid") { align-items: center; }
242
+ @include qss-dsl-boost(".qss-items-center") { align-items: center; }
243
+ @include qss-dsl-boost(".v-end") { align-items: flex-end; }
244
+ @include qss-dsl-boost(".h-start") { justify-content: flex-start; }
245
+ @include qss-dsl-boost(".h-mid") { justify-content: center; }
246
+ @include qss-dsl-boost(".qss-justify-center") { justify-content: center; }
247
+ @include qss-dsl-boost(".h-end") { justify-content: flex-end; }
248
+ @include qss-dsl-boost(".spaced") { justify-content: space-between; }
249
+ @include qss-dsl-boost(".qss-justify-between") { justify-content: space-between; }
250
+ @include qss-dsl-boost(".around") { justify-content: space-around; }
251
+ @include qss-dsl-boost(".evenly") { justify-content: space-evenly; }
252
+ @include qss-dsl-boost(".flex-wrap") { flex-wrap: wrap; }
253
+ @include qss-dsl-boost(".flex-nowrap") { flex-wrap: nowrap; }
254
+ @include qss-dsl-boost(".flex-1") { flex: 1 1 0%; }
255
+ @include qss-dsl-boost(".flex-auto") { flex: 1 1 auto; }
256
+ @include qss-dsl-boost(".flex-none") { flex: none; }
257
+ @include qss-dsl-boost(".flex") { display: flex; }
258
+ @include qss-dsl-boost(".qss-flex") { display: flex; }
259
+ @include qss-dsl-boost(".flex-shrink") { flex-shrink: 1; }
260
+ @include qss-dsl-boost(".qss-flex-shrink") { flex-shrink: 1; }
261
+ @include qss-dsl-boost(".flex-shrink-0") { flex-shrink: 0; }
262
+ @include qss-dsl-boost(".qss-flex-shrink-0") { flex-shrink: 0; }
263
+ @include qss-dsl-boost(".divide-x") { > * + * { border-left-width: 1px; border-left-style: solid; } }
264
+ @include qss-dsl-boost(".qss-divide-x") { > * + * { border-left-width: 1px; border-left-style: solid; } }
265
+ @include qss-dsl-boost(".divide-y") { > * + * { border-top-width: 1px; border-top-style: solid; } }
266
+ @include qss-dsl-boost(".qss-divide-y") { > * + * { border-top-width: 1px; border-top-style: solid; } }
267
+ @include qss-dsl-boost(".grid-cols-1") { grid-template-columns: repeat(1, minmax(0, 1fr)); }
268
+ @include qss-dsl-boost(".qss-grid-cols-1") { grid-template-columns: repeat(1, minmax(0, 1fr)); }
269
+ @include qss-dsl-boost(".grid-cols-2") { grid-template-columns: repeat(2, minmax(0, 1fr)); }
270
+ @include qss-dsl-boost(".qss-grid-cols-2") { grid-template-columns: repeat(2, minmax(0, 1fr)); }
271
+ @include qss-dsl-boost(".w-f") { width: 100%; }
272
+ @include qss-dsl-boost(".qss-w-f") { width: 100%; }
273
+ @include qss-dsl-boost(".h-f") { height: 100%; }
274
+ @include qss-dsl-boost(".qss-h-f") { height: 100%; }
275
+ @include qss-dsl-boost(".block") { display: block; }
276
+ @include qss-dsl-boost(".qss-block") { display: block; }
277
+ @include qss-dsl-boost(".inline") { display: inline; }
278
+ @include qss-dsl-boost(".qss-inline") { display: inline; }
279
+ @include qss-dsl-boost(".inline-block") { display: inline-block; }
280
+ @include qss-dsl-boost(".qss-inline-block") { display: inline-block; }
281
+ @include qss-dsl-boost(".table") { display: table; }
282
+ @include qss-dsl-boost(".qss-table") { display: table; }
283
+ @include qss-dsl-boost(".contents") { display: contents; }
284
+ @include qss-dsl-boost(".qss-contents") { display: contents; }
285
+ @include qss-dsl-boost(".list-item") { display: list-item; }
286
+ @include qss-dsl-boost(".qss-list-item") { display: list-item; }
287
+ @include qss-dsl-boost(".overflow-auto") { overflow: auto; }
288
+ @include qss-dsl-boost(".qss-overflow-auto") { overflow: auto; }
289
+ @include qss-dsl-boost(".overflow-x-auto") { overflow-x: auto; }
290
+ @include qss-dsl-boost(".qss-overflow-x-auto") { overflow-x: auto; }
291
+ @include qss-dsl-boost(".inset-0") { top: 0; right: 0; bottom: 0; left: 0; }
292
+ @include qss-dsl-boost(".qss-inset-0") { top: 0; right: 0; bottom: 0; left: 0; }
293
+ @include qss-dsl-boost(".truncate") { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
294
+ @include qss-dsl-boost(".qss-truncate") { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
295
+ @include qss-dsl-boost(".text-xs") { font-size: 0.75rem; }
296
+ @include qss-dsl-boost(".qss-text-xs") { font-size: 0.75rem; }
297
+ @include qss-dsl-boost(".text-sm") { font-size: 0.875rem; }
298
+ @include qss-dsl-boost(".qss-text-sm") { font-size: 0.875rem; }
299
+ @include qss-dsl-boost(".text-md") { font-size: 1rem; }
300
+ @include qss-dsl-boost(".qss-text-md") { font-size: 1rem; }
301
+ @include qss-dsl-boost(".text-base") { font-size: 1rem; }
302
+ @include qss-dsl-boost(".qss-text-base") { font-size: 1rem; }
303
+ @include qss-dsl-boost(".text-lg") { font-size: 1.125rem; }
304
+ @include qss-dsl-boost(".qss-text-lg") { font-size: 1.125rem; }
305
+ @include qss-dsl-boost(".text-xl") { font-size: 1.25rem; }
306
+ @include qss-dsl-boost(".qss-text-xl") { font-size: 1.25rem; }
307
+ @include qss-dsl-boost(".text-2xl") { font-size: 1.5rem; }
308
+ @include qss-dsl-boost(".qss-text-2xl") { font-size: 1.5rem; }
309
+ @include qss-dsl-boost(".text-left") { text-align: left; }
310
+ @include qss-dsl-boost(".qss-text-left") { text-align: left; }
311
+ @include qss-dsl-boost(".text-right") { text-align: right; }
312
+ @include qss-dsl-boost(".qss-text-right") { text-align: right; }
313
+ @include qss-dsl-boost(".text-center") { text-align: center; }
314
+ @include qss-dsl-boost(".qss-text-center") { text-align: center; }
315
+ @include qss-dsl-boost(".text-justify") { text-align: justify; }
316
+ @include qss-dsl-boost(".qss-text-justify") { text-align: justify; }
317
+ @include qss-dsl-boost(".leading") { line-height: normal; }
318
+ @include qss-dsl-boost(".qss-leading") { line-height: normal; }
319
+ @include qss-dsl-boost(".tracking") { letter-spacing: normal; }
320
+ @include qss-dsl-boost(".qss-tracking") { letter-spacing: normal; }
321
+ @include qss-dsl-boost(".tracking-wider") { letter-spacing: 0.05em; }
322
+ @include qss-dsl-boost(".qss-tracking-wider") { letter-spacing: 0.05em; }
323
+ @include qss-dsl-boost(".whitespace-nowrap") { white-space: nowrap; }
324
+ @include qss-dsl-boost(".qss-whitespace-nowrap") { white-space: nowrap; }
325
+ @include qss-dsl-boost(".border") { border-width: 1px; border-style: solid; }
326
+ @include qss-dsl-boost(".qss-border") { border-width: 1px; border-style: solid; }
327
+ @include qss-dsl-boost(".border-t") { border-top-width: 1px; border-top-style: solid; }
328
+ @include qss-dsl-boost(".qss-border-t") { border-top-width: 1px; border-top-style: solid; }
329
+ @include qss-dsl-boost(".border-b") { border-bottom-width: 1px; border-bottom-style: solid; }
330
+ @include qss-dsl-boost(".qss-border-b") { border-bottom-width: 1px; border-bottom-style: solid; }
331
+ @include qss-dsl-boost(".border-l") { border-left-width: 1px; border-left-style: solid; }
332
+ @include qss-dsl-boost(".qss-border-l") { border-left-width: 1px; border-left-style: solid; }
333
+ @include qss-dsl-boost(".border-r") { border-right-width: 1px; border-right-style: solid; }
334
+ @include qss-dsl-boost(".qss-border-r") { border-right-width: 1px; border-right-style: solid; }
335
+ @include qss-dsl-boost(".rounded") { border-radius: 0.25rem; }
336
+ @include qss-dsl-boost(".qss-rounded") { border-radius: 0.25rem; }
337
+ @include qss-dsl-boost(".shadow") { box-shadow: 0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1); }
338
+ @include qss-dsl-boost(".qss-shadow") { box-shadow: 0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1); }
339
+ @include qss-dsl-boost(".opacity") { opacity: 1; }
340
+ @include qss-dsl-boost(".qss-opacity") { opacity: 1; }
341
+ @include qss-dsl-boost(".blur") { filter: blur(8px); }
342
+ @include qss-dsl-boost(".qss-blur") { filter: blur(8px); }
343
+ @include qss-dsl-boost(".bright") { filter: brightness(1.1); }
344
+ @include qss-dsl-boost(".qss-bright") { filter: brightness(1.1); }
345
+ @include qss-dsl-boost(".contrast") { filter: contrast(1.1); }
346
+ @include qss-dsl-boost(".qss-contrast") { filter: contrast(1.1); }
347
+ @include qss-dsl-boost(".grayscale") { filter: grayscale(100%); }
348
+ @include qss-dsl-boost(".qss-grayscale") { filter: grayscale(100%); }
349
+ @include qss-dsl-boost(".hue") { filter: hue-rotate(90deg); }
350
+ @include qss-dsl-boost(".qss-hue") { filter: hue-rotate(90deg); }
351
+ @include qss-dsl-boost(".invert") { filter: invert(100%); }
352
+ @include qss-dsl-boost(".qss-invert") { filter: invert(100%); }
353
+ @include qss-dsl-boost(".saturate") { filter: saturate(1.5); }
354
+ @include qss-dsl-boost(".qss-saturate") { filter: saturate(1.5); }
355
+ @include qss-dsl-boost(".sepia") { filter: sepia(100%); }
356
+ @include qss-dsl-boost(".qss-sepia") { filter: sepia(100%); }
357
+ @include qss-dsl-boost(".blend") { mix-blend-mode: multiply; }
358
+ @include qss-dsl-boost(".qss-blend") { mix-blend-mode: multiply; }
359
+ @include qss-dsl-boost(".backdrop-blur-sm") { backdrop-filter: blur(4px); }
360
+ @include qss-dsl-boost(".qss-backdrop-blur-sm") { backdrop-filter: blur(4px); }
361
+ @include qss-dsl-boost(".backdrop-blur-md") { backdrop-filter: blur(8px); }
362
+ @include qss-dsl-boost(".qss-backdrop-blur-md") { backdrop-filter: blur(8px); }
363
+ @include qss-dsl-boost(".max-w-lg") { max-width: 32rem; }
364
+ @include qss-dsl-boost(".qss-max-w-lg") { max-width: 32rem; }
365
+ @include qss-dsl-boost(".scroll") { overflow: scroll; }
366
+ @include qss-dsl-boost(".qss-scroll") { overflow: scroll; }
367
+ @include qss-dsl-boost(".cursor-col-resize") { cursor: col-resize; }
368
+ @include qss-dsl-boost(".qss-cursor-col-resize") { cursor: col-resize; }
369
+ @include qss-dsl-boost(".cursor-row-resize") { cursor: row-resize; }
370
+ @include qss-dsl-boost(".qss-cursor-row-resize") { cursor: row-resize; }
371
+ @include qss-dsl-boost(".ring") { box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.5); }
372
+ @include qss-dsl-boost(".qss-ring") { box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.5); }
373
+ @include qss-dsl-boost(".resize") { resize: both; }
374
+ @include qss-dsl-boost(".qss-resize") { resize: both; }
375
+ @include qss-dsl-boost(".outline-none") { outline: none; }
376
+ @include qss-dsl-boost(".qss-outline-none") { outline: none; }
377
+
378
+
379
+ @include qss-dsl-boost(".qss-fill-h") { bottom: 0; }
380
+ @include qss-dsl-boost(".qss-fill-w") { right: 0; }
381
+ @include qss-dsl-boost(".qss-inline-flex") { display: inline-flex; }
382
+ @include qss-dsl-boost(".qss-flex-grow") { flex-grow: 1; }
383
+ @include qss-dsl-boost(".w-full") { width: 100%; }
384
+ @include qss-dsl-boost(".qss-w-full") { width: 100%; }
385
+ @include qss-dsl-boost(".h-full") { height: 100%; }
386
+ @include qss-dsl-boost(".qss-h-full") { height: 100%; }
387
+ @include qss-dsl-boost(".hidden") { display: none; }
388
+ @include qss-dsl-boost(".qss-hidden") { display: none; }
389
+ @include qss-dsl-boost(".visible") { visibility: visible; }
390
+ @include qss-dsl-boost(".invisible") { visibility: hidden; }
391
+ @include qss-dsl-boost(".qss-overflow-hidden") { overflow: hidden; }
392
+ @include qss-dsl-boost(".qss-overflow-y-auto") { overflow-y: auto; }
393
+
394
+ @include qss-dsl-boost(".clickable") { cursor: pointer; }
395
+ @include qss-dsl-boost(".qss-cursor-pointer") { cursor: pointer; }
396
+ @include qss-dsl-boost(".busy") { cursor: wait; }
397
+ @include qss-dsl-boost(".ghost") { pointer-events: none; }
398
+ @include qss-dsl-boost(".unselectable") { user-select: none; }
399
+
400
+ @include qss-dsl-boost(".smooth") { transition: all 0.2s ease-in-out; }
401
+ @include qss-dsl-boost(".qss-transition-all") { transition: all 0.2s ease-in-out; }
402
+ @include qss-dsl-boost(".transition-colors") { transition: background-color 0.2s, border-color 0.2s; }
403
+ @include qss-dsl-boost(".transition-none") { transition: none; }
404
+ @include qss-dsl-boost(".scroll-smooth") { scroll-behavior: smooth; }
405
+
406
+ /* Typography DSL Extensions */
407
+ @include qss-dsl-boost(".underline") { text-decoration: underline; }
408
+ @include qss-dsl-boost(".nowrap") { white-space: nowrap; }
409
+
410
+ /* Layout DSL Extensions */
411
+ @include qss-dsl-boost(".grid") { display: grid; }
412
+ @include qss-dsl-boost(".table-fixed") { table-layout: fixed; }
413
+ @include qss-dsl-boost(".contain") { object-fit: contain; }
414
+ @include qss-dsl-boost(".cover") { object-fit: cover; }
415
+
416
+ /* Visual Atmosphere */
417
+ @include qss-dsl-boost(".shadow-sm") { box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); }
418
+ @include qss-dsl-boost(".shadow-md") { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); }
419
+ @include qss-dsl-boost(".shadow-lg") { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); }
420
+ @include qss-dsl-boost(".shadow-none") { box-shadow: none; }
421
+
422
+ /* Visual Depth */
423
+ @each $key, $val in $qss-depths {
424
+ @include qss-dsl-boost(".qss-depth\\[#{$key}\\]") { z-index: #{$val}; }
425
+ }
426
+
427
+ /* Text scale (item 2, SETTLED 2026-09-21): text-size[N] = N px when the canvas is
428
+ calibration-width wide, scaling proportionally with --qnt at every other width,
429
+ bounded by a floor/cap that are themselves functions of N (not a flat px floor). */
430
+ $qss-text-ref: math.div(map-get($qss-text-scale, "calibration-width"), map-get($qss-quantization, "units"));
431
+ @for $size from 1 through 96 {
432
+ $qss-text-floor-mult: $size * map-get($qss-text-scale, "floor-multiplier");
433
+ $qss-text-floor: if($qss-text-floor-mult > map-get($qss-text-scale, "floor-px"), $qss-text-floor-mult, map-get($qss-text-scale, "floor-px")) * 1px;
434
+ $qss-text-cap: $size * map-get($qss-text-scale, "cap-multiplier") * 1px;
435
+ @include qss-dsl-boost(".qss-text-size\\[#{$size}\\]") {
436
+ font-size: clamp(#{$qss-text-floor}, calc(#{$size} * var(--qnt) / #{$qss-text-ref}), #{$qss-text-cap});
437
+ }
438
+ @include qss-dsl-boost(".text-size\\[#{$size}\\]") {
439
+ font-size: clamp(#{$qss-text-floor}, calc(#{$size} * var(--qnt) / #{$qss-text-ref}), #{$qss-text-cap});
440
+ }
441
+ }
442
+
443
+ /* Icon scale (item 2/3, SETTLED 2026-09-21): icon glyphs are non-text -- linear with
444
+ the new content unit, no floor, no cap. Brand new token, zero existing usage, so
445
+ it can use the content-scale unit today without waiting for Phase B's converter. */
446
+ @for $size from 1 through 96 {
447
+ @include qss-dsl-boost(".icon-size\\[#{$size}\\]") {
448
+ font-size: calc(#{$size} * var(--u));
449
+ }
450
+ }
451
+
452
+ @include qss-dsl-boost(".qss-ergonomic-floor") {
453
+ min-width: calc(44 * var(--qnt));
454
+ min-height: calc(44 * var(--qnt));
455
+ }
456
+
457
+ /* Item 7 (auditor rule / JIT elimination, SETTLED 2026-09-22): compile-time
458
+ variant-prefix and group-relational classes, replacing qss-engine.js's runtime
459
+ JIT for these states. Two dedicated mixins rather than an extension of
460
+ qss-dsl-boost, since the selector shape differs (same-element pseudo-class vs.
461
+ ancestor pseudo-class + descendant combinator). Real usage is confirmed
462
+ (2026-09-22 scan of a consuming project's views and scripts, 21 dead views
463
+ excluded) to be state = hover/focus/focus-within/active, always in the form
464
+ "{state}:{base}" (state itself is never qss-prefixed) -- the OLD block above
465
+ generated ".qss-#{state}:bg-X", which has never matched real usage syntax.
466
+ Removed as dead, superseded by this. */
467
+
468
+ @mixin qss-state-boost($selector, $state) {
469
+ :is(#{$qss-scope}) #{$selector}:#{$state} {
470
+ @content;
471
+ }
472
+ }
473
+
474
+ @mixin qss-group-boost($group-selector, $state, $descendant-selector) {
475
+ :is(#{$qss-scope}) #{$group-selector}:#{$state} #{$descendant-selector} {
476
+ @content;
477
+ }
478
+ }
479
+
480
+ /* Incidental fix found while scanning real usage: opacity-100/qss-opacity-100 are
481
+ used (including under hover:) but no base rule for them existed at all, with or
482
+ without a state prefix -- same shape as the existing bare .opacity rule. */
483
+ @include qss-dsl-boost(".opacity-100") { opacity: 1; }
484
+ @include qss-dsl-boost(".qss-opacity-100") { opacity: 1; }
485
+
486
+ /* ISOLATED TEST 2026-09-22 (self-referential only -- group-relational stays reverted
487
+ at 2 states below): re-adding the 21-state expansion here alone, to determine
488
+ whether the self-referential cross product by itself is what broke Cucumber, or
489
+ whether it was specifically the group-relational x group-name cross product.
490
+ Do not change this or any file while the verification Cucumber run is executing. */
491
+ $qss-state-prefixes-test: (
492
+ "hover", "focus", "focus-within", "active",
493
+ "enabled", "disabled", "checked", "indeterminate", "default", "placeholder-shown",
494
+ "valid", "invalid", "in-range", "out-of-range", "required", "optional",
495
+ "read-only", "read-write", "user-valid", "user-invalid", "autofill"
496
+ );
497
+ @each $state in $qss-state-prefixes-test {
498
+ @each $name, $hex in $qss-palette {
499
+ @include qss-state-boost(".#{$state}\\:qss-bg-#{$name}", $state) { background-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--bg-a, 100) * 1%), transparent); }
500
+ @include qss-state-boost(".#{$state}\\:bg-#{$name}", $state) { background-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--bg-a, 100) * 1%), transparent); }
501
+ @include qss-state-boost(".#{$state}\\:qss-text-#{$name}", $state) { color: color-mix(in srgb, var(--c-#{$name}) calc(var(--text-a, 100) * 1%), transparent); }
502
+ @include qss-state-boost(".#{$state}\\:text-#{$name}", $state) { color: color-mix(in srgb, var(--c-#{$name}) calc(var(--text-a, 100) * 1%), transparent); }
503
+ @include qss-state-boost(".#{$state}\\:qss-border-#{$name}", $state) { border-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--border-a, 100) * 1%), transparent); }
504
+ @include qss-state-boost(".#{$state}\\:border-#{$name}", $state) { border-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--border-a, 100) * 1%), transparent); }
505
+ }
506
+ }
507
+
508
+ /* Self-referential state variants of alpha classes -- same bounded reasoning. */
509
+ @each $state in $qss-state-prefixes-test {
510
+ @for $a from 0 through 100 {
511
+ @include qss-state-boost(".#{$state}\\:bg-alpha\\[#{$a}\\]", $state) { --bg-a: #{$a}; }
512
+ @include qss-state-boost(".#{$state}\\:border-alpha\\[#{$a}\\]", $state) { --border-a: #{$a}; }
513
+ @include qss-state-boost(".#{$state}\\:text-alpha\\[#{$a}\\]", $state) { --text-a: #{$a}; }
514
+ }
515
+ }
516
+
517
+ /* Item A step 3 (2026-09-23): essential, self-referential state rules. One rule per
518
+ state x property -- they decide WHETHER the property applies under the state and
519
+ read WHICH color from --accent-* (step 2 classes) and HOW opaque from --*-a.
520
+ Additive: adding a palette color adds zero rules here.
521
+ State list = W3C convention (architecture doc 10.3), not consumer config.
522
+ Held out deliberately: visited (privacy restrictions, needs its own test),
523
+ local-link (no browser support), DOM-position selectors (different mechanism). */
524
+ @if map-has-key($qss-palette, "accent") {
525
+ @error "Palette color named 'accent' would collide with the {state}:bg-accent essential classes.";
526
+ }
527
+ $qss-accent-states: (
528
+ "hover", "focus", "focus-within", "focus-visible", "active",
529
+ "enabled", "disabled", "checked", "indeterminate", "default", "placeholder-shown",
530
+ "valid", "invalid", "in-range", "out-of-range", "required", "optional",
531
+ "read-only", "read-write", "user-valid", "user-invalid", "autofill",
532
+ "link", "any-link", "target",
533
+ "open", "popover-open", "modal", "fullscreen", "picture-in-picture", "defined"
534
+ );
535
+ @each $state in $qss-accent-states {
536
+ @include qss-state-boost(".#{$state}\\:qss-bg-accent", $state) { background-color: color-mix(in srgb, var(--accent-bg) calc(var(--bg-a, 100) * 1%), transparent); }
537
+ @include qss-state-boost(".#{$state}\\:bg-accent", $state) { background-color: color-mix(in srgb, var(--accent-bg) calc(var(--bg-a, 100) * 1%), transparent); }
538
+ @include qss-state-boost(".#{$state}\\:qss-text-accent", $state) { color: color-mix(in srgb, var(--accent-text) calc(var(--text-a, 100) * 1%), transparent); }
539
+ @include qss-state-boost(".#{$state}\\:text-accent", $state) { color: color-mix(in srgb, var(--accent-text) calc(var(--text-a, 100) * 1%), transparent); }
540
+ @include qss-state-boost(".#{$state}\\:qss-border-accent", $state) { border-color: color-mix(in srgb, var(--accent-border) calc(var(--border-a, 100) * 1%), transparent); }
541
+ @include qss-state-boost(".#{$state}\\:border-accent", $state) { border-color: color-mix(in srgb, var(--accent-border) calc(var(--border-a, 100) * 1%), transparent); }
542
+ }
543
+
544
+ /* Item A step 4 (2026-09-23): essential, group-relational state rules -- same
545
+ 31-state list, gated by an ANCESTOR's state (bare .group, and each registered
546
+ named group from $qss-group-names). Still additive: (1 + groups) x states x props,
547
+ independent of palette size. Accent/alpha values come from the descendant itself. */
548
+ @each $state in $qss-accent-states {
549
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:qss-bg-accent") { background-color: color-mix(in srgb, var(--accent-bg) calc(var(--bg-a, 100) * 1%), transparent); }
550
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:bg-accent") { background-color: color-mix(in srgb, var(--accent-bg) calc(var(--bg-a, 100) * 1%), transparent); }
551
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:qss-text-accent") { color: color-mix(in srgb, var(--accent-text) calc(var(--text-a, 100) * 1%), transparent); }
552
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:text-accent") { color: color-mix(in srgb, var(--accent-text) calc(var(--text-a, 100) * 1%), transparent); }
553
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:qss-border-accent") { border-color: color-mix(in srgb, var(--accent-border) calc(var(--border-a, 100) * 1%), transparent); }
554
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:border-accent") { border-color: color-mix(in srgb, var(--accent-border) calc(var(--border-a, 100) * 1%), transparent); }
555
+ @each $group-name in $qss-group-names {
556
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:qss-bg-accent") { background-color: color-mix(in srgb, var(--accent-bg) calc(var(--bg-a, 100) * 1%), transparent); }
557
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:bg-accent") { background-color: color-mix(in srgb, var(--accent-bg) calc(var(--bg-a, 100) * 1%), transparent); }
558
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:qss-text-accent") { color: color-mix(in srgb, var(--accent-text) calc(var(--text-a, 100) * 1%), transparent); }
559
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:text-accent") { color: color-mix(in srgb, var(--accent-text) calc(var(--text-a, 100) * 1%), transparent); }
560
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:qss-border-accent") { border-color: color-mix(in srgb, var(--accent-border) calc(var(--border-a, 100) * 1%), transparent); }
561
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:border-accent") { border-color: color-mix(in srgb, var(--accent-border) calc(var(--border-a, 100) * 1%), transparent); }
562
+ }
563
+ }
564
+
565
+
566
+ /* Group-relational: named groups confirmed in real usage (2026-09-22 scan), plus the
567
+ unnamed/bare .group form. Palette crossed with group name x state is still bounded. */
568
+ /* $qss-group-names now comes from _qss_variables.scss (grammar.yml group_names) -- see architecture-decisions section 9.3. */
569
+
570
+ @each $state in ("hover", "focus-within") {
571
+ @each $name, $hex in $qss-palette {
572
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:qss-bg-#{$name}") { background-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--bg-a, 100) * 1%), transparent); }
573
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:bg-#{$name}") { background-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--bg-a, 100) * 1%), transparent); }
574
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:qss-text-#{$name}") { color: color-mix(in srgb, var(--c-#{$name}) calc(var(--text-a, 100) * 1%), transparent); }
575
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:text-#{$name}") { color: color-mix(in srgb, var(--c-#{$name}) calc(var(--text-a, 100) * 1%), transparent); }
576
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:qss-border-#{$name}") { border-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--border-a, 100) * 1%), transparent); }
577
+ @include qss-group-boost(".group", $state, ".group-#{$state}\\:border-#{$name}") { border-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--border-a, 100) * 1%), transparent); }
578
+ }
579
+ @each $group-name in $qss-group-names {
580
+ @each $name, $hex in $qss-palette {
581
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:qss-bg-#{$name}") { background-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--bg-a, 100) * 1%), transparent); }
582
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:bg-#{$name}") { background-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--bg-a, 100) * 1%), transparent); }
583
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:qss-text-#{$name}") { color: color-mix(in srgb, var(--c-#{$name}) calc(var(--text-a, 100) * 1%), transparent); }
584
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:text-#{$name}") { color: color-mix(in srgb, var(--c-#{$name}) calc(var(--text-a, 100) * 1%), transparent); }
585
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:qss-border-#{$name}") { border-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--border-a, 100) * 1%), transparent); }
586
+ @include qss-group-boost(".group\\/#{$group-name}", $state, ".group-#{$state}\\/#{$group-name}\\:border-#{$name}") { border-color: color-mix(in srgb, var(--c-#{$name}) calc(var(--border-a, 100) * 1%), transparent); }
587
+ }
588
+ }
589
+ }
590
+
591
+
592
+ /* Responsive Quantization (Macro Layout only to prevent bloat) */
593
+ @each $bp-name, $bp-width in $qss-breakpoints {
594
+ @media (min-width: #{$bp-width}) {
595
+ @for $i from 0 through map-get($qss-quantization, "units") {
596
+ .qss-#{$bp-name}\:w-pct\[#{$i}\] { width: #{$i * 0.1}%; }
597
+ .qss-#{$bp-name}\:h-pct\[#{$i}\] { height: #{$i * 0.1}%; }
598
+ .qss-#{$bp-name}\:pos-x-pct\[#{$i}\] { left: #{$i * 0.1}%; }
599
+ .qss-#{$bp-name}\:pos-y-pct\[#{$i}\] { top: #{$i * 0.1}%; }
600
+ }
601
+ }
602
+ }
603
+
604
+ /* Vertical Responsive Quantization (Macro-Y) */
605
+ @each $bp-name, $bp-height in $qss-vertical-breakpoints {
606
+ @media (min-height: #{$bp-height}) {
607
+ @for $i from 0 through map-get($qss-quantization, "units") {
608
+ .qss-#{$bp-name}\:w-pct\[#{$i}\] { width: #{$i * 0.1}%; }
609
+ .qss-#{$bp-name}\:h-pct\[#{$i}\] { height: #{$i * 0.1}%; }
610
+ .qss-#{$bp-name}\:pos-x-pct\[#{$i}\] { left: #{$i * 0.1}%; }
611
+ .qss-#{$bp-name}\:pos-y-pct\[#{$i}\] { top: #{$i * 0.1}%; }
612
+ }
613
+ }
614
+ }