{"version":3,"file":"index.mjs","names":[],"sources":["../src/utils.ts","../src/properties.ts","../src/rules.ts","../src/selectors.ts"],"sourcesContent":["// cspell:words khtml\n\n/**\n * A type-safe wrapper around Object.keys that preserves the object's key types.\n *\n * @returns a typed array of keys of the object\n */\nexport const unsafeKeys = Object.keys as <T>(object: T) => Array<keyof T>;\n\n/**\n * A generator function that yields keys of an object that pass an optional validation function.\n *\n * Iterates through all own properties of the given object and yields\n * each key that passes the optional validation function.\n *\n * @param object - The object to iterate over\n * @param valid - Optional validation function that determines which keys to yield\n * @returns A generator of valid keys from the object\n */\nexport function* keys<T, K extends keyof T>(object: T, valid?: (key: keyof T) => boolean): Generator<K> {\n  for (const key of unsafeKeys(object)) {\n    if (typeof key === 'string' && Object.prototype.hasOwnProperty.call(object, key) && (valid?.(key) ?? true)) {\n      yield key as K;\n    }\n  }\n}\n\n/**\n * Validates if a key-value pair meets default criteria.\n *\n * A key-value pair is considered valid when:\n * - The value is neither null nor undefined\n * - The key doesn't contain spaces\n * - The key doesn't start with an underscore (_)\n *\n * @param key - The key to validate\n * @param value - The value to validate\n * @returns true if the key-value pair is valid, false otherwise\n *\n */\nexport function defaultValidPair<K extends string, T = unknown>(key: K, value: T): boolean {\n  return value !== null &&\n    value !== undefined &&\n    !key.includes(' ') &&\n    !key.startsWith('_');\n}\n\n/**\n * A generator function that yields valid key-value pairs from an object.\n *\n * Iterates through all own properties of the given object and yields\n * each key-value pair that passes the validation function.\n *\n * @param object - The object to iterate over\n * @param valid - Optional validation function that determines which key-value pairs to yield\n * @returns A generator of valid key-value pairs from the object\n */\nexport function* pairs<K extends string = string, T = unknown>(\n  object: Record<K, T>,\n  valid?: (k: K, v: T) => boolean,\n): Generator<[K, T]> {\n  for (const key of keys(object)) {\n    const value = object[key];\n    if (valid?.(key, value) ?? defaultValidPair(key, value))\n      yield [key, value];\n  }\n}\n\n/*\n * Converts a given string to kebab-case.\n *\n * Transforms various string formats (camelCase, PascalCase, snake_case)\n * into a lowercase string with words separated by hyphens.\n * Adds leading hyphen to recognized vendor prefixes.\n *\n * @param s - The input string to convert\n * @returns A kebab-case representation of the input string\n *\n * @example\n * kebabCase('XMLHttpRequest') // returns 'xml-http-request'\n * kebabCase('camelCase') // returns 'camel-case'\n * kebabCase('snake_case') // returns 'snake-case'\n * kebabCase('WebkitTransition') // returns '-webkit-transition'\n */\nexport function kebabCase(s: string): string {\n  // Apply standard kebab-case transformations\n  const result = s\n    .trim()\n    // handle multiple uppercase letters (e.g., XMLHttpRequest -> xml-http-request)\n    // use lookbehind + lookahead to avoid ReDoS from overlapping quantifiers\n    .replaceAll(/(?<=[A-Z])(?=[A-Z][a-z])/g, '-')\n    // handle camelCase\n    .replaceAll(/([a-z])([A-Z])/g, '$1-$2')\n    // handle snakeCase\n    .replaceAll(/[\\s_]+/g, '-')\n    .toLowerCase();\n\n  // Check for vendor prefixes using a regex and add leading hyphen if needed\n  if (vendorPrefixPattern.test(result)) {\n    return `-${result}`;\n  }\n\n  return result;\n}\n\nconst vendorPrefixPattern = /^(webkit|moz|ms|o|khtml)-/;\n\n/**\n * Converts a given string to camelCase.\n *\n * Transforms various string formats (kebab-case, PascalCase, snake_case)\n * into a camelCase string. Properly handles vendor prefixes and internal\n * capitalization patterns.\n *\n * @param s - The input string to convert\n * @returns A camelCase representation of the input string\n *\n * @example\n * camelCase('xml-http-request') // returns 'xmlHttpRequest'\n * camelCase('PascalCase') // returns 'pascalCase'\n * camelCase('snake_case') // returns 'snakeCase'\n * camelCase('-webkit-transition') // returns 'webkitTransition'\n * camelCase('BGColor') // returns 'bgColor'\n * camelCase('HTMLElement') // returns 'htmlElement'\n */\nexport function camelCase(s: string): string {\n  // Handle empty strings and single delimiters\n  if (!s || s === '-' || s === '_') {\n    return '';\n  }\n\n  // Remove leading hyphens (for vendor prefixes) and trim\n  let result = s.trim().replace(/^-/, '');\n\n  // Handle explicit delimiter-separated words (kebab-case, snake_case, spaces)\n  result = result.replaceAll(/[-_\\s]+([a-zA-Z\\d])/g, (_, c: string) => c.toUpperCase());\n\n  // Handle internal capitalization patterns like \"BGColor\" -> \"bgColor\"\n  // Look for uppercase letters that are preceded by lowercase or are the start\n  // of a capital sequence followed by lowercase (like in \"BGColor\" or \"HTMLElement\")\n  result = result\n    // First handle patterns like \"BGColor\" -> \"bgColor\" by lowercasing\n    // uppercase runs before a capital+lowercase boundary\n    .replaceAll(/[A-Z]+(?=[A-Z][a-z])/g, (match) => match.toLowerCase())\n    // Then ensure the first letter is lowercase (handling both PascalCase and\n    // cases like \"BG\" at the start)\n    .replaceAll(/^[A-Z]+/g, (match) => match.toLowerCase());\n\n  return result;\n}\n","import {\n  kebabCase,\n  pairs,\n} from './utils';\n\nexport type CSSProperties<K extends string = string> = Record<K, CSSValue>;\nexport type CSSValue = (boolean | number | string)[] | boolean | number | string;\n\n/**\n * Configuration options for CSS properties stringification.\n */\nexport type CSSPropertiesOptions = {\n  /** Indentation string, defaults to two spaces. */\n  indent?: string\n  /** Whether to format output on a single line, defaults to false. */\n  inline?: boolean\n  /** New line character, defaults to LF. */\n  newLine?: string\n  /** Prefix string added before each line, defaults to empty string. */\n  prefix?: string\n  /** Maximum number of properties to format on a single line, defaults to 1. */\n  singleLineThreshold?: number\n};\n\n/**\n * Converts a CSSProperties object into a formatted CSS string representation.\n *\n * @param object - The CSSProperties object to stringify.\n * @param options - Configuration options for string formatting.\n * @returns A string representing the CSS properties enclosed in curly braces.\n * @remarks no newLine at the end to aid composition.\n */\nexport function stringifyCSSProperties<K extends string>(\n  object: CSSProperties<K>,\n  options?: CSSPropertiesOptions,\n): string {\n  const {\n    indent = '  ',\n    prefix = '',\n    newLine = '\\n',\n    inline = false,\n    singleLineThreshold = 1,\n  } = options || {};\n\n  const lines = formatCSSProperties(object);\n\n  // Handle empty blocks with a simple format\n  if (lines.length === 0) {\n    return '{}';\n  }\n\n  // Handle inline mode or when property count is below threshold\n  if (inline || lines.length <= singleLineThreshold) {\n    return `{ ${lines.join('; ')} }`;\n  }\n\n  // Standard multiline format\n  return `{${newLine}${prefix}${indent}${lines.join(`;${newLine}${prefix}${indent}`)}${newLine}${prefix}}`;\n}\n\n/**\n * Formats a CSSProperties object into an array of CSS property strings.\n *\n * @param object - The CSSProperties object to format.\n * @returns An array of strings, where each string is a CSS property in the format \"key: value;\".\n */\nexport function formatCSSProperties<K extends string>(object: CSSProperties<K>): string[] {\n  const propertyMap = new Map<string, string>();\n  for (const [key, value] of properties(object)) {\n    const kebabKey = kebabCase(key);\n    const useComma = !spaceDelimitedProperties.has(kebabKey);\n    const formattedValue = formatCSSValue(value, useComma);\n    propertyMap.set(kebabKey, formattedValue);\n  }\n\n  const lines: string[] = [];\n  for (const [key, value] of propertyMap) {\n    lines.push(`${key}: ${value}`);\n  }\n  return lines;\n}\n\n/**\n * Formats a CSS value into a string representation.\n *\n * @param value - The CSS value to format, which can be a single value or an array of values.\n * @param useComma - Flag to determine whether array values should be comma-separated (true)\n *                   or space-separated (false). Defaults to true.\n * @returns A formatted string representation of the CSS value.\n * @remarks\n\n * - For array values, elements are joined with commas or spaces based on the useComma parameter.\n * - The choice between commas and spaces depends on the CSS property being formatted.\n * - Properties like 'font-family' use commas while properties like 'margin' use spaces.\n */\nexport function formatCSSValue(value: CSSValue, useComma = true): string {\n  if (Array.isArray(value)) {\n    return value.map((v) => quoted(v)).join(useComma ? ', ' : ' ');\n  }\n  return quoted(value);\n}\n\n/**\n * Encloses a CSS value in double quotes if it is a string containing spaces,\n * except for CSS functions which should not be quoted.\n *\n * @param v - The CSS value to process.\n * @returns The processed CSS value as a string.\n * @example\n * quoted('Open Sans')         // Returns \"\\\"Open Sans\\\"\"\n * quoted('rgb(255, 0, 0)')    // Returns \"rgb(255, 0, 0)\" (no quotes - CSS function)\n * quoted(16)                  // Returns \"16\"\n * quoted(true)                // Returns \"true\"\n */\nexport function quoted(v: CSSValue): string {\n  if (typeof v === 'boolean') {\n    return v ? 'true' : 'false';\n  } else if (typeof v === 'string') {\n    // Check if this is a CSS function (contains parentheses)\n    const isCssFunction = /^[a-zA-Z-]+\\(.*\\)$/.test(v.trim());\n\n    // Only quote strings with spaces that are not CSS functions\n    if (v.includes(' ') && !isCssFunction) {\n      return `\"${v}\"`;\n    }\n  }\n  return String(v);\n}\n\n/**\n * Generates a sequence of valid CSS property key-value pairs from a CSSProperties object.\n *\n * @param object - The object containing CSS properties.\n * @returns A generator of valid key-value CSS property pairs.\n * @remarks Filters out invalid or empty CSS property values, returning only valid entries.\n */\nexport function* properties<K extends string>(object: CSSProperties<K>): Generator<[K, CSSValue]> {\n  for (const [key, value] of pairs(object)) {\n    if (Array.isArray(value) ? (value.length > 0 && value.every((v) => isValidValue(v))) : isValidValue(value)) {\n      yield [key, value as CSSValue];\n    }\n  }\n}\n\n/**\n * Checks if a CSS value is valid.\n * A value is considered valid if it is a non-empty string or a number.\n *\n * @param value - The value to check.\n * @returns True if the value is valid, false otherwise.\n */\nfunction isValidValue(value: unknown): boolean {\n  if (typeof value === 'string')\n    return value !== '';\n  return typeof value === 'number';\n}\n\n/**\n * A set of CSS properties that typically have space-delimited values.\n * These properties often require multiple values to be specified in a single declaration.\n *\n * @remarks\n * When formatting CSS values for these properties, values are space-separated rather than comma-separated.\n * For example:\n * - margin: 10px 20px 30px 40px    (spaces between values)\n * - padding: 5px 10px              (spaces between values)\n * - font: bold 16px Arial          (spaces between values)\n *\n * This differs from comma-separated properties like font-family:\n * - font-family: Arial, Helvetica, sans-serif  (commas between values)\n */\nexport const spaceDelimitedProperties: ReadonlySet<string> = new Set([\n  'animation',\n  'background',\n  'box-shadow',\n  'flex',\n  'font',\n  'grid-auto-columns',\n  'grid-auto-flow',\n  'grid-auto-rows',\n  'grid-gap',\n  'grid-template-areas',\n  'grid-template-columns',\n  'grid-template-rows',\n  'list-style',\n  'margin',\n  'padding',\n  'text-decoration',\n  'text-shadow',\n  'transform',\n  'transition',\n]);\n","import { defu } from 'defu';\nimport { kebabCase, pairs } from './utils';\n\nimport {\n  formatCSSValue,\n  spaceDelimitedProperties,\n} from './properties';\n\n/**\n * Represents a structured CSS rule set that can contain nested rules.\n *\n * This type allows for representing complex CSS structures including:\n * - Simple property/value pairs\n * - At-rules (like `@media`, `@keyframes`)\n * - Nested rule sets\n * - Arrays of values or rule sets\n *\n * @example\n * ```\n * // Example CSS rule structure\n * const rules = {\n *   body: {\n *     color: 'red',\n *     fontSize: '16px',\n *     '@media (max-width: 768px)': {\n *       fontSize: '14px'\n *     }\n *   }\n * };\n * ```\n */\nexport type CSSRules = {\n  [name: string]: CSSRules | CSSRules[] | null | string | string[]\n};\n\n/**\n * Represents the possible value types that can be assigned to a CSS rule.\n *\n * This is a type alias for the union of all possible values in a CSSRules\n * object.\n */\nexport type CSSRulesValue = CSSRules[string];\n\n/**\n * Configuration options for formatting CSS rules.\n */\nexport interface CSSRulesFormatOptions {\n  /**\n   * Indentation string to use for each level of nesting.\n   * @defaultValue `'  '` (two spaces)\n   */\n  indent?: string\n\n  /**\n   * Prefix string added before each line.\n   * @defaultValue `''` (empty string)\n   */\n  prefix?: string\n\n  /**\n   * Optional validation function to determine which rules to include.\n   * @param key - The rule name/selector\n   * @param value - The rule value\n   * @returns `true` if the rule should be included, `false` otherwise\n   */\n  valid?: (key: string, value: CSSRulesValue) => boolean\n\n  /**\n   * Whether to normalize CSS property names from camelCase to kebab-case.\n   * Only applies to property names, not selectors.\n   * @defaultValue `false`\n   */\n  normalizeProperties?: boolean\n}\n\n/**\n * A subset of CSSRules that is compatible with tailwindcss plugin API.\n *\n * This type is more restrictive than CSSRules:\n * - It doesn't allow null values\n * - It uses itself for nested rules rather than the broader CSSRules type\n */\nexport type CSSRuleObject = {\n  [key: string]: CSSRuleObject | string | string[]\n};\n\n/**\n * Converts a CSS rule object into a formatted string representation.\n *\n * This function takes a CSS rule object and returns a formatted string with\n * proper indentation and nesting.\n *\n * @param rules - The CSS rules to stringify\n * @param options - Configuration options for string formatting\n * @returns A string representing the CSS rules with proper formatting\n * @remarks a newLine is not appended at the end to aid composition.\n *\n * @example\n * ```\n * // Simple example of converting CSS rules to string format\n * const rules = {\n *   'body': {\n *     'color': 'red',\n *     'font-size': '16px'\n *   }\n * };\n *\n * const result = stringifyCSSRules(rules);\n * // Result will be:\n * // body {\n * //   color: red;\n * //   font-size: 16px;\n * // };\n * ```\n */\nexport function stringifyCSSRules(\n  rules: CSSRuleObject | CSSRules = {},\n  options: CSSRulesFormatOptions & {\n    /**\n     * Character(s) to use for line breaks.\n     * @defaultValue `'\\n'`\n     */\n    newLine?: string\n  } = {},\n): string {\n  const {\n    newLine = '\\n',\n  } = options;\n\n  return formatCSSRules(rules, options).join(newLine);\n}\n\n/**\n * Formats CSS rule objects into an array of formatted lines.\n *\n * This function processes a CSS rule object and returns an array of strings,\n * where each string represents a line in the formatted CSS output. It\n * handles various value types including strings, numbers, arrays, and nested\n * objects.\n *\n * @param rules - The CSS rules to format\n * @param options - Configuration options for formatting\n * @returns An array of strings, each representing a line in the formatted\n *   CSS\n *\n * @example\n * ```\n * const rules = {\n *   'body': {\n *     'color': 'red'\n *   }\n * };\n *\n * const lines = formatCSSRules(rules);\n * // Returns: ['body {', '  color: red;', '}']\n * ```\n */\nexport function formatCSSRules(\n  rules: CSSRuleObject | CSSRules = {},\n  options: CSSRulesFormatOptions = {},\n): string[] {\n  return [...generateCSSRules(rules, options)];\n}\n\n/**\n * Formats an array of CSS rules into an array of formatted string lines.\n *\n * This function processes various CSS rule representations recursively and\n * converts them into strings representing CSS code with proper formatting.\n * It handles:\n *\n * - String values (treated as direct CSS with semicolons added)\n * - Empty strings (converted to blank lines for spacing if appropriate)\n * - CSS rule objects (recursively processed with formatCSSRules)\n * - Empty rule objects (possibly generating blank lines)\n *\n * The function maintains proper whitespace by tracking whether the last\n * inserted item was a blank line to avoid consecutive empty lines.\n *\n * @param rules - The array of CSS rules to format (strings or rule objects)\n * @param options - Configuration options for formatting\n * @returns An array of strings, each representing a line in the formatted\n *   CSS\n *\n * @example\n * ```\n * // Mixed strings and objects\n * formatCSSRulesArray([\n *   'display: block',\n *   { color: 'red' },\n *   '',\n *   { fontSize: '16px' }\n * ]);\n * // Returns: ['display: block;', 'color: red;', '', 'fontSize: 16px;']\n * ```\n */\nexport function formatCSSRulesArray(\n  rules: (CSSRuleObject | CSSRules | string)[] = [],\n  options: CSSRulesFormatOptions = {},\n): string[] {\n  return [...generateCSSRulesArray(rules, options)];\n}\n\n/**\n * Default validation function for CSS rules.\n *\n * Determines if a CSS rule key-value pair should be included in the output.\n * By default, a rule is valid if:\n * - The key is not an empty string\n * - The value is neither undefined nor null\n *\n * @param key - The rule key/selector to validate\n * @param value - The rule value to validate\n * @returns `true` if the rule should be included, `false` otherwise\n */\nexport function defaultValidCSSRule(\n  key: string,\n  value: CSSRulesValue,\n): boolean {\n  if (key === '' || value === undefined || value === null) {\n    return false;\n  }\n  return true;\n}\n\n/**\n * Special handling for CSS at-rules with empty content.\n *\n * At-rules (rules starting with `@`) with empty content are treated\n * differently:\n * - Empty at-rules (like `@import`, `@charset`) are rendered as a single\n *   line with semicolon\n * - Normal CSS rules with empty content would be omitted entirely\n *\n * @example\n * `@supports (display: grid) {}` becomes `@supports (display: grid);`\n */\nfunction atRuleException(key: string, value: CSSRulesValue): boolean {\n  if (!key.startsWith('@') || value === null) {\n    return false;\n  } else if (Array.isArray(value)) {\n    return value.length === 0;\n  } else if (typeof value === 'object') {\n    return Object.keys(value).length === 0;\n  } else {\n    return false;\n  }\n}\n\n/**\n * Generator version of formatCSSRulesArray that yields lines as they're\n * generated. This avoids building arrays in memory and is more efficient for\n * large files.\n *\n * @param rules - The array of CSS rules to format\n * @param options - Configuration options for formatting\n * @returns Generator that yields individual CSS lines without line\n *   endings\n */\nexport function* generateCSSRulesArray(\n  rules: (CSSRuleObject | CSSRules | string)[] = [],\n  options: CSSRulesFormatOptions = {},\n): Generator<string, void, unknown> {\n  // Track if the last item was a blank line to avoid consecutive empty lines\n  let wasBlankLine = true;\n\n  for (const value of rules) {\n    if (typeof value === 'string') {\n      // String rule, preserve empty for whitespace\n      if (value) {\n        yield `${value};`;\n        wasBlankLine = false;\n      } else if (!wasBlankLine) {\n        yield '';\n        wasBlankLine = true;\n      }\n    } else if (value !== null && value !== undefined) {\n      // Object rule\n      let hasContent = false;\n      const innerLines: string[] = [];\n\n      // Collect to check if empty (we need to peek ahead)\n      for (const line of generateCSSRules(value, options)) {\n        innerLines.push(line);\n        hasContent = true;\n      }\n\n      if (hasContent) {\n        for (const line of innerLines) {\n          yield line;\n        }\n        wasBlankLine = false;\n      } else if (!wasBlankLine) {\n        yield '';\n        wasBlankLine = true;\n      }\n    }\n  }\n}\n\n/**\n * Generator version of formatCSSRules that yields lines as they're\n * generated.\n *\n * @param rules - The CSS rules to format\n * @param options - Configuration options for formatting\n * @returns Generator that yields individual CSS lines without line\n *   endings\n */\nexport function* generateCSSRules(\n  rules: CSSRuleObject | CSSRules = {},\n  options: CSSRulesFormatOptions = {},\n): Generator<string, void, unknown> {\n  const {\n    indent = '  ',\n    prefix = '',\n    valid = defaultValidCSSRule,\n    normalizeProperties = false,\n  } = options;\n\n  const nextOptions: CSSRulesFormatOptions = {\n    ...options,\n    prefix: prefix + indent,\n  };\n\n  // Helper to normalize key if appropriate (property vs selector/at-rule)\n  const mayNormalize = (key: string): string => {\n    if (!normalizeProperties) return key;\n    // Don't normalize selectors or at-rules\n    if (key.startsWith('.') || key.startsWith('#') ||\n      key.startsWith('@') || key.startsWith(':') ||\n      key.includes(' ')) {\n      return key;\n    }\n    return kebabCase(key);\n  };\n\n  for (const [key, value] of pairs(rules, valid)) {\n    if (atRuleException(key, value)) {\n      // at-function\n      yield `${prefix}${key};`;\n    } else if (typeof value === 'string') {\n      // string, omit empty\n      if (value) {\n        // Apply kebab-case conversion only to properties, like formatCSSProperties\n        yield `${prefix}${mayNormalize(key)}: ${value};`;\n      }\n    } else if (Array.isArray(value)) {\n      if (value.length === 0) {\n        // Skip empty arrays\n      } else if (typeof value[0] === 'string') {\n        // multi-value - follow formatCSSProperties pattern\n        const normalizedKey = mayNormalize(key);\n        const useComma = !spaceDelimitedProperties.has(normalizedKey);\n        const inner = formatCSSValue(value as string[], useComma);\n        if (inner) {\n          yield `${prefix}${normalizedKey}: ${inner};`;\n        }\n      } else {\n        // nested rules array\n        let hasContent = false;\n        const innerLines: string[] = [];\n\n        // Collect to check if empty\n        for (const line of generateCSSRulesArray(value, nextOptions)) {\n          innerLines.push(line);\n          hasContent = true;\n        }\n\n        if (hasContent) {\n          yield `${prefix}${key} {`;\n          for (const line of innerLines) {\n            yield line;\n          }\n          yield `${prefix}}`;\n        }\n      }\n    } else if (value) {\n      // nested rules object\n      let hasContent = false;\n      const innerLines: string[] = [];\n\n      // Collect to check if empty\n      for (const line of generateCSSRules(value, nextOptions)) {\n        innerLines.push(line);\n        hasContent = true;\n      }\n\n      if (hasContent) {\n        yield `${prefix}${key} {`;\n        for (const line of innerLines) {\n          yield line;\n        }\n        yield `${prefix}}`;\n      }\n    }\n  }\n}\n\n/**\n * Interleaves an array of CSS rule objects with empty objects.\n *\n * @param rules - An array of CSS rule objects to be interleaved\n * @returns An array with the original rules spaced out with empty objects\n *\n * @example\n * ```\n * // Input: [{ color: 'red' }, { background: 'blue' }]\n * // Output: [{ color: 'red' }, {}, { background: 'blue' }]\n * ```\n */\nexport function interleavedRules(rules: CSSRules[]): CSSRules[] {\n  if (rules.length === 0) return [];\n\n  const size = rules.length * 2 - 1;\n  const out: Array<CSSRules> = Array.from({ length: size }, () => ({}));\n\n  let i = 0;\n  for (const entry of rules) {\n    out[i] = entry;\n    i += 2;\n  }\n\n  return out;\n}\n\n/**\n * Renames the keys in a CSS rules object using the provided function.\n *\n * @param rules - The CSS rules object whose keys should be renamed\n * @param fn - A function that takes an original key name and returns a new\n *   key name (or falsy value to skip)\n * @returns A new CSS rules object with renamed keys\n *\n * @example\n * ```\n * // Input: { '.button': { color: 'blue' } }, key => `@utility\n * //   ${key.slice(1)}`\n * // Output: { '@utility button': { color: 'blue' } }\n * ```\n */\nexport function renameRules(\n  rules: CSSRules,\n  fn: (name: string) => string,\n): CSSRules {\n  if (!fn) return rules;\n\n  const map = new Map<string, CSSRules[string]>();\n  for (const [key, value] of pairs(rules)) {\n    const k2 = fn(key);\n    if (k2) map.set(k2, value);\n  }\n\n  return Object.fromEntries(map);\n}\n\nconst UNSAFE_PROTO_KEYS: ReadonlySet<string> = new Set([\n  '__proto__',\n  'constructor',\n  'prototype',\n]);\n\n/** True for keys that would mutate the prototype chain when assigned. */\nfunction isUnsafeKey(key: string): boolean {\n  return UNSAFE_PROTO_KEYS.has(key);\n}\n\n/** Descends into `parent[key]`, creating an empty CSSRules if missing.\n * Throws if a non-object value already occupies the slot. */\nfunction getOrCreateChild(\n  parent: CSSRules,\n  key: string,\n  segmentIndex: number,\n  fullPath: string[],\n): CSSRules {\n  const existing = parent[key];\n  if (existing === undefined) {\n    const empty = {} as CSSRules;\n    parent[key] = empty;\n    return empty;\n  }\n  if (typeof existing !== 'object' || existing === null) {\n    throw new Error(\n      `Invalid path at segment ${segmentIndex}: \"${key}\" in path: ` +\n      `${fullPath.join('.')}: ${typeof existing}`,\n    );\n  }\n  return existing as CSSRules;\n}\n\n/** Returns the own-property at `key` of `current`, or undefined when\n * `current` is not a non-null object or does not own the key. */\nfunction lookupChild(\n  current: CSSRulesValue | undefined,\n  key: string,\n): CSSRulesValue | undefined {\n  if (typeof current !== 'object' || current === null ||\n    !Object.prototype.hasOwnProperty.call(current, key)) {\n    return undefined;\n  }\n  return (current as CSSRules)[key];\n}\n\n/**\n * Sets a CSS rule object at a specified path within a target object,\n * merging with existing objects and creating intermediate objects as needed.\n *\n * This function allows for deep setting of CSS rules in a nested object\n * structure. It can handle both string paths for top-level assignments and\n * array paths for nested assignments. When the target path already contains\n * an object, the new object is merged with the existing one, with new values\n * taking precedence.\n *\n * The function is overloaded to provide type safety for both general\n * `CSSRules` objects and TailwindCSS-compatible `CSSRuleObject` types.\n *\n * @param target - The target CSS rules object to modify\n * @param path - Either a string key for direct assignment or an array of\n *   string keys for nested assignment\n * @param object - The CSS rule object to set at the specified path\n * @returns The modified target object (same type as input)\n * @remarks The target object is modified in place, returned reference is\n *   only a convenience.\n *\n * @example\n * ```\n * // Direct assignment\n * setDeepRule(rules, 'button', { color: 'blue' });\n * // Result: { button: { color: 'blue' } }\n *\n * // Nested assignment\n * setDeepRule(rules, ['components', 'button'], { color: 'blue' });\n * // Result: { components: { button: { color: 'blue' } } }\n *\n * // Merging with existing object (new values take precedence)\n * const rules = { button: { color: 'red', margin: '5px' } };\n * setDeepRule(rules, 'button', { color: 'blue', padding: '10px' });\n * // Result: { button: { color: 'blue', margin: '5px', padding: '10px' } }\n * ```\n */\nexport function setDeepRule(\n  target: CSSRuleObject,\n  path: string | string[],\n  object: CSSRuleObject,\n): CSSRuleObject;\nexport function setDeepRule(\n  target: CSSRules,\n  path: string | string[],\n  object: CSSRules,\n): CSSRules;\nexport function setDeepRule(\n  target: CSSRules,\n  path: string | string[],\n  object: CSSRules,\n): CSSRules {\n  let p: CSSRules = target;\n  let lastKey = '';\n\n  if (Array.isArray(path)) {\n    if (path.length === 0) return target;\n\n    for (const [i, k] of path.slice(0, -1).entries()) {\n      if (isUnsafeKey(k)) return target;\n      p = getOrCreateChild(p, k, i, path);\n    }\n\n    lastKey = path.at(-1) as string;\n  } else {\n    lastKey = path;\n  }\n\n  if (isUnsafeKey(lastKey)) return target;\n\n  p[lastKey] = defu(object, p[lastKey] ?? {} as typeof object);\n\n  return target;\n}\n\n/**\n * Retrieves a CSS rule value from a specified path within a target object.\n *\n * This function allows for deep retrieval of CSS rules from a nested object\n * structure. It can handle both string paths for top-level access and array\n * paths for nested access.\n *\n * The function is overloaded to provide type safety for both general\n * `CSSRules` objects and TailwindCSS-compatible `CSSRuleObject` types.\n *\n * @param target - The target CSS rules object to search within\n * @param path - Either a string key for direct access or an array of\n *   string keys for nested access\n * @returns The value at the specified path, or `undefined` if the path\n *   does not exist\n *\n * @example\n * ```\n * const rules = {\n *   components: { button: { color: 'blue' } },\n *   utils: ['clearfix', 'sr-only']\n * };\n *\n * // Direct access\n * getDeepRule(rules, 'utils');\n * // Result: ['clearfix', 'sr-only']\n *\n * // Nested access\n * getDeepRule(rules, ['components', 'button', 'color']);\n * // Result: 'blue'\n *\n * // Non-existent path\n * getDeepRule(rules, ['components', 'header']);\n * // Result: undefined\n *\n * // Root access (empty array)\n * getDeepRule(rules, []);\n * // Result: { components: { ... }, utils: [...] }\n * ```\n */\nexport function getDeepRule(\n  target: CSSRuleObject,\n  path: string | string[],\n): CSSRuleObject | undefined;\nexport function getDeepRule(\n  target: CSSRules,\n  path: string | string[],\n): CSSRulesValue | undefined;\nexport function getDeepRule(\n  target: CSSRules,\n  path: string | string[],\n): CSSRulesValue | undefined {\n  const segments = typeof path === 'string' ? [path] : path;\n\n  if (segments.length === 0) {\n    // Empty path returns the target object itself\n    return target;\n  }\n\n  let current: CSSRulesValue | undefined = target;\n  for (const key of segments) {\n    current = lookupChild(current, key);\n    if (current === undefined) return undefined;\n  }\n\n  return current;\n}\n","/**\n * Default selector aliases that expand simple names into complex at-rules\n */\nconst DEFAULT_SELECTOR_ALIASES: Record<string, string> = {\n  media: '@media (prefers-color-scheme: dark)',\n  dark: '@media (prefers-color-scheme: dark)',\n  light: '@media (prefers-color-scheme: light)',\n  mobile: '@media (max-width: 768px)',\n  tablet: '@media (min-width: 769px) and (max-width: 1024px)',\n  desktop: '@media (min-width: 1025px)',\n};\n\n/**\n * Expands selector aliases into their full forms\n * @param selector - The selector to potentially expand\n * @param aliases - Custom aliases to use (defaults to built-in ones)\n * @returns Expanded selector or original if no alias found\n */\nexport function expandSelectorAlias(\n  selector: string,\n  aliases: Record<string, string> = DEFAULT_SELECTOR_ALIASES,\n): string {\n  const trimmed = selector.trim();\n  return aliases[trimmed] || trimmed;\n}\n\nexport interface ProcessCSSSelectorOptions {\n  /** Whether to add \"selector *\" variants to each selector */\n  addStarVariants?: boolean\n  /** Custom selector aliases to use for expansion */\n  aliases?: Record<string, string>\n  /** Whether to allow comma-separated selectors to pass through */\n  allowCommaPassthrough?: boolean\n}\n\n/**\n * Processes CSS selectors and at-rules, handling both strings and arrays.\n * Merges consecutive selectors with OR and adds * variants,\n * while keeping at-rules stacked separately.\n *\n * @param selectors - CSS selector(s) and at-rules\n * @param options - Processing options\n * @returns Array of processed selector strings or undefined\n */\nexport function processCSSSelectors(\n  selectors: string | string[],\n  options: ProcessCSSSelectorOptions = {},\n): string[] | undefined {\n  const {\n    addStarVariants = true,\n    allowCommaPassthrough = true,\n    aliases = DEFAULT_SELECTOR_ALIASES,\n  } = options;\n\n  // Convert string to array for unified processing\n  const selectorArray = Array.isArray(selectors) ? selectors : [selectors];\n\n  // Handle comma pass-through for single strings\n  if (!Array.isArray(selectors) && allowCommaPassthrough && selectors.includes(',')) {\n    const expanded = expandSelectorAlias(selectors, aliases);\n    return [expanded];\n  }\n\n  const result: string[] = [];\n  const currentSelectors: string[] = [];\n\n  const flushSelectors = () => {\n    if (currentSelectors.length > 0) {\n      // Merge consecutive selectors with OR, optionally adding * variants\n      const expandedSelectors: string[] = [];\n      for (const selector of currentSelectors) {\n        expandedSelectors.push(selector);\n        if (addStarVariants) {\n          expandedSelectors.push(`${selector} *`);\n        }\n      }\n      result.push(expandedSelectors.join(', '));\n      currentSelectors.length = 0;\n    }\n  };\n\n  for (const s of selectorArray) {\n    const expanded = expandSelectorAlias(s, aliases);\n    const trimmed = expanded.trim();\n    if (!trimmed) continue;\n\n    if (trimmed.startsWith('@')) {\n      // At-rule: flush current selectors and add at-rule separately\n      flushSelectors();\n      result.push(trimmed);\n    } else {\n      // Regular selector: add to current batch\n      currentSelectors.push(trimmed);\n    }\n  }\n\n  // Flush any remaining selectors\n  flushSelectors();\n\n  return result.length === 0 ? undefined : result;\n}\n"],"mappings":";;;;;;;;;;;;;;SAoBO,UAAa,GAAA;;;;;;;;;;;;;SAqBX,uBACL,QAAU,SACT;;;;;;;;;;;EAcL,MAAA,iBAEE,eACmB,OAAA,CAAA,yBAAA,IAAA,SAAA,CAAA;EACnB,YAAW,IAAA,UAAY,eAAS;;OAE1B,QAAQ,EAAA;;;;SAmCV,eAAA,OAAyB,WAC3B,MAAO;CAGT,IAAA,MAAO,QAAA,MAAA,EAAA,OAAA,MAAA,KAAA,MAAA,OAAA,EAAA,CAAA,CAAA,KAAA,WAAA,OAAA,IAAA;;;;;;;;;;;;;;;;;;MAyBF,2BAAwB,IAC3B,IAAA;CAIF;CAGA;CAKA;CAQA;;;;;;;;;;;CCpHF;CAIE;CAQA;CAGA;CAKA;CAKA,CAAA;;;;;AASF,SAAgB,eAAA,QAAsC,EAAA,EAAA,UAAoC,EAAA,EAAA;CACxF,OAAM,CAAA,GAAA,iBAAA,OAAA,QAAkB,CAAA;;SAIhB,oBAAiB,QAAA,EAAA,EAAe,UADpB,EAAA,EAAA;QAElB,CAAA,GAAA,sBAA0B,OAAA,QAAe,CAAA;;SAItC,oBAAsB,KAAA,OACzB;CAEF,IAAA,QAAO,MAAA,UAAA,KAAA,KAAA,UAAA,MAAA,OAAA;;;;;;;;;;;;;GAgBT,MAAgB,GAAA,MAAA;GACd,eAAU;SAGH,IAAA,CAAA,cAAa;;;;;;;;;;;;;;SAeN,IAAA,CAAA,cAA4B;GAC1C,MAAI;kBAEc;;;;;;;;;;;;EAmBpB,IAAA,IAAiB,WAA6B,IAAA,IAAoD,IAAA,WAAA,IAAA,IAAA,IAAA,WAAA,IAAA,IAAA,IAAA,WAAA,IAAA,IAAA,IAAA,SAAA,IAAA,EAAA,OAAA;EAChG,OAAK,UAAY,IAAA;;;;;;;;;QAcnB;EACE,IAAI,aAAO;EAEX,MAAO,aAAO,EAAA;;;;;;;;;;;;;;;;GAiBhB,aAAa;;EAEX,IAAA,YAAA;GACA,MAAA,GAAA,SAAA,IAAA;GACA,KAAA,MAAA,QAAA,YAAA,MAAA;GACA,MAAA,GAAA,OAAA;;;;SAKA,iBAAA,OAAA;CACA,IAAA,MAAA,WAAA,GAAA,OAAA,EAAA;CACA,MAAA,OAAA,MAAA,SAAA,IAAA;CACA,MAAA,MAAA,MAAA,KAAA,EAAA,QAAA,MAAA,SAAA,EAAA,EAAA;CACA,IAAA,IAAA;CACA,KAAA,MAAA,SAAA,OAAA;EACA,IAAA,KAAA;EACA,KAAA;;CAEA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SChEE,YAAU,SACR,KAAA;CAEJ,IAAA,OAAO,YAAe,YAAO,YAAc,QAAQ,CAAA,OAAA,UAAA,eAAA,KAAA,SAAA,IAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmErD,MAAA,UAAgB,oBACiC,GAC/C,QAAA,CAAA,MACU;EACV,IAAA,CAAA,SAAW"}