// ============================================================
//  _variables.scss
//  Design tokens, color palettes and CSS custom-property
//  generators. This module is the single source of truth for the
//  framework palette and tokens.
//
//  All maps are flagged with !default: define your own value
//  before @use-ing this module to override them.
// ============================================================
@use "sass:map";
@use "sass:list";
@use "sass:meta";
@use "sass:color";

// ============================================
//  TOKEN MAPS
//  Sass maps that store the framework design tokens. Keys become
//  the class/custom-property suffixes (e.g. "sm" → --shadow-sm).
// ============================================

// Named font stacks: key = token name, value = CSS font-family list.
$font-families: (
  "sans-serif": (ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif),
  "serif": ("Times New Roman", Trebuchet, Geneva, serif),
  "mono": (monospace)
) !default;

// Box-shadow presets (Tailwind-style). Single values are plain
// shadows; lists combine multiple shadows separated by commas.
$shadow-sizes: (
  "default": (0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)),
  "sm": 0 1px 2px 0 rgb(0 0 0 / 0.05),
  "md": (0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)),
  "lg": (0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)),
  "xl": (0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)),
  "2xl": 0 25px 50px -12px rgb(0 0 0 / 0.25),
  "inner": inset 0 2px 4px 0 rgb(0 0 0 / 0.05)
) !default;

// Max-width presets for container-like components.
$container-sizes: (
  "sm": 24rem, "md": 28rem, "lg": 32rem, "xl": 36rem,
  "2xl": 42rem, "3xl": 48rem, "4xl": 56rem, "5xl": 64rem, "6xl": 72rem
) !default;

// Screen breakpoints (min-width values). Mirrored in _mixins.scss.
$breakpoint-sizes: (
  "xs": 0, "sm": 640px, "md": 768px, "lg": 1024px,
  "xl": 1280px, "2xl": 1536px, "3xl": 1920px
) !default;

// Classic spacing scale used for the --spacing-* custom properties.
$spacing-scale: (
  "0": 0, "1": 0.25rem, "2": 0.5rem, "3": 0.75rem, "4": 1rem,
  "5": 1.25rem, "6": 1.5rem, "8": 2rem, "10": 2.5rem, "12": 3rem,
  "16": 4rem, "20": 5rem, "24": 6rem, "32": 8rem
) !default;

// Full spacing scale — single source of truth for the .p-*/.m-*/.gap-*
// utility classes (_utilities.scss) and for the @apply registry
// (_mixins.scss). Fractions use kebab notation: p-05, p-1-5…
$spacing-map: (
  "0": 0, "05": 0.125rem, "base": 1px, "1": 0.25rem, "1-5": 0.375rem,
  "2": 0.5rem, "2-5": 0.625rem, "3": 0.75rem, "3-5": 0.875rem, "4": 1rem,
  "5": 1.25rem, "6": 1.5rem, "7": 1.75rem, "8": 2rem, "9": 2.25rem,
  "10": 2.5rem, "11": 2.75rem, "12": 3rem, "14": 3.5rem, "16": 4rem,
  "20": 5rem, "24": 6rem, "28": 7rem, "32": 8rem, "36": 9rem, "40": 10rem,
  "44": 11rem, "48": 12rem, "52": 13rem, "56": 14rem, "60": 15rem, "64": 16rem,
  "72": 18rem, "80": 20rem, "96": 24rem
) !default;

// Border-radius presets; "full" produces a pill/circle shape.
$radius: (
  "default": 0.25rem, "sm": 0.125rem, "md": 0.375rem, "lg": 0.5rem,
  "xl": 0.75rem, "2xl": 1rem, "3xl": 1.5rem, "full": 9999px
) !default;

// Z-index scale, from plain numbers to named layers (dropdown…tooltip).
$z-layers: (
  "auto": auto, "0": 0, "10": 10, "20": 20, "30": 30,
  "40": 40, "50": 50, "dropdown": 1000, "sticky": 1020,
  "fixed": 1030, "modal": 1040, "popover": 1050, "tooltip": 1060
) !default;

// Transition durations keyed by milliseconds.
$transition-durations: (
  "75": 75ms, "100": 100ms, "150": 150ms, "200": 200ms,
  "300": 300ms, "500": 500ms, "700": 700ms, "1000": 1000ms
) !default;

// Transition timing functions. Keys are used as .ease-* suffixes.
$transition-easings: (
  "linear": linear, "in": cubic-bezier(0.4, 0, 1, 1),
  "out": cubic-bezier(0, 0, 0.2, 1), "in-out": cubic-bezier(0.4, 0, 0.2, 1)
) !default;

// ============================================
//  TOKEN ACCESS FUNCTIONS
//  Typed getters for the token maps. Each one errors out with the
//  list of valid keys when given an unknown key, catching typos
//  at compile time.
// ============================================

// Returns the font stack for a key of $font-families.
@function font-family($name) {
  @if not map.has-key($font-families, $name) {
    @error "font-family(): '#{$name}' no existe. Use: #{map.keys($font-families)}.";
  }
  @return map.get($font-families, $name);
}

// Returns the box-shadow preset for $size ("default", "sm", "md"…).
@function shadow($size: "default") {
  @if not map.has-key($shadow-sizes, $size) {
    @error "shadow(): '#{$size}' no existe. Use: #{map.keys($shadow-sizes)}.";
  }
  @return map.get($shadow-sizes, $size);
}

// Returns the container max-width for $size ("sm"…"6xl").
@function container($size) {
  @if not map.has-key($container-sizes, $size) {
    @error "container(): '#{$size}' no existe. Use: #{map.keys($container-sizes)}.";
  }
  @return map.get($container-sizes, $size);
}

// Returns the pixel width for a breakpoint name ("xs"…"3xl").
@function breakpoint($name) {
  @if not map.has-key($breakpoint-sizes, $name) {
    @error "breakpoint(): '#{$name}' no existe. Use: #{map.keys($breakpoint-sizes)}.";
  }
  @return map.get($breakpoint-sizes, $name);
}

// Returns a value from $spacing-scale. Accepts a string key ("4")
// or a number (4), which is converted to its key form.
@function spacing($size) {
  @if meta.type-of($size) == "number" { $size: "#{$size}"; }
  @if not map.has-key($spacing-scale, $size) {
    @error "spacing(): '#{$size}' no existe. Use: #{map.keys($spacing-scale)}.";
  }
  @return map.get($spacing-scale, $size);
}

// Returns the border-radius preset for $size.
@function radius($size: "default") {
  @if not map.has-key($radius, $size) {
    @error "radius(): '#{$size}' no existe. Use: #{map.keys($radius)}.";
  }
  @return map.get($radius, $size);
}

// Returns the z-index for a layer key; numbers are stringified ("10").
@function z($layer) {
  @if meta.type-of($layer) == "number" { $layer: "#{$layer}"; }
  @if not map.has-key($z-layers, $layer) {
    @error "z(): '#{$layer}' no existe. Use: #{map.keys($z-layers)}.";
  }
  @return map.get($z-layers, $layer);
}

// Returns the transition duration for $ms (75, 100, 150…).
@function duration($ms) {
  @if meta.type-of($ms) == "number" { $ms: "#{$ms}"; }
  @if not map.has-key($transition-durations, $ms) {
    @error "duration(): '#{$ms}' no existe. Use: #{map.keys($transition-durations)}.";
  }
  @return map.get($transition-durations, $ms);
}

// Returns the easing curve for $name (default "in-out").
@function ease($name: "in-out") {
  @if not map.has-key($transition-easings, $name) {
    @error "ease(): '#{$name}' no existe. Use: #{map.keys($transition-easings)}.";
  }
  @return map.get($transition-easings, $name);
}

// ============================================
//  GENERATE CSS CUSTOM PROPERTIES (tokens)
//  Emits the design tokens as --prefix-key custom properties
//  inside :root, e.g. --font-sans-serif, --shadow-md, --spacing-4.
// ============================================

// Emits one group of custom properties per token map.
// Every group is enabled by default; pass false to skip a group
// (e.g. generate-css-tokens($shadows: false)).
@mixin generate-css-tokens(
  $fonts: true, $shadows: true, $containers: true, $spacing: true,
  $radius-tokens: true, $z: true, $durations: true, $easings: true
) {
  :root {
    @if $fonts { @each $n, $v in $font-families { --font-#{$n}: #{list.join($v, (), $separator: comma)}; } }
    @if $shadows { @each $n, $v in $shadow-sizes { --shadow-#{$n}: #{$v}; } }
    @if $containers { @each $n, $v in $container-sizes { --container-#{$n}: #{$v}; } }
    @if $spacing { @each $n, $v in $spacing-scale { --spacing-#{$n}: #{$v}; } }
    @if $radius-tokens { @each $n, $v in $radius { --radius-#{$n}: #{$v}; } }
    @if $z { @each $n, $v in $z-layers { --z-#{$n}: #{$v}; } }
    @if $durations { @each $n, $v in $transition-durations { --duration-#{$n}: #{$v}; } }
    @if $easings { @each $n, $v in $transition-easings { --ease-#{$n}: #{$v}; } }
  }
}

// ============================================================
//  COLOR PALETTES
//  Each palette maps a shade (100–700, light → dark) to an hsla
//  color. Palette names become the prefix of the generated
//  classes and custom properties (--purple-500, .bg-purple-500…).
// ============================================================

// Main palettes. Override the whole map or individual entries
// before importing to re-theme the framework.
$colors: (
  "neutral": (
    50: hsla(0, 0%, 97%, 1), 100: hsla(0, 0%, 93%, 1), 200: hsla(0, 0%, 86%, 1),
    300: hsla(0, 0%, 71%, 1), 400: hsla(0, 0%, 50%, 1), 500: hsla(0, 0%, 35%, 1),
    600: hsla(0, 0%, 24%, 1), 700: hsla(0, 0%, 12%, 1), 800: hsla(0, 0%, 9%, 1),
    900: hsla(0, 0%, 6%, 1), 950: hsla(0, 0%, 3%, 1),
  ),
  "purple": (
    50: hsla(269, 60%, 97%, 1), 100: hsla(269, 60%, 93%, 1), 200: hsla(269, 70%, 86%, 1),
    300: hsla(269, 70%, 71%, 1), 400: hsla(269, 66%, 50%, 1), 500: hsla(269, 66%, 35%, 1),
    600: hsla(269, 60%, 24%, 1), 700: hsla(269, 50%, 12%, 1), 800: hsla(269, 50%, 9%, 1),
    900: hsla(269, 50%, 6%, 1), 950: hsla(269, 50%, 3%, 1),
  ),
  "info": (
    50: hsla(215, 95%, 97%, 1), 100: hsla(215, 95%, 93%, 1), 200: hsla(215, 95%, 86%, 1),
    300: hsla(215, 95%, 71%, 1), 400: hsla(215, 95%, 50%, 1), 500: hsla(215, 95%, 35%, 1),
    600: hsla(215, 95%, 24%, 1), 700: hsla(215, 95%, 12%, 1), 800: hsla(215, 95%, 9%, 1),
    900: hsla(215, 95%, 6%, 1), 950: hsla(215, 95%, 3%, 1),
  ),
  "warning": (
    50: hsla(49, 100%, 97%, 1), 100: hsla(49, 100%, 93%, 1), 200: hsla(49, 100%, 86%, 1),
    300: hsla(49, 100%, 71%, 1), 400: hsla(49, 100%, 50%, 1), 500: hsla(49, 100%, 35%, 1),
    600: hsla(49, 90%, 24%, 1), 700: hsla(49, 70%, 12%, 1), 800: hsla(49, 70%, 9%, 1),
    900: hsla(49, 70%, 6%, 1), 950: hsla(49, 70%, 3%, 1),
  ),
  "danger": (
    50: hsla(3, 95%, 97%, 1), 100: hsla(3, 95%, 93%, 1), 200: hsla(3, 95%, 86%, 1),
    300: hsla(3, 95%, 71%, 1), 400: hsla(3, 95%, 50%, 1), 500: hsla(3, 95%, 35%, 1),
    600: hsla(3, 95%, 24%, 1), 700: hsla(3, 95%, 12%, 1), 800: hsla(3, 95%, 9%, 1),
    900: hsla(3, 95%, 6%, 1), 950: hsla(3, 95%, 3%, 1),
  ),
  "success": (
    50: hsla(147, 95%, 97%, 1), 100: hsla(147, 95%, 93%, 1), 200: hsla(147, 95%, 86%, 1),
    300: hsla(147, 95%, 71%, 1), 400: hsla(147, 95%, 50%, 1), 500: hsla(147, 95%, 35%, 1),
    600: hsla(147, 95%, 24%, 1), 700: hsla(147, 95%, 17%, 1), 800: hsla(147, 95%, 12%, 1),
    900: hsla(147, 95%, 8%, 1), 950: hsla(147, 95%, 4%, 1),
  ),
  // --- Extended palettes (Tailwind-compatible) ---
  "slate": (
    50: hsl(210, 40%, 98%), 100: hsl(210, 40%, 96%), 200: hsl(214, 32%, 91%),
    300: hsl(213, 27%, 84%), 400: hsl(215, 20%, 65%), 500: hsl(215, 16%, 47%),
    600: hsl(215, 19%, 35%), 700: hsl(215, 25%, 27%), 800: hsl(217, 33%, 17%),
    900: hsl(222, 47%, 11%), 950: hsl(229, 84%, 5%),
  ),
  "gray": (
    50: hsl(220, 14%, 96%), 100: hsl(220, 13%, 91%), 200: hsl(220, 13%, 84%),
    300: hsl(216, 12%, 73%), 400: hsl(218, 11%, 65%), 500: hsl(220, 9%, 46%),
    600: hsl(220, 8%, 36%), 700: hsl(220, 10%, 28%), 800: hsl(220, 14%, 18%),
    900: hsl(224, 25%, 10%), 950: hsl(230, 40%, 5%),
  ),
  "zinc": (
    50: hsl(0, 0%, 98%), 100: hsl(240, 5%, 96%), 200: hsl(240, 6%, 90%),
    300: hsl(240, 5%, 81%), 400: hsl(240, 5%, 65%), 500: hsl(240, 4%, 46%),
    600: hsl(240, 5%, 36%), 700: hsl(240, 5%, 28%), 800: hsl(240, 6%, 17%),
    900: hsl(240, 10%, 10%), 950: hsl(240, 20%, 4%),
  ),
  "stone": (
    50: hsl(60, 9%, 97%), 100: hsl(60, 5%, 93%), 200: hsl(20, 6%, 87%),
    300: hsl(30, 5%, 76%), 400: hsl(30, 4%, 60%), 500: hsl(25, 5%, 45%),
    600: hsl(25, 6%, 35%), 700: hsl(28, 7%, 27%), 800: hsl(30, 9%, 17%),
    900: hsl(24, 15%, 11%), 950: hsl(30, 20%, 5%),
  ),
  "red": (
    50: hsl(0, 86%, 97%), 100: hsl(0, 93%, 94%), 200: hsl(0, 96%, 90%),
    300: hsl(0, 94%, 82%), 400: hsl(0, 91%, 71%), 500: hsl(0, 84%, 60%),
    600: hsl(0, 72%, 51%), 700: hsl(0, 74%, 42%), 800: hsl(0, 70%, 35%),
    900: hsl(0, 63%, 31%), 950: hsl(0, 75%, 15%),
  ),
  "orange": (
    50: hsl(34, 100%, 97%), 100: hsl(34, 100%, 92%), 200: hsl(32, 98%, 83%),
    300: hsl(31, 97%, 72%), 400: hsl(27, 96%, 61%), 500: hsl(25, 95%, 53%),
    600: hsl(21, 90%, 48%), 700: hsl(17, 88%, 40%), 800: hsl(15, 79%, 34%),
    900: hsl(16, 72%, 28%), 950: hsl(14, 74%, 14%),
  ),
  "amber": (
    50: hsl(48, 100%, 96%), 100: hsl(48, 96%, 89%), 200: hsl(48, 97%, 77%),
    300: hsl(46, 97%, 65%), 400: hsl(43, 96%, 56%), 500: hsl(38, 92%, 50%),
    600: hsl(32, 95%, 44%), 700: hsl(26, 90%, 37%), 800: hsl(23, 83%, 31%),
    900: hsl(22, 78%, 26%), 950: hsl(22, 80%, 14%),
  ),
  "yellow": (
    50: hsl(55, 92%, 95%), 100: hsl(55, 97%, 88%), 200: hsl(53, 98%, 77%),
    300: hsl(50, 98%, 64%), 400: hsl(48, 96%, 53%), 500: hsl(45, 93%, 47%),
    600: hsl(41, 96%, 40%), 700: hsl(35, 92%, 33%), 800: hsl(32, 81%, 29%),
    900: hsl(28, 73%, 26%), 950: hsl(27, 75%, 13%),
  ),
  "lime": (
    50: hsl(78, 92%, 95%), 100: hsl(80, 89%, 86%), 200: hsl(82, 84%, 72%),
    300: hsl(82, 77%, 56%), 400: hsl(84, 81%, 44%), 500: hsl(85, 78%, 37%),
    600: hsl(86, 69%, 30%), 700: hsl(88, 61%, 25%), 800: hsl(89, 53%, 21%),
    900: hsl(89, 45%, 18%), 950: hsl(89, 60%, 10%),
  ),
  "green": (
    50: hsl(152, 76%, 95%), 100: hsl(149, 80%, 90%), 200: hsl(152, 76%, 80%),
    300: hsl(156, 72%, 67%), 400: hsl(158, 64%, 52%), 500: hsl(160, 84%, 39%),
    600: hsl(161, 94%, 30%), 700: hsl(163, 94%, 24%), 800: hsl(165, 91%, 18%),
    900: hsl(167, 91%, 14%), 950: hsl(168, 100%, 6%),
  ),
  "emerald": (
    50: hsl(151, 81%, 96%), 100: hsl(149, 80%, 90%), 200: hsl(152, 76%, 80%),
    300: hsl(156, 72%, 67%), 400: hsl(158, 64%, 52%), 500: hsl(160, 84%, 39%),
    600: hsl(161, 94%, 30%), 700: hsl(163, 94%, 24%), 800: hsl(165, 91%, 18%),
    900: hsl(167, 91%, 14%), 950: hsl(168, 100%, 6%),
  ),
  "teal": (
    50: hsl(166, 76%, 97%), 100: hsl(167, 85%, 89%), 200: hsl(168, 84%, 78%),
    300: hsl(170, 77%, 64%), 400: hsl(172, 66%, 50%), 500: hsl(173, 80%, 36%),
    600: hsl(174, 83%, 28%), 700: hsl(175, 78%, 23%), 800: hsl(176, 69%, 18%),
    900: hsl(178, 61%, 16%), 950: hsl(180, 80%, 8%),
  ),
  "cyan": (
    50: hsl(183, 100%, 96%), 100: hsl(185, 96%, 90%), 200: hsl(186, 94%, 82%),
    300: hsl(187, 92%, 69%), 400: hsl(187, 81%, 53%), 500: hsl(189, 94%, 43%),
    600: hsl(192, 91%, 34%), 700: hsl(193, 84%, 27%), 800: hsl(195, 78%, 22%),
    900: hsl(197, 71%, 18%), 950: hsl(198, 80%, 9%),
  ),
  "sky": (
    50: hsl(204, 100%, 97%), 100: hsl(204, 94%, 94%), 200: hsl(201, 94%, 86%),
    300: hsl(199, 95%, 74%), 400: hsl(198, 93%, 60%), 500: hsl(199, 89%, 48%),
    600: hsl(200, 98%, 39%), 700: hsl(201, 96%, 32%), 800: hsl(201, 90%, 27%),
    900: hsl(202, 80%, 24%), 950: hsl(204, 80%, 12%),
  ),
  "blue": (
    50: hsl(214, 100%, 97%), 100: hsl(214, 95%, 93%), 200: hsl(213, 97%, 87%),
    300: hsl(212, 96%, 78%), 400: hsl(213, 94%, 68%), 500: hsl(217, 91%, 60%),
    600: hsl(221, 83%, 53%), 700: hsl(224, 76%, 48%), 800: hsl(226, 71%, 40%),
    900: hsl(224, 64%, 33%), 950: hsl(226, 55%, 21%),
  ),
  "indigo": (
    50: hsl(226, 100%, 97%), 100: hsl(226, 100%, 94%), 200: hsl(228, 96%, 89%),
    300: hsl(230, 94%, 82%), 400: hsl(234, 89%, 74%), 500: hsl(239, 84%, 67%),
    600: hsl(243, 75%, 59%), 700: hsl(245, 58%, 51%), 800: hsl(244, 55%, 41%),
    900: hsl(243, 47%, 34%), 950: hsl(244, 47%, 20%),
  ),
  "violet": (
    50: hsl(250, 100%, 97%), 100: hsl(251, 100%, 94%), 200: hsl(251, 91%, 87%),
    300: hsl(252, 90%, 80%), 400: hsl(256, 86%, 72%), 500: hsl(258, 80%, 63%),
    600: hsl(262, 73%, 54%), 700: hsl(263, 70%, 46%), 800: hsl(263, 67%, 38%),
    900: hsl(263, 62%, 31%), 950: hsl(265, 60%, 18%),
  ),
  "pink": (
    50: hsl(330, 100%, 97%), 100: hsl(340, 100%, 93%), 200: hsl(340, 82%, 86%),
    300: hsl(339, 77%, 76%), 400: hsl(340, 72%, 65%), 500: hsl(340, 75%, 54%),
    600: hsl(343, 72%, 46%), 700: hsl(345, 67%, 39%), 800: hsl(346, 61%, 33%),
    900: hsl(347, 55%, 28%), 950: hsl(349, 66%, 14%),
  ),
  "rose": (
    50: hsl(340, 100%, 97%), 100: hsl(340, 87%, 93%), 200: hsl(340, 82%, 86%),
    300: hsl(340, 77%, 76%), 400: hsl(340, 72%, 65%), 500: hsl(348, 81%, 59%),
    600: hsl(348, 76%, 50%), 700: hsl(348, 67%, 42%), 800: hsl(347, 60%, 35%),
    900: hsl(344, 55%, 29%), 950: hsl(346, 72%, 15%),
  ),
  "fuchsia": (
    50: hsl(289, 100%, 97%), 100: hsl(287, 100%, 93%), 200: hsl(288, 86%, 86%),
    300: hsl(291, 77%, 76%), 400: hsl(292, 72%, 65%), 500: hsl(292, 72%, 54%),
    600: hsl(292, 67%, 46%), 700: hsl(291, 59%, 39%), 800: hsl(290, 53%, 33%),
    900: hsl(288, 46%, 28%), 950: hsl(290, 60%, 15%),
  ),
) !default;

// Single-value colors without shades: black, white, transparent, current.
$special-colors: (
  "black": hsl(0, 0%, 3%), "white": hsl(0, 0%, 98%),
  "transparent": transparent, "current": currentColor
) !default;

// Shade order used by the theme() mixin to invert palettes in dark mode.
$shades: (50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950) !default;

// ============================================================
//  COLOR ACCESS FUNCTIONS
//  Typed color getters with compile-time validation.
// ============================================================

// Returns a color from $colors/$special-colors.
// Special colors ("white", "black"…) ignore $shade. Pass $alpha != 1
// to change the alpha channel of regular colors.
@function get-color($name, $shade: 300, $alpha: 1) {
  @if map.has-key($special-colors, $name) {
    $color: map.get($special-colors, $name);
    @if $alpha != 1 and meta.type-of($color) == "color" { @return color.change($color, $alpha: $alpha); }
    @return $color;
  }
  @if not map.has-key($colors, $name) { @error "get-color(): paleta '#{$name}' no existe."; }
  $palette: map.get($colors, $name);
  @if not map.has-key($palette, $shade) { @error "get-color(): tono '#{$shade}' no existe en '#{$name}'."; }
  $color: map.get($palette, $shade);
  @if $alpha != 1 { @return color.change($color, $alpha: $alpha); }
  @return $color;
}

// Shorthand: main color of a palette (shade 500) with optional alpha.
@function get($name, $alpha: 1) { @return get-color($name, 500, $alpha); }
// Shorthand for a semi-transparent color (alpha defaults to 0.5).
@function alpha($name, $shade: 500, $alpha: 0.5) { @return get-color($name, $shade, $alpha); }

// ============================================================
//  GENERATE CSS CUSTOM PROPERTIES (colors)
//  Emits --palette-shade custom properties (plus the special
//  colors) inside the selector you choose.
// ============================================================

// Private helper: keeps only the palettes whose names are listed in
// $keys (a single string is wrapped into a one-item list first).
@function _filter-palettes($map, $keys) {
  @if meta.type-of($keys) == "string" { $keys: ($keys,); }
  $result: ();
  @each $key, $value in $map {
    @if list.index($keys, $key) != null { $result: map.merge($result, ($key: $value)); }
  }
  @return $result;
}

// Emits color custom properties.
// $root: selector to wrap the properties in (default ":root").
// $palettes: null → all palettes; a map → use it directly;
//            a list of names → only those palettes from $colors.
// $include-special: also emit --white, --black, --transparent, --current.
@mixin generate-css-vars($root: ":root", $palettes: null, $include-special: true) {
  $source: $colors;
  @if $palettes != null {
    @if meta.type-of($palettes) == "map" { $source: $palettes; }
    @else { $source: _filter-palettes($colors, $palettes); }
  }
  #{$root} {
    @each $name, $palette in $source {
      @each $shade, $value in $palette { --#{$name}-#{$shade}: #{$value}; }
    }
    @if $include-special {
      @each $name, $value in $special-colors { --#{$name}: #{$value}; }
    }
  }
}

// ============================================================
//  COLOR UTILITY CLASS GENERATORS
//  Emit utility classes from the palettes, e.g.
//  .text-purple-500, .bg-info-300, .border-danger-700 and the
//  special variants .text-white, .bg-transparent…
// ============================================================

// Private generator shared by text/bg/border utilities:
// one class per palette shade for $property, prefixed with $class-prefix.
@mixin _utility-classes($property, $class-prefix, $palettes: null, $include-special: true) {
  $palettes: if(sass($palettes == null): $colors; else: _filter-palettes($colors, $palettes));
  @each $name, $palette in $palettes {
    @each $shade, $value in $palette {
      .#{$class-prefix}-#{$name}-#{$shade} { #{$property}: $value; }
    }
  }
  @if $include-special {
    @each $name, $value in $special-colors {
      .#{$class-prefix}-#{$name} { #{$property}: $value; }
    }
  }
}

// Public generators. Each accepts $palettes (null = all, list = subset)
// and $special (whether to emit the special colors too).
@mixin text-utilities($palettes: null, $special: true)   { @include _utility-classes(color, "text", $palettes, $special); }
@mixin bg-utilities($palettes: null, $special: true)     { @include _utility-classes(background-color, "bg", $palettes, $special); }
@mixin border-utilities($palettes: null, $special: true) { @include _utility-classes(border-color, "border", $palettes, $special); }

// Emits :hover color variants: .hover-text-purple-500:hover and
// .hover-bg-purple-500:hover (plus the special colors).
@mixin hover-utilities($palettes: null, $special: true) {
  $palettes: if(sass($palettes == null): $colors; else: _filter-palettes($colors, $palettes));
  @each $name, $palette in $palettes {
    @each $shade, $value in $palette {
      .hover-text-#{$name}-#{$shade}:hover { color: $value; }
      .hover-bg-#{$name}-#{$shade}:hover   { background-color: $value; }
    }
  }
  @if $special {
    @each $name, $value in $special-colors {
      .hover-text-#{$name}:hover { color: $value; }
      .hover-bg-#{$name}:hover   { background-color: $value; }
    }
  }
}

// Emits every color utility group at once.
@mixin all-utilities($palettes: null, $special: true) {
  @include text-utilities($palettes, $special);
  @include bg-utilities($palettes, $special);
  @include border-utilities($palettes, $special);
  @include hover-utilities($palettes, $special);
}

// ============================================================
//  THEME
//  Emits a themed set of color custom properties scoped to a
//  selector, e.g. :root[data-theme='dark'].
// ============================================================

// Creates a color theme. For $mode == "dark" each palette is
// inverted (shade 100 ↔ 700, 200 ↔ 600, …) so light shades become
// dark and vice versa. $overrides is merged on top of the result.
// Output selector: :root[data-theme='<mode>'].
// Dark mode inversion pairs: light shade ↔ dark shade.
$_dark-inversion: (
  50: 950, 100: 900, 200: 800, 300: 700, 400: 600,
  500: 500, 600: 400, 700: 300, 800: 200, 900: 100, 950: 50
);

@mixin theme($mode, $overrides: ()) {
  $base: $colors;
  @if $mode == "dark" {
    $base: ();
    @each $name, $palette in $colors {
      $new: ();
      @each $shade, $value in $palette {
        $inverted: map.get($_dark-inversion, $shade);
        @if $inverted != null and map.has-key($palette, $inverted) {
          $new: map.merge($new, ($shade: map.get($palette, $inverted)));
        } @else {
          // No inversion pair exists; keep the original value.
          $new: map.merge($new, ($shade: $value));
        }
      }
      $base: map.merge($base, ($name: $new));
    }
  }
  @if meta.type-of($overrides) == "map" { $base: map.merge($base, $overrides); }
  @include generate-css-vars(":root[data-theme='#{$mode}']", $base, false);
}
