@use "sass:list"; .debug { border: 1px solid red !important; } // Font size loops @for $i from 10 through 50 { .fs-#{$i} { font-size: $i + px; } .fsb-#{$i} { font-size: $i + px; font-weight: bold; } } .font-thin { font-weight: 100; } .font-extralight { font-weight: 200; } .font-light { font-weight: 300; } .font-normal { font-weight: 400; } .font-medium { font-weight: 500; } .font-semibold { font-weight: 600; } .font-bold { font-weight: 700; } .font-extrabold { font-weight: 800; } .font-black { font-weight: 900; } .rounded-xs { border-radius: 0.125rem; } .rounded-sm { border-radius: 0.25rem; } .rounded { border-radius: 0.25rem; } .rounded-md { border-radius: 0.375rem; } .rounded-lg { border-radius: 0.5rem; } .rounded-xl { border-radius: 0.75rem; } .rounded-2xl { border-radius: 1rem; } .rounded-3xl { border-radius: 1.5rem; } .rounded-4xl { border-radius: 2rem; } .rounded-none { border-radius: 0; } .rounded-full { border-radius: calc(infinity * 1px); } .static { position: static; } .fixed { position: fixed; } .absolute { position: absolute; } .relative { position: relative; } .sticky { position: sticky; } // ─── CSS custom properties ───────────────────────────────────────────────── :root { --spacing: 0.25rem; --container-3xs: 16rem; --container-2xs: 18rem; --container-xs: 20rem; --container-sm: 24rem; --container-md: 28rem; --container-lg: 32rem; --container-xl: 36rem; --container-2xl: 42rem; --container-3xl: 48rem; --container-4xl: 56rem; --container-5xl: 64rem; --container-6xl: 72rem; --container-7xl: 80rem; } // ─── Shared mixin ────────────────────────────────────────────────────────── @mixin set-props($props, $value) { @each $prop in $props { #{$prop}: $value; } } // ─── Class types ─────────────────────────────────────────────────────────── $class-types: ( "w": ( width, ), "h": ( height, ), "size": ( width, height, ), ); // ─── Numeric: w-0 → w-96, h-0 → h-96, size-0 → size-96 ─────────────────── @each $prefix, $props in $class-types { @for $i from 0 through 96 { .#{$prefix}-#{$i} { @include set-props($props, calc(var(--spacing) * #{$i})); } } } // ─── Fractions ───────────────────────────────────────────────────────────── $fractions: ( "1\\/2": ( 1, 2, ), "1\\/3": ( 1, 3, ), "2\\/3": ( 2, 3, ), "1\\/4": ( 1, 4, ), "2\\/4": ( 2, 4, ), "3\\/4": ( 3, 4, ), "1\\/5": ( 1, 5, ), "2\\/5": ( 2, 5, ), "3\\/5": ( 3, 5, ), "4\\/5": ( 4, 5, ), "1\\/6": ( 1, 6, ), "2\\/6": ( 2, 6, ), "3\\/6": ( 3, 6, ), "4\\/6": ( 4, 6, ), "5\\/6": ( 5, 6, ), "1\\/12": ( 1, 12, ), "2\\/12": ( 2, 12, ), "3\\/12": ( 3, 12, ), "4\\/12": ( 4, 12, ), "5\\/12": ( 5, 12, ), "6\\/12": ( 6, 12, ), "7\\/12": ( 7, 12, ), "8\\/12": ( 8, 12, ), "9\\/12": ( 9, 12, ), "10\\/12": ( 10, 12, ), "11\\/12": ( 11, 12, ), ); @each $prefix, $props in $class-types { @each $name, $pair in $fractions { $num: list.nth($pair, 1); $den: list.nth($pair, 2); .#{$prefix}-#{$name} { @include set-props($props, calc(#{$num} / #{$den} * 100%)); } } } // ─── Container sizes (w- only) ───────────────────────────────────────────── $containers: ("3xs", "2xs", "xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl", "7xl"); @each $name in $containers { .w-#{$name} { width: var(--container-#{$name}); } } // ─── Shared keywords (auto, px, full, min, max, fit) ─────────────────────── $shared-keywords: ( "auto": auto, "px": 1px, "full": 100%, "min": min-content, "max": max-content, "fit": fit-content, ); @each $prefix, $props in $class-types { @each $name, $value in $shared-keywords { .#{$prefix}-#{$name} { @include set-props($props, $value); } } } // ─── Viewport keywords ───────────────────────────────────────────────────── $viewport-keywords: ( "dvw": 100dvw, "dvh": 100dvh, "lvw": 100lvw, "lvh": 100lvh, "svw": 100svw, "svh": 100svh, ); @each $prefix, $props in $class-types { @each $name, $value in $viewport-keywords { .#{$prefix}-#{$name} { @include set-props($props, $value); } } } .w-screen { width: 100vw; } .h-screen { height: 100vh; } // ─── Inset / positional offset classes ──────────────────────────────────── $inset-types: ( "inset": ( top, right, bottom, left, ), "inset-x": ( left, right, ), "inset-y": ( top, bottom, ), "top": ( top, ), "right": ( right, ), "bottom": ( bottom, ), "left": ( left, ), ); // ─── Numeric: 0 → 96, using the same --spacing scale ────────────────────── @each $prefix, $props in $inset-types { @for $i from 0 through 96 { .#{$prefix}-#{$i} { @include set-props($props, calc(var(--spacing) * #{$i})); } } } // ─── Fractions ───────────────────────────────────────────────────────────── @each $prefix, $props in $inset-types { @each $name, $pair in $fractions { $num: list.nth($pair, 1); $den: list.nth($pair, 2); .#{$prefix}-#{$name} { @include set-props($props, calc(#{$num} / #{$den} * 100%)); } } } // ─── Keywords ────────────────────────────────────────────────────────────── $inset-keywords: ( "auto": auto, "px": 1px, "full": 100%, ); @each $prefix, $props in $inset-types { @each $name, $value in $inset-keywords { .#{$prefix}-#{$name} { @include set-props($props, $value); } } } // ─── Max/Min width & height ──────────────────────────────────────────────── $minmax-types: ( "max-w": ( max-width, ), "min-w": ( min-width, ), "max-h": ( max-height, ), "min-h": ( min-height, ), ); // ─── Numeric: 0 → 96, using --spacing scale ─────────────────────────────── @each $prefix, $props in $minmax-types { @for $i from 0 through 96 { .#{$prefix}-#{$i} { @include set-props($props, calc(var(--spacing) * #{$i})); } } } // ─── Fractions ───────────────────────────────────────────────────────────── @each $prefix, $props in $minmax-types { @each $name, $pair in $fractions { $num: list.nth($pair, 1); $den: list.nth($pair, 2); .#{$prefix}-#{$name} { @include set-props($props, calc(#{$num} / #{$den} * 100%)); } } } // ─── Shared keywords ─────────────────────────────────────────────────────── @each $prefix, $props in $minmax-types { @each $name, $value in $shared-keywords { .#{$prefix}-#{$name} { @include set-props($props, $value); } } } // ─── Viewport keywords ───────────────────────────────────────────────────── @each $prefix, $props in $minmax-types { @each $name, $value in $viewport-keywords { .#{$prefix}-#{$name} { @include set-props($props, $value); } } } // ─── Container sizes (max-w- / min-w- only) ─────────────────────────────── @each $name in $containers { .max-w-#{$name} { max-width: var(--container-#{$name}); } .min-w-#{$name} { min-width: var(--container-#{$name}); } } // ─── Screen ──────────────────────────────────────────────────────────────── .max-w-screen { max-width: 100vw; } .min-w-screen { min-width: 100vw; } .max-h-screen { max-height: 100vh; } .min-h-screen { min-height: 100vh; } // ─── none (max only) ─────────────────────────────────────────────────────── .max-w-none { max-width: none; } .max-h-none { max-height: none; } // ─── Opacity ─────────────────────────────────────────────────────────────── $opacity-values: (0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100); @each $val in $opacity-values { .opacity-#{$val} { opacity: calc($val / 100); } }