@import 'variables'; @import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap'); /* ========================================================================== */ /* Reset + Base */ /* ========================================================================== */ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } html, body { height: 100%; } body { font-family: $font-family-base; font-size: map-get($font-sizes, base); line-height: map-get($line-heights, normal); color: map-get($colors, dark); background: map-get($colors, white); text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; } a { color: inherit; text-decoration: none; } img, svg, video, canvas { display: block; max-width: 100%; height: auto; } /* ========================================================================== */ /* Typography Utilities */ /* ========================================================================== */ @each $k, $v in $font-sizes { .text-#{$k} { font-size: $v; } } @each $k, $v in $font-weights { .fw-#{$k} { font-weight: $v; } } @each $k, $v in $line-heights { .lh-#{$k} { line-height: $v; } } .text-left { text-align: left; } .text-center { text-align: center; } .text-right { text-align: right; } .text-uppercase { text-transform: uppercase; } .text-lowercase { text-transform: lowercase; } .text-capitalize { text-transform: capitalize; } .text-underline { text-decoration: underline; } .text-line-through { text-decoration: line-through; } .text-no-decoration { text-decoration: none; } /* ========================================================================== */ /* Color Utilities */ /* ========================================================================== */ @each $name, $color in $colors { .text-#{$name} { color: $color !important; } .bg-#{$name} { background-color: $color !important; } .border-#{$name} { border-color: $color !important; } } /* ========================================================================== */ /* Spacing Utilities (Margin / Padding) */ /* ========================================================================== */ @each $k, $v in $space { .m-#{$k} { margin: $v !important; } .mt-#{$k} { margin-top: $v !important; } .mr-#{$k} { margin-right: $v !important; } .mb-#{$k} { margin-bottom: $v !important; } .ml-#{$k} { margin-left: $v !important; } .mx-#{$k} { margin-left: $v !important; margin-right: $v !important; } .my-#{$k} { margin-top: $v !important; margin-bottom: $v !important; } .p-#{$k} { padding: $v !important; } .pt-#{$k} { padding-top: $v !important; } .pr-#{$k} { padding-right: $v !important; } .pb-#{$k} { padding-bottom: $v !important; } .pl-#{$k} { padding-left: $v !important; } .px-#{$k} { padding-left: $v !important; padding-right: $v !important; } .py-#{$k} { padding-top: $v !important; padding-bottom: $v !important; } } /* Responsive spacing */ @each $bp, $w in $breakpoints { @media (min-width: $w) { @each $k, $v in $space { .#{$bp}-m-#{$k} { margin: $v !important; } .#{$bp}-mt-#{$k} { margin-top: $v !important; } .#{$bp}-mr-#{$k} { margin-right: $v !important; } .#{$bp}-mb-#{$k} { margin-bottom: $v !important; } .#{$bp}-ml-#{$k} { margin-left: $v !important; } .#{$bp}-mx-#{$k} { margin-left: $v !important; margin-right: $v !important; } .#{$bp}-my-#{$k} { margin-top: $v !important; margin-bottom: $v !important; } .#{$bp}-p-#{$k} { padding: $v !important; } .#{$bp}-pt-#{$k} { padding-top: $v !important; } .#{$bp}-pr-#{$k} { padding-right: $v !important; } .#{$bp}-pb-#{$k} { padding-bottom: $v !important; } .#{$bp}-pl-#{$k} { padding-left: $v !important; } .#{$bp}-px-#{$k} { padding-left: $v !important; padding-right: $v !important; } .#{$bp}-py-#{$k} { padding-top: $v !important; padding-bottom: $v !important; } } } } /* ========================================================================== */ /* Sizing Utilities (Width / Height) */ /* ========================================================================== */ @each $k, $v in $size-percent { .w-#{$k} { width: $v; } .h-#{$k} { height: $v; } } @each $k, $v in $size-px { .wpx-#{$k} { width: $v; } .hpx-#{$k} { height: $v; } } @each $k, $v in $size-rem { .wrem-#{$k} { width: $v; } .hrem-#{$k} { height: $v; } } @each $k, $v in $size-vw { .wvw-#{$k} { width: $v; } } @each $k, $v in $size-vh { .hvh-#{$k} { height: $v; } } @each $k, $v in $size-dvh { .hdvh-#{$k} { height: $v; } } @each $k, $v in $size-svh { .hsvh-#{$k} { height: $v; } } @each $k, $v in $size-lvh { .hlvh-#{$k} { height: $v; } } /* Responsive sizing */ @each $bp, $w in $breakpoints { @media (min-width: $w) { @each $k, $v in $size-percent { .#{$bp}-w-#{$k} { width: $v; } .#{$bp}-h-#{$k} { height: $v; } } } } /* ========================================================================== */ /* Display + Layout */ /* ========================================================================== */ @each $t in $display-types { .d-#{$t} { display: $t !important; } } .container { width: 100%; margin-inline: auto; padding-inline: $container-padding; @each $bp, $mw in $container-max-widths { @media (min-width: map-get($breakpoints, $bp)) { max-width: $mw; } } } /* Container variants */ .container-fluid { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: none; } .container-bleed { width: 100vw; margin-left: 50%; transform: translateX(-50%); padding-inline: 0; } .container-narrow { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: clamp(36rem, 70vw, 56rem); } .container-wide { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: clamp(72rem, 92vw, 100rem); } .container-fluid { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: none; } .container-bleed { width: 100vw; margin-left: 50%; transform: translateX(-50%); padding-inline: 0; } .container-narrow { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: clamp(36rem, 70vw, 56rem); } .container-wide { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: clamp(72rem, 92vw, 100rem); } .container-fluid { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: none; } .container-bleed { width: 100vw; margin-left: 50%; transform: translateX(-50%); padding-inline: 0; } .container-narrow { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: clamp(36rem, 70vw, 56rem); } .container-wide { width: 100%; margin-inline: auto; padding-inline: $container-padding; max-width: clamp(72rem, 92vw, 100rem); } /* Flex grid */ .row { display: flex; flex-wrap: wrap; margin-inline: map-get($gutters, 3); margin-block: map-get($gutters, 3); } .col { flex: 1 0 0%; padding-inline: map-get($gutters, 3); padding-block: map-get($gutters, 3); } .col-auto { flex: 0 0 auto; width: auto; padding-inline: map-get($gutters, 3); padding-block: map-get($gutters, 3); } @for $i from 1 through $grid-columns { .col-#{$i} { flex: 0 0 percentage($i / $grid-columns); max-width: percentage($i / $grid-columns); padding-inline: map-get($gutters, 3); padding-block: map-get($gutters, 3); } } @each $bp, $w in $breakpoints { @media (min-width: $w) { .col-#{$bp} { flex: 1 0 0%; padding-inline: map-get($gutters, 3); padding-block: map-get($gutters, 3); } .col-#{$bp}-auto { flex: 0 0 auto; width: auto; padding-inline: map-get($gutters, 3); padding-block: map-get($gutters, 3); } @for $i from 1 through $grid-columns { .col-#{$bp}-#{$i} { flex: 0 0 percentage($i / $grid-columns); max-width: percentage($i / $grid-columns); padding-inline: map-get($gutters, 3); padding-block: map-get($gutters, 3); } } } } /* Flex helpers */ .flex { display: flex; } .inline-flex { display: inline-flex; } @each $k, $v in $flex-directions { .flex-#{$k} { display: flex; flex-direction: $v; } } @each $k, $v in $justify-content-values { .justify-#{$k} { display: flex; justify-content: $v; } } @each $k, $v in $align-items-values { .items-#{$k} { display: flex; align-items: $v; } } /* Borders + Radius + Shadows */ @each $k, $v in $border-widths { .border-#{$k} { border-width: $v; border-style: solid; border-color: currentColor; } } .border { border: 1px solid currentColor; } .border-top { border-top: 1px solid currentColor; } .border-right { border-right: 1px solid currentColor; } .border-bottom { border-bottom: 1px solid currentColor; } .border-left { border-left: 1px solid currentColor; } @each $k, $v in $radii { .rounded-#{$k} { border-radius: $v; } } .rounded { border-radius: map-get($radii, md); } .rounded-top { border-top-left-radius: map-get($radii, md); border-top-right-radius: map-get($radii, md); } .rounded-bottom { border-bottom-left-radius: map-get($radii, md); border-bottom-right-radius: map-get($radii, md); } .rounded-left { border-top-left-radius: map-get($radii, md); border-bottom-left-radius: map-get($radii, md); } .rounded-right { border-top-right-radius: map-get($radii, md); border-bottom-right-radius: map-get($radii, md); } @each $k, $v in $shadows { .shadow-#{$k} { box-shadow: $v !important; } } @each $k, $v in $drop-shadows { .drop-shadow-#{$k} { box-shadow: $v !important; } } /* Z-Index */ .z-base { z-index: map-get($z, base); } .z-dropdown { z-index: map-get($z, dropdown); } .z-overlay { z-index: map-get($z, overlay); } .z-modal { z-index: map-get($z, modal); } .z-toast { z-index: map-get($z, toast); } /* ========================================================================== */ /* Grid System (CSS Grid Utilities) */ /* ========================================================================== */ .grid { display: grid !important; } .inline-grid { display: inline-grid !important; } @for $i from 1 through 12 { .grid-cols-#{$i} { grid-template-columns: repeat($i, 1fr) !important; } } .grid-cols-none { grid-template-columns: none !important; } @each $bp, $width in $breakpoints { @media (min-width: $width) { @for $i from 1 through 12 { .#{$bp}-grid-cols-#{$i} { grid-template-columns: repeat($i, 1fr) !important; } } } } @for $i from 1 through 12 { .grid-rows-#{$i} { grid-template-rows: repeat($i, 1fr) !important; } } .grid-rows-none { grid-template-rows: none !important; } .grid-auto-fit-sm { grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)) !important; } .grid-auto-fit-md { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)) !important; } .grid-auto-fit-lg { grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)) !important; } .grid-auto-fill-sm { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)) !important; } .grid-auto-fill-md { grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)) !important; } .grid-auto-fill-lg { grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)) !important; } .grid-align-center { align-items: center !important; justify-items: center !important; } .grid-align-start { align-items: start !important; justify-items: start !important; } .grid-align-end { align-items: end !important; justify-items: end !important; } .grid-align-stretch { align-items: stretch !important; justify-items: stretch !important; } .place-self-center { place-self: center !important; } .place-self-start { place-self: start !important; } .place-self-end { place-self: end !important; } .place-self-stretch { place-self: stretch !important; } .grid-flow-row { grid-auto-flow: row !important; } .grid-flow-col { grid-auto-flow: column !important; } .grid-flow-row-dense { grid-auto-flow: row dense !important; } .grid-flow-col-dense { grid-auto-flow: column dense !important; } /* Auto rows/cols sizing */ .grid-auto-cols-min { grid-auto-columns: min-content !important; } .grid-auto-cols-max { grid-auto-columns: max-content !important; } .grid-auto-cols-fr { grid-auto-columns: 1fr !important; } .grid-auto-rows-min { grid-auto-rows: min-content !important; } .grid-auto-rows-max { grid-auto-rows: max-content !important; } .grid-auto-rows-fr { grid-auto-rows: 1fr !important; } /* ========================================================================== */ /* Control Blueprints (shared by inputs/buttons/etc.) */ /* ========================================================================== */ @mixin control-base { appearance: none; border-style: map-get($control-border, style); border-width: map-get($control-border, width); border-color: map-get($control-colors, border); background-color: map-get($control-colors, bg); color: map-get($control-colors, fg); outline: 0; transition: background-color map-get($timings, base) map-get($easings, in-out), color map-get($timings, base) map-get($easings, in-out), border-color map-get($timings, base) map-get($easings, in-out), box-shadow map-get($timings, base) map-get($easings, in-out), transform map-get($timings, fast) map-get($easings, out); } @mixin control-size($size) { $props: map-get($control-sizes, $size); font-size: map-get($props, font-size); line-height: map-get($props, line-height); padding: map-get($props, py) map-get($props, px); border-radius: map-get($props, radius); } /* Inputs */ .input, select, textarea { @include control-base; width: 100%; &:focus { border-color: map-get($control-colors, focus); box-shadow: 0 0 0 3px map-get($control-colors, ring); background-color: map-get($colors, white); } &:disabled { background-color: map-get($control-colors, disabled-bg); opacity: .6; cursor: not-allowed; } &::placeholder { color: map-get($control-colors, placeholder); } } @each $size, $props in $control-sizes { .input-#{$size} { @include control-size($size); } } /* Buttons */ .btn { @include control-base; display: inline-flex; width: auto; align-items: center; justify-content: center; cursor: pointer; user-select: none; box-shadow: map-get($shadows, 1); &:focus-visible { border-color: map-get($control-colors, focus); box-shadow: 0 0 0 3px map-get($control-colors, ring), map-get($shadows, 2); } &:active { transform: translateY(1px); box-shadow: map-get($shadows, 3); } &:disabled { opacity: .6; cursor: not-allowed; pointer-events: none; } } @each $size, $props in $control-sizes { .btn-#{$size} { @include control-size($size); } } @each $name, $color in $colors { .btn-#{$name} { background-color: $color; color: if(lightness($color) > 60%, map-get($colors, dark), map-get($colors, white)); border-color: transparent; &:hover { background-color: darken($color, 8%); box-shadow: map-get($shadows, 2); } } .btn-outline-#{$name} { background-color: transparent; color: $color; border-color: $color; &:hover { background-color: $color; color: if(lightness($color) > 60%, map-get($colors, dark), map-get($colors, white)); } } .btn-ghost-#{$name} { background-color: transparent; color: $color; border-color: transparent; &:hover { background-color: rgba($color, .12); } } } /* ========================================================================== */ /* Alerts */ /* ========================================================================== */ .alert { padding: map-get($space, 2) map-get($space, 3); border-radius: map-get($radii, md); border: 1px solid map-get($control-colors, border); background: map-get($colors, accent-white); } @each $name, $color in $colors { .alert-#{$name} { background: mix($color, map-get($colors, white), 12%); border-color: $color; color: if(lightness($color) > 60%, map-get($colors, dark), map-get($colors, dark)); } } /* ========================================================================== */ /* Cards (with custom borders and shadows) */ /* ========================================================================== */ .card { background: map-get($colors, white); border: 1px solid map-get($control-colors, border); border-radius: map-get($radii, lg); box-shadow: map-get($shadows, 1); transition: box-shadow map-get($timings, base) map-get($easings, in-out); } .card-hover:hover { box-shadow: map-get($shadows, 3); } @each $k, $v in $shadows { .card-shadow-#{$k} { box-shadow: $v; } } @each $name, $color in $colors { .card-border-#{$name} { border-color: $color; } .card-bg-#{$name} { background-color: $color; } } /* ========================================================================== */ /* Modals */ /* ========================================================================== */ .modal { position: fixed; inset: 0; display: none; align-items: center; justify-content: center; padding: map-get($space, 3); z-index: map-get($z, modal); } .modal.open { display: flex; } .modal__overlay { position: absolute; inset: 0; background: rgba(map-get($colors, black), .5); } .modal__dialog { position: relative; width: min(720px, 100%); background: map-get($colors, white); border: 1px solid map-get($control-colors, border); border-radius: map-get($radii, lg); box-shadow: map-get($shadows, 5); padding: map-get($space, 3); } .modal__header { display: flex; align-items: center; justify-content: space-between; gap: map-get($space, 2); margin-bottom: map-get($space, 2); } .modal__title { font-size: map-get($font-sizes, lg); font-weight: map-get($font-weights, semibold); } .modal__close { @extend .btn; @extend .btn-sm; background: transparent; box-shadow: none; } /* ========================================================================== */ /* Pills */ /* ========================================================================== */ .pill { display: inline-flex; align-items: center; gap: map-get($space, 1); padding: map-get($space, 1) map-get($space, 2); border-radius: map-get($radii, full); border: 1px solid map-get($control-colors, border); background: map-get($colors, accent-white); font-size: map-get($font-sizes, sm); line-height: map-get($line-heights, normal); } @each $name, $color in $colors { .pill-#{$name} { background: mix($color, map-get($colors, white), 12%); color: if(lightness($color) > 60%, map-get($colors, dark), map-get($colors, white)); border-color: $color; } } /* ========================================================================== */ /* Accordions */ /* ========================================================================== */ .accordion { border: 1px solid map-get($control-colors, border); border-radius: map-get($radii, lg); overflow: hidden; } .accordion__item + .accordion__item { border-top: 1px solid map-get($control-colors, border); } .accordion__header { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: map-get($space, 2); padding: map-get($space, 2) map-get($space, 3); cursor: pointer; background: map-get($colors, accent-white); border: none; } .accordion__title { font-weight: map-get($font-weights, medium); } .accordion__icon { transition: transform map-get($timings, base) map-get($easings, in-out); } .accordion__panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows map-get($timings, base) map-get($easings, in-out); } .accordion__content { overflow: hidden; padding: 0 map-get($space, 3); } .accordion__item.is-open .accordion__panel { grid-template-rows: 1fr; } .accordion__item.is-open .accordion__content { padding: map-get($space, 2) map-get($space, 3) map-get($space, 3); } .accordion__item.is-open .accordion__icon { transform: rotate(180deg); } /* ========================================================================== */ /* Stack Utilities */ /* ========================================================================== */ .stack > * + * { margin-top: map-get($space, 3); } @each $k, $v in $space { .stack-#{$k} > * + * { margin-top: $v; } } /* ========================================================================== */ /* Transitions & Animations */ /* ========================================================================== */ .transition-all { transition: all map-get($timings, base) map-get($easings, in-out); } .transition-fast { transition-duration: map-get($timings, fast); } .transition-slow { transition-duration: map-get($timings, slow); } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes slide-up { from { transform: translateY(10px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .animate-fade-in { animation: fade-in .3s map-get($easings, out) both; } .animate-slide-up { animation: slide-up .35s map-get($easings, out) both; } /* ========================================================================== */ /* Tooltips */ /* ========================================================================== */ .tooltip { position: relative; display: inline-block; cursor: help; } .tooltip::after { content: attr(data-tip); position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); background: map-get($colors, dark); color: map-get($colors, white); padding: .25rem .5rem; font-size: map-get($font-sizes, sm); border-radius: map-get($radii, sm); white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity map-get($timings, base) map-get($easings, in-out); z-index: map-get($z, dropdown); } .tooltip:hover::after { opacity: 1; } /* ========================================================================== */ /* Tabs */ /* ========================================================================== */ .tabs { display: flex; gap: map-get($space, 2); border-bottom: 1px solid map-get($control-colors, border); } .tab { padding: map-get($space, 2) map-get($space, 3); cursor: pointer; border-bottom: 2px solid transparent; transition: border-color map-get($timings, base) map-get($easings, in-out), color map-get($timings, base) map-get($easings, in-out); } .tab.active { border-color: map-get($colors, primary); color: map-get($colors, primary); } /* ========================================================================== */ /* Transform & Scale Utilities */ /* ========================================================================== */ .scale-90 { transform: scale(.9); } .scale-95 { transform: scale(.95); } .scale-100 { transform: scale(1); } .scale-105 { transform: scale(1.05); } .scale-110 { transform: scale(1.1); } .rotate-90 { transform: rotate(90deg); } .rotate-180 { transform: rotate(180deg); } .rotate-270 { transform: rotate(270deg); } .skew-x-6 { transform: skewX(6deg); } .skew-y-6 { transform: skewY(6deg); } /* ========================================================================== */ /* Shadow, Blur, and Glow Utilities */ /* ========================================================================== */ .shadow-none { box-shadow: none !important; } .blur-sm { filter: blur(2px); } .blur-md { filter: blur(4px); } .blur-lg { filter: blur(8px); } .glow { box-shadow: 0 0 12px rgba(map-get($colors, accent), .5); } /* ========================================================================== */ /* Dark Mode (opt-in via .theme-dark) */ /* ========================================================================== */ .theme-dark { background: map-get($colors, dark); color: map-get($colors, light); } .theme-dark .card, .theme-dark .modal__dialog { background: map-get($colors, secondary); border-color: map-get($colors, muted); color: map-get($colors, light); } .theme-dark .input, .theme-dark select, .theme-dark textarea { background: map-get($colors, secondary); color: map-get($colors, light); border-color: map-get($colors, muted); } .theme-dark .tabs { border-bottom-color: map-get($colors, muted); } .theme-dark .tab.active { border-color: map-get($colors, primary); color: map-get($colors, primary); } /* ========================================================================== */ /* Scroll Utilities */ /* ========================================================================== */ .scroll-y { overflow-y: auto !important; } .scroll-x { overflow-x: auto !important; } .scroll-hidden { overflow: hidden !important; } /* ========================================================================== */ /* Spinner */ /* ========================================================================== */ @keyframes ui-spinner { to { transform: rotate(360deg); } } .spinner { display: inline-block; width: 1rem; height: 1rem; border-radius: 50%; border-style: solid; border-width: 2px; border-color: map-get($colors, dark); border-left-color: transparent !important; animation: ui-spinner 1s linear infinite; } @each $name, $color in $colors { .spinner-#{$name} { border-color: $color; border-left-color: transparent !important; } } .spinner-sm { width: .875rem; height: .875rem; border-width: 2px; } .spinner-md { width: 1.25rem; height: 1.25rem; border-width: 2px; } .spinner-lg { width: 1.75rem; height: 1.75rem; border-width: 3px; } .spinner-xl { width: 2.25rem; height: 2.25rem; border-width: 4px; } /* ========================================================================== */ /* Visibility + Accessibility */ /* ========================================================================== */ .visible { visibility: visible !important; } .invisible { visibility: hidden !important; } .sr-only { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0, 0, 0, 0) !important; white-space: nowrap !important; border: 0 !important; } /* ========================================================================== */ /* Overflow + Text Truncation */ /* ========================================================================== */ .overflow-hidden { overflow: hidden !important; } .overflow-auto { overflow: auto !important; } .overflow-scroll { overflow: scroll !important; } .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ========================================================================== */ /* Opacity */ /* ========================================================================== */ .opacity-0 { opacity: 0; } .opacity-25 { opacity: .25; } .opacity-50 { opacity: .5; } .opacity-75 { opacity: .75; } .opacity-100 { opacity: 1; } /* ========================================================================== */ /* Cursor + Pointer Events */ /* ========================================================================== */ .cursor-default { cursor: default !important; } .cursor-pointer { cursor: pointer !important; } .cursor-not-allowed { cursor: not-allowed !important; } .pointer-none { pointer-events: none !important; } .pointer-auto { pointer-events: auto !important; } /* ========================================================================== */ /* Position + Inset */ /* ========================================================================== */ .relative { position: relative !important; } .absolute { position: absolute !important; } .fixed { position: fixed !important; } .sticky { position: sticky !important; } .inset-0 { inset: 0 !important; } .top-0 { top: 0 !important; } .right-0 { right: 0 !important; } .bottom-0 { bottom: 0 !important; } .left-0 { left: 0 !important; } /* ========================================================================== */ /* Flex Wrapping + Gap */ /* ========================================================================== */ .wrap { flex-wrap: wrap !important; } .nowrap { flex-wrap: nowrap !important; } .wrap-reverse { flex-wrap: wrap-reverse !important; } @each $k, $v in $space { .gap-#{$k} { gap: $v !important; } .row-gap-#{$k} { row-gap: $v !important; } .col-gap-#{$k} { column-gap: $v !important; } } /* ========================================================================== */ /* Responsive Reverse (small-down) */ /* ========================================================================== */ .sm-reverse { @media (max-width: map-get($breakpoints, md)) { display: flex; flex-direction: column-reverse; } } /* ========================================================================== */ /* Aspect Ratios + Object Fit */ /* ========================================================================== */ .ratio { position: relative; width: 100%; height: 0; overflow: hidden; } .ratio > * { position: absolute; inset: 0; width: 100%; height: 100%; } .ratio-16x9 { padding-bottom: 56.25%; } .ratio-4x3 { padding-bottom: 75%; } .ratio-1x1 { padding-bottom: 100%; } .object-contain { object-fit: contain !important; } .object-cover { object-fit: cover !important; } .object-fill { object-fit: fill !important; } .object-none { object-fit: none !important; } .object-scale-down { object-fit: scale-down !important; } /* ========================================================================== */ /* Hover Motion Helpers */ /* ========================================================================== */ .hover-raise { transition: transform map-get($timings, base) map-get($easings, in-out), box-shadow map-get($timings, base) map-get($easings, in-out); } .hover-raise:hover { transform: translateY(-2px); box-shadow: map-get($shadows, 2); } .hover-glow { transition: box-shadow map-get($timings, base) map-get($easings, in-out); } .hover-glow:hover { box-shadow: 0 0 0 3px map-get($control-colors, ring), map-get($shadows, 2); } /* ========================================================================== */ /* Divider Utilities */ /* ========================================================================== */ .hr { width: 100%; height: 1px; background: map-get($control-colors, border); border: 0; } .hr-dashed { height: 1px; border-top: 1px dashed map-get($control-colors, border); background: transparent; } /* ========================================================================== */ /* Utility Badges (aliases of pills) */ /* ========================================================================== */ .badge { @extend .pill; } @each $name, $color in $colors { .badge-#{$name} { @extend .pill-#{$name}; } } /* ========================================================================== */ /* Quick Utility Aliases */ /* ========================================================================== */ .rel { position: relative; } .no-click { pointer-events: none; } .center { display: grid; place-items: center; } .full-height { height: 100vh; } /* ========================================================================== */ /* Flex Grid Extensions */ /* ========================================================================== */ .row.no-gutter { margin-inline: 0; margin-block: 0; > .col, > [class^="col-"] { padding-inline: 0; padding-block: 0; } } .row.gx-0 { margin-right: 0; margin-left: 0; > .col, > [class^="col-"] { padding-right: 0; padding-left: 0; } } .row.gy-0 { margin-top: 0; margin-bottom: 0; > .col, > [class^="col-"] { padding-top: 0; padding-bottom: 0; } } .row-bleed { margin-right: calc(#{$container-padding} * -1); margin-left: calc(#{$container-padding} * -1); } @each $bp, $width in $breakpoints { @media (min-width: $width) { .#{$bp}-row-center { justify-content: center; } .#{$bp}-row-between { justify-content: space-between; } .#{$bp}-row-around { justify-content: space-around; } .#{$bp}-row-evenly { justify-content: space-evenly; } } } /* ========================================================================== */ /* CSS Grid Enhancements */ /* ========================================================================== */ @for $i from 1 through 12 { .grid-cols-#{$i} { grid-template-columns: repeat($i, 1fr) !important; } } .grid-cols-none { grid-template-columns: none !important; } @for $i from 1 through 12 { .grid-rows-#{$i} { grid-template-rows: repeat($i, 1fr) !important; } } .grid-rows-none { grid-template-rows: none !important; } .grid-auto-fit-sm { grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)) !important; } .grid-auto-fit-md { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)) !important; } .grid-auto-fit-lg { grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)) !important; } .grid-auto-fill-sm { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)) !important; } .grid-auto-fill-md { grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)) !important; } .grid-auto-fill-lg { grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)) !important; } .grid-align-center { align-items: center !important; justify-items: center !important; } .grid-align-start { align-items: start !important; justify-items: start !important; } .grid-align-end { align-items: end !important; justify-items: end !important; } .grid-align-stretch { align-items: stretch !important; justify-items: stretch !important; } .grid-flow-row { grid-auto-flow: row !important; } .grid-flow-col { grid-auto-flow: column !important; } .grid-flow-row-dense { grid-auto-flow: row dense !important; } .grid-flow-col-dense { grid-auto-flow: column dense !important; }