farvist 0.5.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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +324 -0
  3. package/assets/farvist.js +187 -0
  4. package/assets/icons/farvist-icons.svg +49 -0
  5. package/assets/logo.svg +11 -0
  6. package/assets/og-image.svg +34 -0
  7. package/assets/patterns/blob.svg +9 -0
  8. package/assets/patterns/dots.svg +3 -0
  9. package/assets/patterns/grid.svg +3 -0
  10. package/assets/patterns/mesh.svg +20 -0
  11. package/dist/farvist.css +8967 -0
  12. package/dist/farvist.min.css +1 -0
  13. package/package.json +53 -0
  14. package/scss/abstracts/_functions.scss +85 -0
  15. package/scss/abstracts/_index.scss +9 -0
  16. package/scss/abstracts/_mixins.scss +78 -0
  17. package/scss/abstracts/_variables.scss +252 -0
  18. package/scss/base/_reset.scss +120 -0
  19. package/scss/base/_root.scss +87 -0
  20. package/scss/base/_typography.scss +102 -0
  21. package/scss/components/_accordion.scss +64 -0
  22. package/scss/components/_alerts.scss +63 -0
  23. package/scss/components/_avatar.scss +76 -0
  24. package/scss/components/_badges.scss +54 -0
  25. package/scss/components/_breadcrumb.scss +44 -0
  26. package/scss/components/_buttons.scss +163 -0
  27. package/scss/components/_callout.scss +37 -0
  28. package/scss/components/_cards.scss +74 -0
  29. package/scss/components/_chip.scss +61 -0
  30. package/scss/components/_dropdown.scss +90 -0
  31. package/scss/components/_empty-state.scss +37 -0
  32. package/scss/components/_forms.scss +125 -0
  33. package/scss/components/_icon.scss +25 -0
  34. package/scss/components/_list-group.scss +60 -0
  35. package/scss/components/_modal.scss +95 -0
  36. package/scss/components/_navbar.scss +67 -0
  37. package/scss/components/_pagination.scss +51 -0
  38. package/scss/components/_progress.scss +60 -0
  39. package/scss/components/_range.scss +58 -0
  40. package/scss/components/_rating.scss +26 -0
  41. package/scss/components/_segmented.scss +51 -0
  42. package/scss/components/_skeleton.scss +52 -0
  43. package/scss/components/_spinner.scss +60 -0
  44. package/scss/components/_stat.scss +32 -0
  45. package/scss/components/_stepper.scss +78 -0
  46. package/scss/components/_switch.scss +65 -0
  47. package/scss/components/_table.scss +51 -0
  48. package/scss/components/_tabs.scss +64 -0
  49. package/scss/components/_timeline.scss +77 -0
  50. package/scss/components/_toast.scss +79 -0
  51. package/scss/components/_tooltip.scss +45 -0
  52. package/scss/farvist.scss +60 -0
  53. package/scss/layout/_grid.scss +83 -0
  54. package/scss/utilities/_backgrounds.scss +110 -0
  55. package/scss/utilities/_effects.scss +118 -0
  56. package/scss/utilities/_spacing.scss +76 -0
  57. package/scss/utilities/_utilities.scss +213 -0
@@ -0,0 +1,60 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Spinner
3
+ // A ring loader and a bouncing-dots loader, both color-themeable.
4
+ // =============================================================================
5
+
6
+ @use 'sass:map';
7
+ @use '../abstracts' as *;
8
+
9
+ .spinner {
10
+ display: inline-block;
11
+ width: 1.5rem;
12
+ height: 1.5rem;
13
+ vertical-align: middle;
14
+ border: 3px solid var(--fv-glass-border);
15
+ border-top-color: var(--fv-primary);
16
+ border-radius: 50%;
17
+ animation: fv-spin 0.7s linear infinite;
18
+ }
19
+
20
+ .spinner-sm { width: 1rem; height: 1rem; border-width: 2px; }
21
+ .spinner-lg { width: 2.5rem; height: 2.5rem; border-width: 4px; }
22
+
23
+ @each $name, $clr in $theme-colors {
24
+ .spinner-#{$name} { border-top-color: $clr; }
25
+ }
26
+
27
+ // Three bouncing dots.
28
+ .spinner-dots {
29
+ display: inline-flex;
30
+ gap: 0.3rem;
31
+ vertical-align: middle;
32
+
33
+ > span {
34
+ width: 0.5rem;
35
+ height: 0.5rem;
36
+ background-color: var(--fv-primary);
37
+ border-radius: 50%;
38
+ animation: fv-bounce 0.6s ease-in-out infinite;
39
+ }
40
+
41
+ > span:nth-child(2) { animation-delay: 0.12s; }
42
+ > span:nth-child(3) { animation-delay: 0.24s; }
43
+ }
44
+
45
+ @keyframes fv-spin {
46
+ to { transform: rotate(360deg); }
47
+ }
48
+
49
+ @keyframes fv-bounce {
50
+ 0%, 100% { transform: translateY(0); opacity: 0.5; }
51
+ 50% { transform: translateY(-0.45rem); opacity: 1; }
52
+ }
53
+
54
+ // Keep a slow, continuous spin so the loading indicator stays meaningful. The
55
+ // !important is required to beat the global reduced-motion reset (which would
56
+ // otherwise freeze the ring mid-rotation).
57
+ @media (prefers-reduced-motion: reduce) {
58
+ .spinner { animation: fv-spin 1.6s linear infinite !important; }
59
+ .spinner-dots > span { animation: none; }
60
+ }
@@ -0,0 +1,32 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Stat
3
+ // Typographic helpers for metric tiles (drop inside a .card).
4
+ // <div class="stat-value">8,420</div>
5
+ // <div class="stat-label">Active users</div>
6
+ // <span class="stat-trend stat-trend-up">+12%</span>
7
+ // =============================================================================
8
+
9
+ @use 'sass:map';
10
+ @use '../abstracts' as *;
11
+
12
+ .stat-value {
13
+ font-size: map.get($font-sizes, '3xl');
14
+ font-weight: map.get($font-weights, 'black');
15
+ line-height: 1.1;
16
+ letter-spacing: -0.02em;
17
+ }
18
+
19
+ .stat-label {
20
+ color: var(--fv-muted);
21
+ }
22
+
23
+ .stat-trend {
24
+ display: inline-flex;
25
+ align-items: center;
26
+ gap: 0.25rem;
27
+ font-size: map.get($font-sizes, 'sm');
28
+ font-weight: map.get($font-weights, 'semibold');
29
+ }
30
+
31
+ .stat-trend-up { color: var(--fv-success); }
32
+ .stat-trend-down { color: var(--fv-danger); }
@@ -0,0 +1,78 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Stepper
3
+ // <ol class="stepper">
4
+ // <li class="step is-done"><span class="step-dot">1</span><span class="step-label">Account</span></li>
5
+ // <li class="step is-active"><span class="step-dot">2</span><span class="step-label">Plan</span></li>
6
+ // <li class="step"><span class="step-dot">3</span><span class="step-label">Done</span></li>
7
+ // </ol>
8
+ // =============================================================================
9
+
10
+ @use 'sass:map';
11
+ @use '../abstracts' as *;
12
+
13
+ .stepper {
14
+ display: flex;
15
+ gap: spacer(2);
16
+ padding: 0;
17
+ margin: 0 0 spacer(4);
18
+ list-style: none;
19
+ }
20
+
21
+ .step {
22
+ position: relative;
23
+ flex: 1 1 0;
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ gap: spacer(2);
28
+ text-align: center;
29
+ }
30
+
31
+ .step-dot {
32
+ position: relative;
33
+ z-index: 1;
34
+ display: inline-flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ width: 2rem;
38
+ height: 2rem;
39
+ font-weight: map.get($font-weights, 'semibold');
40
+ color: var(--fv-muted);
41
+ background-color: var(--fv-body-bg);
42
+ border: $border-width solid var(--fv-glass-border);
43
+ border-radius: 50%;
44
+ }
45
+
46
+ .step-label {
47
+ font-size: map.get($font-sizes, 'sm');
48
+ color: var(--fv-muted);
49
+ }
50
+
51
+ // Connector line from each step's center to the next.
52
+ .step:not(:last-child)::after {
53
+ content: '';
54
+ position: absolute;
55
+ top: 1rem;
56
+ left: 50%;
57
+ width: 100%;
58
+ height: 2px;
59
+ background-color: var(--fv-glass-border);
60
+ }
61
+
62
+ .step.is-active .step-dot {
63
+ color: #ffffff;
64
+ background-image: var(--fv-gradient-primary);
65
+ border-color: transparent;
66
+ box-shadow: var(--fv-glow-primary);
67
+ }
68
+
69
+ .step.is-done .step-dot {
70
+ color: #ffffff;
71
+ background-color: var(--fv-success);
72
+ border-color: transparent;
73
+ }
74
+
75
+ .step.is-active .step-label,
76
+ .step.is-done .step-label {
77
+ color: var(--fv-body-color);
78
+ }
@@ -0,0 +1,65 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Switch (toggle)
3
+ // Markup (give the input a label — visible text or aria-label):
4
+ // <label class="switch">
5
+ // <input type="checkbox" aria-label="Dark mode" />
6
+ // <span class="switch-track"></span>
7
+ // <span class="switch-thumb"></span>
8
+ // </label>
9
+ // =============================================================================
10
+
11
+ @use 'sass:map';
12
+ @use '../abstracts' as *;
13
+
14
+ .switch {
15
+ position: relative;
16
+ display: inline-flex;
17
+ align-items: center;
18
+ cursor: pointer;
19
+
20
+ input {
21
+ position: absolute;
22
+ width: 0;
23
+ height: 0;
24
+ opacity: 0;
25
+ }
26
+ }
27
+
28
+ .switch-track {
29
+ width: 2.6rem;
30
+ height: 1.5rem;
31
+ background-color: var(--fv-glass-bg-strong);
32
+ border: $border-width solid var(--fv-glass-border);
33
+ border-radius: map.get($radii, 'pill');
34
+ transition: background-color $transition-base, border-color $transition-base;
35
+ }
36
+
37
+ .switch-thumb {
38
+ position: absolute;
39
+ top: 50%;
40
+ left: 0.22rem;
41
+ width: 1.04rem;
42
+ height: 1.04rem;
43
+ background-color: #ffffff;
44
+ border-radius: 50%;
45
+ box-shadow: var(--fv-shadow-sm);
46
+ transform: translateY(-50%);
47
+ transition: transform $transition-base;
48
+ }
49
+
50
+ .switch input:checked ~ .switch-track {
51
+ background-image: var(--fv-gradient-primary);
52
+ border-color: transparent;
53
+ }
54
+
55
+ .switch input:checked ~ .switch-thumb {
56
+ transform: translateY(-50%) translateX(1.08rem);
57
+ }
58
+
59
+ .switch input:focus-visible ~ .switch-track {
60
+ box-shadow: var(--fv-focus-ring);
61
+ }
62
+
63
+ .switch input:disabled ~ .switch-track {
64
+ opacity: 0.5;
65
+ }
@@ -0,0 +1,51 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Table
3
+ // Clean data table with hover/striped modifiers; drop inside a .card for glass.
4
+ // =============================================================================
5
+
6
+ @use 'sass:map';
7
+ @use '../abstracts' as *;
8
+
9
+ .table {
10
+ width: 100%;
11
+ border-collapse: collapse;
12
+ color: var(--fv-body-color);
13
+
14
+ th,
15
+ td {
16
+ padding: spacer(3) spacer(4);
17
+ text-align: left;
18
+ vertical-align: middle;
19
+ border-bottom: $border-width solid var(--fv-border-color);
20
+ }
21
+
22
+ thead th {
23
+ font-size: map.get($font-sizes, 'sm');
24
+ font-weight: map.get($font-weights, 'semibold');
25
+ color: var(--fv-muted);
26
+ text-transform: uppercase;
27
+ letter-spacing: 0.04em;
28
+ }
29
+
30
+ tbody tr {
31
+ transition: background-color $transition-base;
32
+ }
33
+
34
+ tbody tr:last-child td {
35
+ border-bottom: 0;
36
+ }
37
+ }
38
+
39
+ .table-hover tbody tr:hover {
40
+ background-color: var(--fv-glass-bg);
41
+ }
42
+
43
+ .table-striped tbody tr:nth-child(odd) {
44
+ background-color: var(--fv-glass-bg);
45
+ }
46
+
47
+ // Horizontal scroll wrapper for narrow viewports.
48
+ .table-responsive {
49
+ overflow-x: auto;
50
+ -webkit-overflow-scrolling: touch;
51
+ }
@@ -0,0 +1,64 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Tabs (segmented)
3
+ // JS-driven: .tab buttons carry data-fv-tab="#panelId"; farvist.js toggles
4
+ // the .active class on the clicked tab and its panel.
5
+ // =============================================================================
6
+
7
+ @use 'sass:map';
8
+ @use '../abstracts' as *;
9
+
10
+ .tabs {
11
+ display: inline-flex;
12
+ flex-wrap: wrap;
13
+ gap: spacer(1);
14
+ padding: spacer(1);
15
+ margin-bottom: spacer(4);
16
+ background-color: var(--fv-glass-bg);
17
+ border: $border-width solid var(--fv-glass-border);
18
+ border-radius: map.get($radii, 'lg');
19
+ }
20
+
21
+ .tab {
22
+ padding: spacer(2) spacer(4);
23
+ font-size: map.get($font-sizes, 'base');
24
+ font-weight: map.get($font-weights, 'medium');
25
+ color: var(--fv-muted);
26
+ background: transparent;
27
+ border: 0;
28
+ border-radius: map.get($radii, 'md');
29
+ cursor: pointer;
30
+ transition: color $transition-base, background-color $transition-base;
31
+
32
+ &:hover {
33
+ color: var(--fv-body-color);
34
+ }
35
+
36
+ &:focus-visible {
37
+ outline: 0;
38
+ box-shadow: var(--fv-focus-ring);
39
+ }
40
+
41
+ &.active {
42
+ color: var(--fv-body-color);
43
+ background-color: var(--fv-glass-bg-strong);
44
+ box-shadow: var(--fv-shadow-sm);
45
+ }
46
+ }
47
+
48
+ .tab-panel {
49
+ display: none;
50
+
51
+ &.active {
52
+ display: block;
53
+ animation: fv-fade-in 0.25s ease;
54
+ }
55
+ }
56
+
57
+ @keyframes fv-fade-in {
58
+ from { opacity: 0; transform: translateY(0.4rem); }
59
+ to { opacity: 1; transform: none; }
60
+ }
61
+
62
+ @media (prefers-reduced-motion: reduce) {
63
+ .tab-panel.active { animation: none; }
64
+ }
@@ -0,0 +1,77 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Timeline
3
+ // <ul class="timeline">
4
+ // <li class="timeline-item timeline-success">
5
+ // <div class="timeline-marker"></div>
6
+ // <div class="timeline-content">
7
+ // <div class="timeline-title">Deployed</div>
8
+ // <div class="timeline-time">2 min ago</div>
9
+ // </div>
10
+ // </li>
11
+ // </ul>
12
+ // =============================================================================
13
+
14
+ @use 'sass:map';
15
+ @use '../abstracts' as *;
16
+
17
+ .timeline {
18
+ padding: 0;
19
+ margin: 0;
20
+ list-style: none;
21
+ }
22
+
23
+ .timeline-item {
24
+ display: flex;
25
+ gap: spacer(4);
26
+ }
27
+
28
+ .timeline-marker {
29
+ flex: 0 0 auto;
30
+ display: flex;
31
+ flex-direction: column;
32
+ align-items: center;
33
+ }
34
+
35
+ .timeline-marker::before {
36
+ content: '';
37
+ flex: 0 0 auto;
38
+ width: 0.9rem;
39
+ height: 0.9rem;
40
+ margin-top: 0.3rem;
41
+ background-color: var(--fv-primary);
42
+ border: 2px solid var(--fv-body-bg);
43
+ border-radius: 50%;
44
+ box-shadow: 0 0 0 1px var(--fv-glass-border);
45
+ }
46
+
47
+ .timeline-marker::after {
48
+ content: '';
49
+ flex: 1 1 auto;
50
+ width: 2px;
51
+ margin-top: 0.25rem;
52
+ background-color: var(--fv-glass-border);
53
+ }
54
+
55
+ .timeline-item:last-child .timeline-marker::after {
56
+ display: none;
57
+ }
58
+
59
+ .timeline-content {
60
+ padding-bottom: spacer(5);
61
+ }
62
+
63
+ .timeline-title {
64
+ font-weight: map.get($font-weights, 'semibold');
65
+ }
66
+
67
+ .timeline-time {
68
+ font-size: map.get($font-sizes, 'sm');
69
+ color: var(--fv-muted);
70
+ }
71
+
72
+ // Per-item dot colors.
73
+ @each $name, $clr in $theme-colors {
74
+ .timeline-#{$name} .timeline-marker::before {
75
+ background-color: $clr;
76
+ }
77
+ }
@@ -0,0 +1,79 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Toast
3
+ // Spawn with farvist.js: Farvist.toast({ title, message, variant }).
4
+ // =============================================================================
5
+
6
+ @use 'sass:map';
7
+ @use '../abstracts' as *;
8
+
9
+ .toast-container {
10
+ position: fixed;
11
+ top: spacer(5);
12
+ right: spacer(5);
13
+ z-index: map.get($z-layers, 'tooltip');
14
+ display: flex;
15
+ flex-direction: column;
16
+ gap: spacer(2);
17
+ width: min(22rem, calc(100vw - #{spacer(6)}));
18
+ }
19
+
20
+ .toast {
21
+ display: flex;
22
+ align-items: flex-start;
23
+ gap: spacer(3);
24
+ padding: spacer(3) spacer(4);
25
+ border-radius: map.get($radii, 'lg');
26
+ border-left: 3px solid var(--fv-primary);
27
+ @include glass($strong: true);
28
+ box-shadow: var(--fv-shadow-xl);
29
+ animation: fv-toast-in 0.3s ease;
30
+ }
31
+
32
+ .toast-body {
33
+ flex: 1 1 auto;
34
+ min-width: 0;
35
+ }
36
+
37
+ .toast-title {
38
+ font-weight: map.get($font-weights, 'semibold');
39
+ }
40
+
41
+ .toast-message {
42
+ font-size: map.get($font-sizes, 'sm');
43
+ color: var(--fv-muted);
44
+ }
45
+
46
+ .toast-close {
47
+ flex-shrink: 0;
48
+ padding: 0;
49
+ font-size: 1.2rem;
50
+ line-height: 1;
51
+ color: var(--fv-muted);
52
+ background: transparent;
53
+ border: 0;
54
+ cursor: pointer;
55
+
56
+ &:hover { color: var(--fv-body-color); }
57
+ }
58
+
59
+ // Colored left accent per variant.
60
+ @each $name, $clr in $theme-colors {
61
+ .toast-#{$name} { border-left-color: $clr; }
62
+ }
63
+
64
+ .toast.is-leaving {
65
+ animation: fv-toast-out 0.25s ease forwards;
66
+ }
67
+
68
+ @keyframes fv-toast-in {
69
+ from { opacity: 0; transform: translateX(1rem); }
70
+ to { opacity: 1; transform: none; }
71
+ }
72
+
73
+ @keyframes fv-toast-out {
74
+ to { opacity: 0; transform: translateX(1rem); }
75
+ }
76
+
77
+ @media (prefers-reduced-motion: reduce) {
78
+ .toast { animation: none; }
79
+ }
@@ -0,0 +1,45 @@
1
+ // =============================================================================
2
+ // Farvist · Components · Tooltip (CSS-only)
3
+ // Add `data-tooltip="text"` to any element. Appears above on hover/focus.
4
+ //
5
+ // ACCESSIBILITY: the tooltip text is rendered with `content: attr()`, which is
6
+ // DECORATIVE — it is not exposed to assistive tech. The host must therefore be
7
+ // focusable AND carry its own accessible name. For an icon-only control, give it
8
+ // a real label, e.g. `<button aria-label="Notifications" data-tooltip="Notifications">`.
9
+ // =============================================================================
10
+
11
+ @use 'sass:map';
12
+ @use '../abstracts' as *;
13
+
14
+ [data-tooltip] {
15
+ position: relative;
16
+ }
17
+
18
+ [data-tooltip]::after {
19
+ content: attr(data-tooltip);
20
+ position: absolute;
21
+ left: 50%;
22
+ bottom: calc(100% + 0.5rem);
23
+ z-index: map.get($z-layers, 'tooltip');
24
+ padding: spacer(1) spacer(3);
25
+ font-size: map.get($font-sizes, 'sm');
26
+ font-weight: map.get($font-weights, 'medium');
27
+ white-space: nowrap;
28
+ color: var(--fv-body-color);
29
+ background-color: var(--fv-glass-bg-strong);
30
+ backdrop-filter: blur(var(--fv-glass-blur)) saturate(var(--fv-glass-saturate));
31
+ -webkit-backdrop-filter: blur(var(--fv-glass-blur)) saturate(var(--fv-glass-saturate));
32
+ border: $border-width solid var(--fv-glass-border);
33
+ border-radius: map.get($radii, 'md');
34
+ box-shadow: var(--fv-shadow-lg);
35
+ opacity: 0;
36
+ pointer-events: none;
37
+ transform: translateX(-50%) translateY(0.25rem);
38
+ transition: opacity $transition-base, transform $transition-base;
39
+ }
40
+
41
+ [data-tooltip]:hover::after,
42
+ [data-tooltip]:focus-visible::after {
43
+ opacity: 1;
44
+ transform: translateX(-50%) translateY(0);
45
+ }
@@ -0,0 +1,60 @@
1
+ // =============================================================================
2
+ // Farvist — a lightweight, Sass-powered CSS framework
3
+ // -----------------------------------------------------------------------------
4
+ // Single entry point. Layers are loaded low-specificity first so that utilities
5
+ // (loaded last) can always win the cascade.
6
+ //
7
+ // Base → resets and element defaults
8
+ // Layout → container and grid system
9
+ // Components → buttons, cards, forms, …
10
+ // Utilities → generated single-purpose helpers
11
+ //
12
+ // Build: npm run dev (writes dist/farvist.css and dist/farvist.min.css)
13
+ // =============================================================================
14
+
15
+ // Base
16
+ @use 'base/root';
17
+ @use 'base/reset';
18
+ @use 'base/typography';
19
+
20
+ // Layout
21
+ @use 'layout/grid';
22
+
23
+ // Components
24
+ @use 'components/buttons';
25
+ @use 'components/badges';
26
+ @use 'components/alerts';
27
+ @use 'components/cards';
28
+ @use 'components/forms';
29
+ @use 'components/navbar';
30
+ @use 'components/icon';
31
+ @use 'components/table';
32
+ @use 'components/avatar';
33
+ @use 'components/chip';
34
+ @use 'components/progress';
35
+ @use 'components/spinner';
36
+ @use 'components/skeleton';
37
+ @use 'components/breadcrumb';
38
+ @use 'components/pagination';
39
+ @use 'components/tooltip';
40
+ @use 'components/switch';
41
+ @use 'components/tabs';
42
+ @use 'components/accordion';
43
+ @use 'components/dropdown';
44
+ @use 'components/modal';
45
+ @use 'components/toast';
46
+ @use 'components/stepper';
47
+ @use 'components/timeline';
48
+ @use 'components/segmented';
49
+ @use 'components/rating';
50
+ @use 'components/stat';
51
+ @use 'components/empty-state';
52
+ @use 'components/list-group';
53
+ @use 'components/callout';
54
+ @use 'components/range';
55
+
56
+ // Utilities (last — highest cascade priority)
57
+ @use 'utilities/spacing';
58
+ @use 'utilities/utilities';
59
+ @use 'utilities/effects';
60
+ @use 'utilities/backgrounds';
@@ -0,0 +1,83 @@
1
+ // =============================================================================
2
+ // Farvist · Layout · Container & flexbox grid
3
+ // A 12-column flexbox grid. The column and offset classes are generated with a
4
+ // nested `@for` (columns) inside an `@each` (breakpoints) loop.
5
+ // =============================================================================
6
+
7
+ @use 'sass:map';
8
+ @use 'sass:math';
9
+ @use '../abstracts' as *;
10
+
11
+ // -- Containers ---------------------------------------------------------------
12
+ .container,
13
+ .container-fluid {
14
+ width: 100%;
15
+ margin-inline: auto;
16
+ padding-inline: math.div($grid-gutter, 2);
17
+ }
18
+
19
+ // A fixed `.container` steps up to each breakpoint's max-width.
20
+ @each $name, $width in $container-max-widths {
21
+ @include media-up($name) {
22
+ .container {
23
+ max-width: $width;
24
+ }
25
+ }
26
+ }
27
+
28
+ // -- Row ----------------------------------------------------------------------
29
+ // Negative inline margin cancels the columns' gutter padding so edges align.
30
+ .row {
31
+ display: flex;
32
+ flex-wrap: wrap;
33
+ margin-inline: math.div(-$grid-gutter, 2);
34
+
35
+ > * {
36
+ width: 100%;
37
+ max-width: 100%;
38
+ padding-inline: math.div($grid-gutter, 2);
39
+ }
40
+ }
41
+
42
+ // -- Auto / equal-width columns ----------------------------------------------
43
+ .col {
44
+ flex: 1 0 0%;
45
+ }
46
+
47
+ .col-auto {
48
+ flex: 0 0 auto;
49
+ width: auto;
50
+ }
51
+
52
+ // -- Generated fixed-width columns & offsets ---------------------------------
53
+ @each $bp in map.keys($grid-breakpoints) {
54
+ $infix: breakpoint-infix($bp);
55
+
56
+ @include media-up($bp) {
57
+ // .col-6, .col-md-4, ... built with a @for loop over the column count.
58
+ @for $i from 1 through $grid-columns {
59
+ .col#{$infix}-#{$i} {
60
+ flex: 0 0 auto;
61
+ width: math.percentage(math.div($i, $grid-columns));
62
+ }
63
+ }
64
+
65
+ // .offset-3, .offset-lg-2, ... push a column to the right.
66
+ @for $i from 0 through $grid-columns - 1 {
67
+ $offset: 0;
68
+ @if $i != 0 {
69
+ $offset: math.percentage(math.div($i, $grid-columns));
70
+ }
71
+ .offset#{$infix}-#{$i} {
72
+ margin-left: $offset;
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ // -- Gutter utilities (gap-based, opt-in) ------------------------------------
79
+ @each $key, $value in $spacers {
80
+ .g-#{$key} { gap: $value; }
81
+ .gx-#{$key} { column-gap: $value; }
82
+ .gy-#{$key} { row-gap: $value; }
83
+ }