/**
CSS Extras - A collection of useful CSS custom functions

@author Sindre Sorhus
@license (MIT OR CC0-1.0)
*/

/* ===================================
	 Math & Number Functions
	 =================================== */

/**
Negates a value (returns the negative).

@param {Number} --value - The value to negate.
@returns {Number} The negated value.
@example padding: --negate(1em);
*/
@function --negate(--value) {
	result: calc(-1 * var(--value));
}

/**
Returns the absolute value of a number.

@param {Number} --value - The input value.
@returns {Number} The absolute value.
@example margin: --abs(-20px);
*/
@function --abs(--value) {
	result: max(var(--value), calc(-1 * var(--value)));
}

/**
Linear interpolation between two values.

@param {Number} --from - Start value.
@param {Number} --to - End value.
@param {Number} --progress - Progress between 0 and 1.
@returns {Number} Interpolated value.
@example width: --lerp(100px, 200px, 0.5);
*/
@function --lerp(--from, --to, --progress) {
	result: calc(var(--from) + (var(--to) - var(--from)) * var(--progress));
}

/**
Maps a value from one range to another.

@param {Number} --value - Input value.
@param {Number} --in-min - Input range minimum.
@param {Number} --in-max - Input range maximum.
@param {Number} --out-min - Output range minimum.
@param {Number} --out-max - Output range maximum.
@returns {Number} Mapped value.
@example font-size: --map-range(50vw, 320px, 1920px, 14px, 24px);
*/
@function --map-range(--value, --in-min, --in-max, --out-min, --out-max) {
	--progress: clamp(0, calc((var(--value) - var(--in-min)) / (var(--in-max) - var(--in-min))), 1);
	result: calc(var(--out-min) + (var(--out-max) - var(--out-min)) * var(--progress));
}

/**
Returns the ratio of two values. Supports values with different units, unlike regular division.

@param {CalcSum} --value - Input value.
@param {CalcSum} --to-value - Another input value.
@returns {Number} The ratio between two values.
@example scale: --ratio(16px, 1em);
*/
@function --ratio(--value, --to-value) {
	result: tan(atan2(var(--value), var(--to-value)));
}

/* ===================================
	 Color Functions
	 =================================== */

/**
Returns a semi-transparent version of any color.

@param {Color} --color - The base color.
@param {Number} --opacity - Opacity value (0-100% or 0-1).
@returns {Color} Color with opacity.
@example background: --opacity(blue, 50%);
*/
@function --opacity(--color, --opacity) {
	result: rgb(from var(--color) r g b / var(--opacity));
}

/**
Lightens a color by mixing with white.

Uses OKLAB color space for perceptually uniform mixing.

@param {Color} --color - The base color.
@param {Number} --amount - Amount to lighten (0-100%).
@returns {Color} Lightened color.
@example background: --tint(blue, 20%);
*/
@function --tint(--color, --amount: 10%) {
	result: color-mix(in oklab, var(--color), white var(--amount));
}

/**
Darkens a color by mixing with black.

Uses OKLAB color space for perceptually uniform mixing.

@param {Color} --color - The base color.
@param {Number} --amount - Amount to darken (0-100%).
@returns {Color} Darkened color.
@example background: --shade(blue, 20%);
*/
@function --shade(--color, --amount: 10%) {
	result: color-mix(in oklab, var(--color), black var(--amount));
}

/**
Adjusts color saturation.

Uses OKLCH color space for perceptually uniform chroma adjustment. Chroma is clamped to 0.4 for safe display.

@param {Color} --color - The base color.
@param {Number} --amount - Chroma multiplier.
@returns {Color} Adjusted color.
@example color: --saturate(red, 1.5);
*/
@function --saturate(--color, --amount: 1.2) {
	result: oklch(from var(--color) l clamp(0, calc(c * var(--amount)), 0.4) h);
}

/**
Adjusts color lightness.

Uses OKLCH color space for perceptually uniform lightness adjustment. Maintains chroma independently.

@param {Color} --color - The base color.
@param {Number} --amount - Lightness adjustment (-100% to 100%).
@returns {Color} Adjusted color.
@example background: --lighten(blue, 20%);
*/
@function --lighten(--color, --amount: 10%) {
	result: oklch(from var(--color) clamp(0, calc(l + var(--amount) / 100%), 1) c h);
}

/**
Rotates the hue of a color.

Uses OKLCH color space for perceptually uniform hue rotation.

@param {Color} --color - The base color.
@param {Angle} --degrees - Degrees to rotate hue.
@returns {Color} Color with rotated hue.
@example background: --rotate-hue(blue, 180deg);
*/
@function --rotate-hue(--color, --degrees: 30deg) {
	result: oklch(from var(--color) l c calc(h + var(--degrees)));
}

/**
Returns the complementary color.

Uses OKLCH color space for perceptually accurate complementary colors.

@param {Color} --color - The base color.
@returns {Color} Complementary color.
@example border-color: --complement(blue);
*/
@function --complement(--color) {
	result: oklch(from var(--color) l c calc(h + 180deg));
}

/**
Inverts a color.

@param {Color} --color - The color to invert.
@returns {Color} Inverted color.
@example background: --invert(white);
*/
@function --invert(--color) {
	result: rgb(from var(--color) calc(255 - r) calc(255 - g) calc(255 - b) / alpha);
}

/**
Creates a semi-transparent black.

@param {Number} --opacity - Opacity value (0-100% or 0-1).
@returns {Color} Semi-transparent black.
@example box-shadow: 0 2px 4px --black(20%);
*/
@function --black(--opacity: 50%) {
	result: rgb(0 0 0 / var(--opacity));
}

/**
Creates a semi-transparent white.

@param {Number} --opacity - Opacity value (0-100% or 0-1).
@returns {Color} Semi-transparent white.
@example background: --white(90%);
*/
@function --white(--opacity: 50%) {
	result: rgb(255 255 255 / var(--opacity));
}

/* ===================================
	 Typography Functions
	 =================================== */

/**
Creates fluid typography that scales with viewport.

NOTE: This function is mathematically equivalent to `--responsive-value()` but optimized for typography. Use this for `font-size`, `--responsive-value()` for other properties.

@param {Length} --min - Minimum font size.
@param {Length} --max - Maximum font size.
@param {Length} --min-viewport - Minimum viewport width.
@param {Length} --max-viewport - Maximum viewport width.
@returns {Length} Fluid font size.
@example font-size: --fluid-type(16px, 24px, 320px, 1280px);
*/
@function --fluid-type(--min, --max, --min-viewport: 320px, --max-viewport: 1280px) {
	--slope: calc((var(--max) - var(--min)) / (var(--max-viewport) - var(--min-viewport)));
	--intercept: calc(var(--min) - var(--slope) * var(--min-viewport));
	result: clamp(var(--min), calc(var(--intercept) + var(--slope) * 100vw), var(--max));
}

/**
Creates a modular scale value.

@param {Number} --base - Base size.
@param {Number} --ratio - Scale ratio (default: 1.25).
@param {Number} --step - Step in the scale.
@returns {Length} Scaled value.
@example font-size: --modular-scale(1rem, 1.25, 3);
*/
@function --modular-scale(--base: 1rem, --ratio: 1.25, --step: 0) {
	result: calc(var(--base) * pow(var(--ratio), var(--step)));
}

/**
Calculates line height as a length value based on font size.

Returns a length (e.g., 24px) rather than a unitless ratio. Use this when you need an absolute line height value.

@param {Length} --font-size - The font size.
@param {Number} --multiplier - Line height multiplier.
@returns {Length} Line height as a length.
@example line-height: --line-height-length(16px, 1.6);
*/
@function --line-height-length(--font-size, --multiplier: 1.5) {
	result: calc(var(--font-size) * var(--multiplier));
}

/**
Calculates line height as a unitless ratio.

Returns a number (e.g., 1.5) which is recommended for better inheritance in CSS.

@param {Length} --line-height - The desired line height as a length.
@param {Length} --font-size - The font size.
@returns {Number} Unitless line height ratio.
@example line-height: --line-height-ratio(24px, 16px);
*/
@function --line-height-ratio(--line-height, --font-size) {
	result: calc(var(--line-height) / var(--font-size));
}

/**
Creates unitless line height from font size (recommended for better inheritance).

NOTE: Only works correctly with pixel font sizes. For rem/em values, use `--line-height()` instead.

@param {Length} --font-size - Font size in pixels.
@param {Number} --multiplier - Line height multiplier.
@returns {Number} Unitless line height.
@example line-height: --line-height-unitless(16px, 1.5);
*/
@function --line-height-unitless(--font-size: 16px, --multiplier: 1.5) {
	result: calc(var(--font-size) * var(--multiplier) / 1px);
}

/* ===================================
	 Layout Functions
	 =================================== */

/**
Creates responsive sidebar layout columns.

@param {Length} --sidebar-width - Width of sidebar.
@param {Length} --content-min - Minimum width of content area.
@returns {Length} Grid template columns value.
@example grid-template-columns: --sidebar-layout(250px, 20ch);
*/
@function --sidebar-layout(--sidebar-width: 20ch, --content-min: 20ch) {
	result: minmax(var(--sidebar-width), 1fr) minmax(var(--content-min), 3fr);
}

/**
Conditional border radius that removes at viewport edges.

@param {Length} --radius - Border radius value.
@param {Length} --edge-dist - Distance from viewport edge.
@returns {Length} Computed border radius.
@example border-radius: --conditional-radius(1rem, 8px);
*/
@function --conditional-radius(--radius, --edge-dist: 4px) {
	/* Multiply by large number to amplify small differences, creating binary 0/radius effect */
	result: clamp(0px, ((100vw - var(--edge-dist)) - 100%) * 1e5, var(--radius));
}

/**
Creates a responsive value that scales between two sizes.

NOTE: This function is mathematically equivalent to `--fluid-type()` but uses a simpler lerp-based approach. Use this for spacing/sizing, `--fluid-type()`for typography.

@param {Length} --small - Minimum value.
@param {Length} --large - Maximum value.
@param {Length} --viewport-min - Minimum viewport width.
@param {Length} --viewport-max - Maximum viewport width.
@returns {Length} Responsive value.
@example padding: --responsive-value(1rem, 2rem, 320px, 1200px);
*/
@function --responsive-value(--small, --large, --viewport-min: 320px, --viewport-max: 1200px) {
	--progress: calc((100vw - var(--viewport-min)) / (var(--viewport-max) - var(--viewport-min)));
	--clamped-progress: clamp(0, var(--progress), 1);
	result: calc(var(--small) + (var(--large) - var(--small)) * var(--clamped-progress));
}

/**
Calculates height from aspect ratio and maximum constraints.

@param {Number} --ratio - Aspect ratio (e.g., 16/9).
@param {Length} --max-width - Maximum width.
@param {Length} --max-height - Maximum height.
@returns {Length} Computed height.
@example height: --aspect-height(16/9, 100vw, 100vh);
*/
@function --aspect-height(--ratio: 1, --max-width: 100%, --max-height: 100%) {
	--computed-height: calc(var(--max-width) / var(--ratio));
	result: min(var(--computed-height), var(--max-height));
}

/* ===================================
	 Spacing Functions
	 =================================== */

/**
Creates consistent spacing based on a scale.

Recommended range: 0-10. Higher values create exponentially larger spacing.

@param {Number} --level - Spacing level (0-10).
@param {Length} --base - Base spacing unit.
@returns {Length} Computed spacing.
@example margin: --spacing(3);
*/
@function --spacing(--level: 1, --base: 0.25rem) {
	result: calc(var(--base) * pow(2, var(--level)));
}

/**
Creates inset spacing for containers.

@param {Length} --padding - Base padding.
@param {Length} --max-width - Maximum container width.
@returns {Length} Responsive padding.
@example padding: --container-padding(2rem, 1200px);
*/
@function --container-padding(--padding: 1rem, --max-width: 1200px) {
	--available: calc(100vw - var(--max-width));
	--side-space: max(var(--padding), calc(var(--available) / 2));
	result: var(--side-space);
}

/* ===================================
	 Animation Functions
	 =================================== */

/**
Creates a simple easing curve value.

@param {Number} --progress - Animation progress (0-1).
@returns {Number} Eased value.
@example transform: translateY(--ease-out(var(--progress)));
*/
@function --ease-out(--progress) {
	--inverse: calc(1 - var(--progress));
	result: calc(1 - var(--inverse) * var(--inverse));
}

/**
Creates elastic easing.

@param {Number} --progress - Animation progress (0-1).
@param {Number} --amplitude - Amplitude of elasticity.
@returns {Number} Eased value.
@example transform: scale(--elastic-ease(var(--progress), 1.2));
*/
@function --elastic-ease(--progress, --amplitude: 1) {
	--p: calc(var(--progress) * 3.14159);
	result: calc(var(--amplitude) * sin(var(--p) * 10) * exp(calc(-5 * var(--progress))));
}

/* ===================================
	 Utility Functions
	 =================================== */

/**
Converts pixels to rem.

@param {Length} --pixels - Pixel value.
@param {Length} --base - Base font size.
@returns {Length} Rem value.
@example font-size: --px-to-rem(24px);
*/
@function --px-to-rem(--pixels, --base: 16px) {
	result: calc(var(--pixels) / var(--base) * 1rem);
}

/**
Converts rem to pixels.

@param {Length} --rems - Rem value.
@param {Length} --base - Base font size.
@returns {Length} Pixel value.
@example width: --rem-to-px(2rem);
*/
@function --rem-to-px(--rems, --base: 16px) {
	result: calc(var(--rems) / 1rem * var(--base));
}

/* ===================================
	 Grid Functions
	 =================================== */

/**
Creates responsive grid columns.

@param {Number} --min-width - Minimum column width.
@param {Number} --max-cols - Maximum number of columns.
@returns {Grid} Grid template columns value.
@example grid-template-columns: --auto-grid(250px, 4);
*/
@function --auto-grid(--min-width: 250px, --max-cols: 4) {
	result: repeat(
		auto-fit,
		minmax(max(var(--min-width), calc(100% / var(--max-cols))), 1fr)
	);
}

/**
Creates a CSS grid span value.

Ensures the span is an integer value.

@param {Number} --columns - Number of columns to span.
@param {Number} --total - Total columns in grid.
@returns {Span} Grid column span (rounded to integer).
@example grid-column: --grid-span(3, 12);
*/
@function --grid-span(--columns: 1, --total: 12) {
	result: span round(clamp(1, var(--columns), var(--total)));
}

/* ===================================
	 Filter Functions
	 =================================== */

/**
Creates a smooth shadow.

Generates 3 shadow layers. The spread-factor controls how distributed the shadows are.

@param {Color} --color - Shadow color.
@param {Length} --size - Shadow size.
@param {Number} --spread-factor - Controls shadow distribution (higher = tighter shadows).
@returns {Shadow} Layered box shadow.
@example box-shadow: --smooth-shadow(black, 20px, 3);
*/
@function --smooth-shadow(--color: rgb(0 0 0 / 0.2), --size: 12px, --spread-factor: 3) {
	--step: calc(var(--size) / var(--spread-factor));
	result:
		0 var(--step) calc(var(--step) * 2) rgb(from var(--color) r g b / 0.25),
		0 calc(var(--step) * 2) calc(var(--step) * 3) rgb(from var(--color) r g b / 0.18),
		0 calc(var(--step) * 3) calc(var(--step) * 4) rgb(from var(--color) r g b / 0.12);
}

/**
Creates a glow effect.

@param {Color} --color - Glow color.
@param {Length} --size - Glow size.
@param {Number} --intensity - Glow intensity (0-1).
@returns {Shadow} Glow shadow.
@example box-shadow: --glow(cyan, 10px, 0.5);
*/
@function --glow(--color: white, --size: 10px, --intensity: 0.5) {
	result: 0 0 var(--size) rgb(from var(--color) r g b / var(--intensity));
}

/* ===================================
	 Theme Functions
	 =================================== */

/**
Theme-aware value switcher for light/dark mode.

Uses CSS `if()` with color-scheme query. Requires `color-scheme: light dark` on `:root`.
Works with ANY value type (colors, lengths, etc.), not just colors.

> [!NOTE]
> CSS has a native [`light-dark()`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark) function for colors. The custom `--light-dark()` function is more powerful as it works with any value type, not just colors.

@param {Any} --light - Value for light mode.
@param {Any} --dark - Value for dark mode.
@returns {Any} Theme-appropriate value.
@example color: --light-dark(black, white);
@example background-image: --light-dark(url(light.svg), url(dark.svg));
@example padding: --light-dark(0.75rem, 1rem);
*/
@function --light-dark(--light, --dark) {
	result: if(color-scheme(dark): var(--dark); else: var(--light));
}

/**
Creates a theme-aware color with automatic adjustment.

Uses CSS `if()` with color-scheme query. Requires `color-scheme: light dark` on `:root`.

In light mode, mixes the base color with white (default 85% white).
In dark mode, mixes the base color with black (default 15% black).

@param {Color} --base - Base color.
@param {Number} --light-mix - Percentage of white to mix in light mode.
@param {Number} --dark-mix - Percentage of black to mix in dark mode.
@returns {Color} Theme-adjusted color.
@example background: --theme-color(blue, 80%, 20%);
*/
@function --theme-color(--base, --light-mix: 85%, --dark-mix: 15%) {
	--light-result: color-mix(in oklab, white var(--light-mix), var(--base));
	--dark-result: color-mix(in oklab, black var(--dark-mix), var(--base));
	result: if(color-scheme(dark): var(--dark-result); else: var(--light-result));
}
