elvish-css 1.0.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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +518 -0
  3. package/dist/elvish.css +2194 -0
  4. package/dist/elvish.d.ts +78 -0
  5. package/dist/elvish.esm.js +2185 -0
  6. package/dist/elvish.iife.js +2169 -0
  7. package/dist/elvish.min.css +9 -0
  8. package/dist/elvish.umd.js +2173 -0
  9. package/elvish.css +28 -0
  10. package/elvish.js +81 -0
  11. package/global/global.css +16 -0
  12. package/global/modern.css +305 -0
  13. package/global/reset.css +507 -0
  14. package/global/tokens.css +154 -0
  15. package/global/transitions.css +288 -0
  16. package/global/transitions.js +289 -0
  17. package/global/utilities.css +151 -0
  18. package/package.json +61 -0
  19. package/primitives/adleithian/adleithian.css +16 -0
  20. package/primitives/adleithian/adleithian.js +63 -0
  21. package/primitives/bau/bau.css +86 -0
  22. package/primitives/bau/bau.js +127 -0
  23. package/primitives/enedh/enedh.css +38 -0
  24. package/primitives/enedh/enedh.js +110 -0
  25. package/primitives/esgal/esgal.css +39 -0
  26. package/primitives/esgal/esgal.js +115 -0
  27. package/primitives/fano/fano.css +28 -0
  28. package/primitives/fano/fano.js +108 -0
  29. package/primitives/gant-thala/gant-thala.css +32 -0
  30. package/primitives/gant-thala/gant-thala.js +69 -0
  31. package/primitives/glan-tholl/glan-tholl.css +71 -0
  32. package/primitives/glan-tholl/glan-tholl.js +147 -0
  33. package/primitives/glan-veleg/glan-veleg.css +45 -0
  34. package/primitives/glan-veleg/glan-veleg.js +138 -0
  35. package/primitives/gonath/gonath.css +57 -0
  36. package/primitives/gonath/gonath.js +113 -0
  37. package/primitives/gwistindor/gwistindor.css +52 -0
  38. package/primitives/gwistindor/gwistindor.js +96 -0
  39. package/primitives/hath/hath.css +39 -0
  40. package/primitives/hath/hath.js +107 -0
  41. package/primitives/him/him.css +43 -0
  42. package/primitives/him/him.js +169 -0
  43. package/primitives/miriant/miriant.css +75 -0
  44. package/primitives/miriant/miriant.js +158 -0
  45. package/primitives/thann/thann.css +57 -0
  46. package/primitives/thann/thann.js +96 -0
  47. package/primitives/tiniath/tiniath.css +16 -0
  48. package/primitives/tiniath/tiniath.js +88 -0
  49. package/primitives/vircantie/vircantie.css +24 -0
  50. package/primitives/vircantie/vircantie.js +83 -0
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Him Layout Custom Element (NEW)
3
+ *
4
+ * Creates sticky positioning with configurable offset.
5
+ * Optionally detects "stuck" state via IntersectionObserver.
6
+ *
7
+ * @property {string} to - Direction to stick: top, bottom, left, right (default: top)
8
+ * @property {string} offset - Distance from edge when stuck (default: 0)
9
+ * @property {boolean} sentinel - Enable stuck state detection
10
+ *
11
+ * @example
12
+ * <i-him offset="var(--s1)" sentinel>
13
+ * <header>This header sticks</header>
14
+ * </i-him>
15
+ */
16
+
17
+ class HimLayout extends HTMLElement {
18
+ static get observedAttributes() {
19
+ return ['to', 'offset', 'sentinel'];
20
+ }
21
+
22
+ constructor() {
23
+ super();
24
+ this.render = this.render.bind(this);
25
+ this.observer = null;
26
+ this.sentinelEl = null;
27
+ }
28
+
29
+ connectedCallback() {
30
+ this.render();
31
+ }
32
+
33
+ disconnectedCallback() {
34
+ this.cleanupSentinel();
35
+ }
36
+
37
+ attributeChangedCallback() {
38
+ this.render();
39
+ }
40
+
41
+ get to() {
42
+ return this.getAttribute('to') || 'top';
43
+ }
44
+
45
+ set to(val) {
46
+ this.setAttribute('to', val);
47
+ }
48
+
49
+ get offset() {
50
+ return this.getAttribute('offset') || '0';
51
+ }
52
+
53
+ set offset(val) {
54
+ this.setAttribute('offset', val);
55
+ }
56
+
57
+ get sentinel() {
58
+ return this.hasAttribute('sentinel');
59
+ }
60
+
61
+ set sentinel(val) {
62
+ if (val) {
63
+ this.setAttribute('sentinel', '');
64
+ } else {
65
+ this.removeAttribute('sentinel');
66
+ }
67
+ }
68
+
69
+ cleanupSentinel() {
70
+ if (this.observer) {
71
+ this.observer.disconnect();
72
+ this.observer = null;
73
+ }
74
+ if (this.sentinelEl) {
75
+ this.sentinelEl.remove();
76
+ this.sentinelEl = null;
77
+ }
78
+ }
79
+
80
+ setupSentinel() {
81
+ this.cleanupSentinel();
82
+
83
+ if (!this.sentinel || !('IntersectionObserver' in window)) {
84
+ return;
85
+ }
86
+
87
+ // Create invisible sentinel element
88
+ this.sentinelEl = document.createElement('div');
89
+ this.sentinelEl.style.cssText = `
90
+ position: absolute;
91
+ height: 1px;
92
+ width: 100%;
93
+ pointer-events: none;
94
+ visibility: hidden;
95
+ `;
96
+
97
+ // Position sentinel based on sticky direction
98
+ if (this.to === 'bottom') {
99
+ this.sentinelEl.style.bottom = '0';
100
+ this.insertAdjacentElement('afterend', this.sentinelEl);
101
+ } else {
102
+ this.sentinelEl.style.top = '0';
103
+ this.insertAdjacentElement('beforebegin', this.sentinelEl);
104
+ }
105
+
106
+ // Observe the sentinel
107
+ this.observer = new IntersectionObserver(
108
+ (entries) => {
109
+ entries.forEach((entry) => {
110
+ // When sentinel is not visible, we're "stuck"
111
+ const isStuck = !entry.isIntersecting;
112
+ this.dataset.stuck = isStuck;
113
+ this.dispatchEvent(new CustomEvent('stuck-change', {
114
+ detail: { stuck: isStuck }
115
+ }));
116
+ });
117
+ },
118
+ { threshold: [0] }
119
+ );
120
+
121
+ this.observer.observe(this.sentinelEl);
122
+ }
123
+
124
+ render() {
125
+ this.style.setProperty('--him-offset', this.offset);
126
+
127
+ const id = `Him-${this.to}-${this.offset}`.replace(/[^\w-]/g, '');
128
+ this.dataset.i = id;
129
+
130
+ if (!document.getElementById(id)) {
131
+ const styleEl = document.createElement('style');
132
+ styleEl.id = id;
133
+
134
+ const selector = `[data-i="${id}"]`;
135
+ let css = '';
136
+
137
+ switch (this.to) {
138
+ case 'bottom':
139
+ css = `${selector} { inset-block-start: auto; inset-block-end: ${this.offset}; }`;
140
+ break;
141
+ case 'left':
142
+ css = `${selector} { inset-block-start: auto; inset-inline-start: ${this.offset}; }`;
143
+ break;
144
+ case 'right':
145
+ css = `${selector} { inset-block-start: auto; inset-inline-end: ${this.offset}; }`;
146
+ break;
147
+ default: // top
148
+ css = `${selector} { inset-block-start: ${this.offset}; }`;
149
+ }
150
+
151
+ styleEl.textContent = css;
152
+ document.head.appendChild(styleEl);
153
+ }
154
+
155
+ // Setup or cleanup sentinel observation
156
+ if (this.sentinel) {
157
+ // Defer to ensure element is in DOM
158
+ requestAnimationFrame(() => this.setupSentinel());
159
+ } else {
160
+ this.cleanupSentinel();
161
+ }
162
+ }
163
+ }
164
+
165
+ if ('customElements' in window) {
166
+ customElements.define('i-him', HimLayout);
167
+ }
168
+
169
+ export default HimLayout;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Grid-Placed Layout (NEW)
3
+ *
4
+ * A CSS Grid with explicit control over columns, rows, and item placement.
5
+ * For when the auto-flow Grid primitive isn't enough.
6
+ *
7
+ * This is the "escape hatch" for complex grid layouts like:
8
+ * - Magazine-style layouts with spanning items
9
+ * - Dashboard widgets of varying sizes
10
+ * - Bento box layouts
11
+ */
12
+
13
+ i-miriant {
14
+ display: grid;
15
+ gap: var(--miriant-space, var(--s1));
16
+
17
+ /* Default: 12-column grid (common baseline) */
18
+ grid-template-columns: repeat(var(--miriant-columns, 12), 1fr);
19
+
20
+ /* Rows auto-size by default */
21
+ grid-auto-rows: var(--miriant-row-height, minmax(0, auto));
22
+ }
23
+
24
+ /* Child placement utilities using data attributes */
25
+ /* Columns */
26
+ i-miriant > [data-col-span="1"] { grid-column: span 1; }
27
+ i-miriant > [data-col-span="2"] { grid-column: span 2; }
28
+ i-miriant > [data-col-span="3"] { grid-column: span 3; }
29
+ i-miriant > [data-col-span="4"] { grid-column: span 4; }
30
+ i-miriant > [data-col-span="5"] { grid-column: span 5; }
31
+ i-miriant > [data-col-span="6"] { grid-column: span 6; }
32
+ i-miriant > [data-col-span="7"] { grid-column: span 7; }
33
+ i-miriant > [data-col-span="8"] { grid-column: span 8; }
34
+ i-miriant > [data-col-span="9"] { grid-column: span 9; }
35
+ i-miriant > [data-col-span="10"] { grid-column: span 10; }
36
+ i-miriant > [data-col-span="11"] { grid-column: span 11; }
37
+ i-miriant > [data-col-span="12"] { grid-column: span 12; }
38
+ i-miriant > [data-col-span="full"] { grid-column: 1 / -1; }
39
+
40
+ /* Rows */
41
+ i-miriant > [data-row-span="1"] { grid-row: span 1; }
42
+ i-miriant > [data-row-span="2"] { grid-row: span 2; }
43
+ i-miriant > [data-row-span="3"] { grid-row: span 3; }
44
+ i-miriant > [data-row-span="4"] { grid-row: span 4; }
45
+ i-miriant > [data-row-span="5"] { grid-row: span 5; }
46
+ i-miriant > [data-row-span="6"] { grid-row: span 6; }
47
+
48
+ /* Dense packing - fill holes */
49
+ i-miriant[dense] {
50
+ grid-auto-flow: dense;
51
+ }
52
+
53
+ /* Responsive: collapse to single column below threshold */
54
+ @container (width < 600px) {
55
+ i-miriant {
56
+ grid-template-columns: 1fr;
57
+ }
58
+
59
+ i-miriant > [data-col-span] {
60
+ grid-column: span 1;
61
+ }
62
+ }
63
+
64
+ /* Alternative: use media query fallback for browsers without container queries */
65
+ @supports not (container-type: inline-size) {
66
+ @media (max-width: 600px) {
67
+ i-miriant {
68
+ grid-template-columns: 1fr;
69
+ }
70
+
71
+ i-miriant > [data-col-span] {
72
+ grid-column: span 1;
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Grid-Placed Layout Custom Element (NEW)
3
+ *
4
+ * A CSS Grid with explicit control over columns, rows, and item placement.
5
+ *
6
+ * @property {number} columns - Number of grid columns (default: 12)
7
+ * @property {string} space - Gap between grid cells (default: var(--s1))
8
+ * @property {string} rowHeight - Height of auto-generated rows (default: minmax(0, auto))
9
+ * @property {boolean} dense - Enable dense packing to fill holes
10
+ *
11
+ * Children can use data attributes for placement:
12
+ * - data-col-span="N" - Span N columns (1-12 or "full")
13
+ * - data-row-span="N" - Span N rows (1-6)
14
+ * - data-col-start="N" - Start at column N
15
+ * - data-row-start="N" - Start at row N
16
+ *
17
+ * @example
18
+ * <i-miriant columns="4" space="var(--s2)">
19
+ * <div data-col-span="2" data-row-span="2">Feature</div>
20
+ * <div>Small</div>
21
+ * <div>Small</div>
22
+ * <div data-col-span="full">Full width</div>
23
+ * </i-miriant>
24
+ */
25
+
26
+ class MiriantLayout extends HTMLElement {
27
+ static get observedAttributes() {
28
+ return ['columns', 'space', 'row-height', 'dense'];
29
+ }
30
+
31
+ constructor() {
32
+ super();
33
+ this.render = this.render.bind(this);
34
+ this.mutationObserver = null;
35
+ }
36
+
37
+ connectedCallback() {
38
+ this.render();
39
+ this.setupChildObserver();
40
+ }
41
+
42
+ disconnectedCallback() {
43
+ if (this.mutationObserver) {
44
+ this.mutationObserver.disconnect();
45
+ }
46
+ }
47
+
48
+ attributeChangedCallback() {
49
+ this.render();
50
+ }
51
+
52
+ get columns() {
53
+ return parseInt(this.getAttribute('columns'), 10) || 12;
54
+ }
55
+
56
+ set columns(val) {
57
+ this.setAttribute('columns', val);
58
+ }
59
+
60
+ get space() {
61
+ return this.getAttribute('space') || 'var(--s1)';
62
+ }
63
+
64
+ set space(val) {
65
+ this.setAttribute('space', val);
66
+ }
67
+
68
+ get rowHeight() {
69
+ return this.getAttribute('row-height') || 'minmax(0, auto)';
70
+ }
71
+
72
+ set rowHeight(val) {
73
+ this.setAttribute('row-height', val);
74
+ }
75
+
76
+ get dense() {
77
+ return this.hasAttribute('dense');
78
+ }
79
+
80
+ set dense(val) {
81
+ if (val) {
82
+ this.setAttribute('dense', '');
83
+ } else {
84
+ this.removeAttribute('dense');
85
+ }
86
+ }
87
+
88
+ setupChildObserver() {
89
+ if (!('MutationObserver' in window)) return;
90
+
91
+ this.mutationObserver = new MutationObserver((mutations) => {
92
+ mutations.forEach((mutation) => {
93
+ if (mutation.type === 'childList') {
94
+ this.styleChildren();
95
+ }
96
+ });
97
+ });
98
+
99
+ this.mutationObserver.observe(this, { childList: true });
100
+ this.styleChildren();
101
+ }
102
+
103
+ styleChildren() {
104
+ // Apply inline styles for explicit placement (data-col-start, data-row-start)
105
+ Array.from(this.children).forEach((child) => {
106
+ const colStart = child.dataset.colStart;
107
+ const rowStart = child.dataset.rowStart;
108
+
109
+ if (colStart) {
110
+ child.style.gridColumnStart = colStart;
111
+ }
112
+ if (rowStart) {
113
+ child.style.gridRowStart = rowStart;
114
+ }
115
+ });
116
+ }
117
+
118
+ render() {
119
+ this.style.setProperty('--miriant-columns', this.columns);
120
+ this.style.setProperty('--miriant-space', this.space);
121
+ this.style.setProperty('--miriant-row-height', this.rowHeight);
122
+
123
+ const denseStr = this.dense ? '-dense' : '';
124
+ const id = `Miriant-${this.columns}-${this.space}-${this.rowHeight}${denseStr}`.replace(/[^\w-]/g, '');
125
+ this.dataset.i = id;
126
+
127
+ // Set container-type for container queries
128
+ this.style.containerType = 'inline-size';
129
+
130
+ if (!document.getElementById(id)) {
131
+ const styleEl = document.createElement('style');
132
+ styleEl.id = id;
133
+
134
+ const selector = `[data-i="${id}"]`;
135
+
136
+ let css = `
137
+ ${selector} {
138
+ grid-template-columns: repeat(${this.columns}, 1fr);
139
+ gap: ${this.space};
140
+ grid-auto-rows: ${this.rowHeight};
141
+ }
142
+ `;
143
+
144
+ if (this.dense) {
145
+ css += `${selector} { grid-auto-flow: dense; }`;
146
+ }
147
+
148
+ styleEl.textContent = css;
149
+ document.head.appendChild(styleEl);
150
+ }
151
+ }
152
+ }
153
+
154
+ if ('customElements' in window) {
155
+ customElements.define('i-miriant', MiriantLayout);
156
+ }
157
+
158
+ export default MiriantLayout;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Thann Layout (Icon)
3
+ *
4
+ * Aligns an SVG icon with accompanying text.
5
+ * Uses relative units for automatic scaling.
6
+ *
7
+ * Attributes:
8
+ * - echuiol: "active" state styling
9
+ * - dhoren: "hidden" state (visually hidden but accessible)
10
+ */
11
+
12
+ i-thann {
13
+ display: inline-flex;
14
+ align-items: baseline;
15
+ gap: var(--thann-space, 0);
16
+ }
17
+
18
+ i-thann svg {
19
+ /* Match uppercase letter height */
20
+ block-size: 0.75em;
21
+ block-size: 1cap; /* Where supported */
22
+
23
+ inline-size: 0.75em;
24
+ inline-size: 1cap; /* Where supported */
25
+
26
+ /* Inherit text color */
27
+ fill: currentColor;
28
+ stroke: currentColor;
29
+ }
30
+
31
+ /* When using natural word spacing (no explicit space) */
32
+ i-thann:not([space]) {
33
+ display: inline;
34
+ }
35
+
36
+ i-thann:not([space]) svg {
37
+ display: inline;
38
+ vertical-align: -0.125em; /* Fine-tune baseline alignment */
39
+ }
40
+
41
+ /* Echuiol = Active state */
42
+ i-thann[echuiol] {
43
+ color: var(--color-accent, currentColor);
44
+ }
45
+
46
+ /* Dhoren = Hidden (visually hidden but accessible) */
47
+ i-thann[dhoren] {
48
+ position: absolute;
49
+ inline-size: 1px;
50
+ block-size: 1px;
51
+ padding: 0;
52
+ margin: -1px;
53
+ overflow: hidden;
54
+ clip: rect(0, 0, 0, 0);
55
+ white-space: nowrap;
56
+ border: 0;
57
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Thann Layout Custom Element
3
+ *
4
+ * Aligns an SVG icon with accompanying text.
5
+ *
6
+ * @property {string} space - Gap between icon and text (default: natural word space)
7
+ * @property {string} label - Accessible label for standalone icons
8
+ *
9
+ * @example
10
+ * <i-thann space="0.5em">
11
+ * <svg>...</svg>
12
+ * Close
13
+ * </i-thann>
14
+ */
15
+
16
+ class ThannLayout extends HTMLElement {
17
+ static get observedAttributes() {
18
+ return ['space', 'label'];
19
+ }
20
+
21
+ constructor() {
22
+ super();
23
+ this.render = this.render.bind(this);
24
+ }
25
+
26
+ connectedCallback() {
27
+ this.render();
28
+ }
29
+
30
+ attributeChangedCallback() {
31
+ this.render();
32
+ }
33
+
34
+ get space() {
35
+ return this.getAttribute('space');
36
+ }
37
+
38
+ set space(val) {
39
+ if (val) {
40
+ this.setAttribute('space', val);
41
+ } else {
42
+ this.removeAttribute('space');
43
+ }
44
+ }
45
+
46
+ get label() {
47
+ return this.getAttribute('label');
48
+ }
49
+
50
+ set label(val) {
51
+ if (val) {
52
+ this.setAttribute('label', val);
53
+ } else {
54
+ this.removeAttribute('label');
55
+ }
56
+ }
57
+
58
+ render() {
59
+ // Handle accessibility for standalone icons
60
+ if (this.label) {
61
+ this.setAttribute('role', 'img');
62
+ this.setAttribute('aria-label', this.label);
63
+ } else {
64
+ this.removeAttribute('role');
65
+ this.removeAttribute('aria-label');
66
+ }
67
+
68
+ // Only set custom property if space is specified
69
+ if (this.space) {
70
+ this.style.setProperty('--thann-space', this.space);
71
+
72
+ const id = `Thann-${this.space}`.replace(/[^\w-]/g, '');
73
+ this.dataset.i = id;
74
+
75
+ if (!document.getElementById(id)) {
76
+ const styleEl = document.createElement('style');
77
+ styleEl.id = id;
78
+
79
+ const selector = `[data-i="${id}"]`;
80
+
81
+ styleEl.textContent = `
82
+ ${selector} {
83
+ gap: ${this.space};
84
+ }
85
+ `;
86
+ document.head.appendChild(styleEl);
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ if ('customElements' in window) {
93
+ customElements.define('i-thann', ThannLayout);
94
+ }
95
+
96
+ export default ThannLayout;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Cluster Layout
3
+ *
4
+ * Groups elements that differ in length and wrap naturally.
5
+ * Perfect for tags, buttons, navigation items.
6
+ */
7
+
8
+ i-tiniath {
9
+ display: flex;
10
+ flex-wrap: wrap;
11
+ gap: var(--tiniath-space, var(--s1));
12
+
13
+ /* Default justification and alignment */
14
+ justify-content: var(--tiniath-justify, flex-start);
15
+ align-items: var(--tiniath-align, center);
16
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Cluster Layout Custom Element
3
+ *
4
+ * Groups elements that differ in length and wrap naturally.
5
+ *
6
+ * @property {string} space - Gap between items (default: var(--s1))
7
+ * @property {string} justify - justify-content value (default: flex-start)
8
+ * @property {string} align - align-items value (default: center)
9
+ *
10
+ * @example
11
+ * <i-tiniath space="var(--s0)" justify="space-between">
12
+ * <button>Save</button>
13
+ * <button>Cancel</button>
14
+ * </i-tiniath>
15
+ */
16
+
17
+ class TiniathLayout extends HTMLElement {
18
+ static get observedAttributes() {
19
+ return ['space', 'justify', 'align'];
20
+ }
21
+
22
+ constructor() {
23
+ super();
24
+ this.render = this.render.bind(this);
25
+ }
26
+
27
+ connectedCallback() {
28
+ this.render();
29
+ }
30
+
31
+ attributeChangedCallback() {
32
+ this.render();
33
+ }
34
+
35
+ get space() {
36
+ return this.getAttribute('space') || 'var(--s1)';
37
+ }
38
+
39
+ set space(val) {
40
+ this.setAttribute('space', val);
41
+ }
42
+
43
+ get justify() {
44
+ return this.getAttribute('justify') || 'flex-start';
45
+ }
46
+
47
+ set justify(val) {
48
+ this.setAttribute('justify', val);
49
+ }
50
+
51
+ get align() {
52
+ return this.getAttribute('align') || 'center';
53
+ }
54
+
55
+ set align(val) {
56
+ this.setAttribute('align', val);
57
+ }
58
+
59
+ render() {
60
+ this.style.setProperty('--tiniath-space', this.space);
61
+ this.style.setProperty('--tiniath-justify', this.justify);
62
+ this.style.setProperty('--tiniath-align', this.align);
63
+
64
+ const id = `Tiniath-${this.space}-${this.justify}-${this.align}`.replace(/[^\w-]/g, '');
65
+ this.dataset.i = id;
66
+
67
+ if (!document.getElementById(id)) {
68
+ const styleEl = document.createElement('style');
69
+ styleEl.id = id;
70
+
71
+ const selector = `[data-i="${id}"]`;
72
+ styleEl.textContent = `
73
+ ${selector} {
74
+ gap: ${this.space};
75
+ justify-content: ${this.justify};
76
+ align-items: ${this.align};
77
+ }
78
+ `;
79
+ document.head.appendChild(styleEl);
80
+ }
81
+ }
82
+ }
83
+
84
+ if ('customElements' in window) {
85
+ customElements.define('i-tiniath', TiniathLayout);
86
+ }
87
+
88
+ export default TiniathLayout;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Vircantie Layout (Grid)
3
+ *
4
+ * Auto-flowing grid with responsive columns based on minimum width.
5
+ * Uses CSS Grid's auto-fit with min() for robust responsiveness.
6
+ */
7
+
8
+ i-vircantie {
9
+ display: grid;
10
+ gap: var(--vircantie-space, var(--s1));
11
+ }
12
+
13
+ /*
14
+ * Using min() prevents overflow when container is narrower than minimum.
15
+ * The 100% value kicks in when min would cause overflow.
16
+ */
17
+ @supports (width: min(var(--vircantie-min, 250px), 100%)) {
18
+ i-vircantie {
19
+ grid-template-columns: repeat(
20
+ auto-fit,
21
+ minmax(min(var(--vircantie-min, 250px), 100%), 1fr)
22
+ );
23
+ }
24
+ }