{"version":3,"file":"critical-css.mjs","sources":["../../../src/lib/performance/critical-css.ts"],"sourcesContent":["/**\n * @file Critical CSS System\n * @description PhD-level critical CSS extraction and inline injection for optimal\n * LCP and first contentful paint performance.\n *\n * Features:\n * - Automatic critical CSS extraction\n * - Inline injection with deferred loading\n * - Route-based critical CSS splitting\n * - LCP element optimization\n * - CSS containment automation\n * - Font preloading coordination\n */\n\nimport type React from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Critical CSS configuration\n */\nexport interface CriticalCSSConfig {\n  /** Viewport height for critical path (default: 100vh) */\n  viewportHeight?: number;\n  /** Enable automatic extraction */\n  autoExtract?: boolean;\n  /** Cache extracted CSS */\n  cacheCSS?: boolean;\n  /** Route patterns for route-specific CSS */\n  routePatterns?: Record<string, string[]>;\n  /** Enable debug logging */\n  debug?: boolean;\n}\n\n/**\n * CSS rule classification\n */\nexport type CSSRuleType = 'critical' | 'above-fold' | 'deferred' | 'unused';\n\n/**\n * Analyzed CSS rule\n */\nexport interface AnalyzedCSSRule {\n  /** CSS selector */\n  selector: string;\n  /** CSS declarations */\n  declarations: string;\n  /** Full rule text */\n  ruleText: string;\n  /** Classification */\n  type: CSSRuleType;\n  /** Specificity score */\n  specificity: number;\n  /** Source stylesheet */\n  source?: string;\n}\n\n/**\n * Critical CSS result\n */\nexport interface CriticalCSSResult {\n  /** Critical CSS for immediate inline */\n  critical: string;\n  /** Above-fold CSS (important but can be slightly deferred) */\n  aboveFold: string;\n  /** Deferred CSS (load async) */\n  deferred: string;\n  /** Unused CSS (can be removed) */\n  unused: string;\n  /** LCP element styles */\n  lcpStyles: string;\n  /** Font preload hints */\n  fontPreloads: string[];\n  /** Extraction timestamp */\n  timestamp: number;\n}\n\n/**\n * Font resource\n */\nexport interface FontResource {\n  /** Font family */\n  family: string;\n  /** Font URL */\n  url: string;\n  /** Font weight */\n  weight?: string;\n  /** Font style */\n  style?: string;\n  /** Unicode range */\n  unicodeRange?: string;\n  /** Format */\n  format?: string;\n}\n\n/**\n * CSS containment options\n */\nexport interface ContainmentOptions {\n  /** Layout containment */\n  layout?: boolean;\n  /** Paint containment */\n  paint?: boolean;\n  /** Size containment */\n  size?: boolean;\n  /** Style containment */\n  style?: boolean;\n  /** Content visibility */\n  contentVisibility?: 'auto' | 'hidden' | 'visible';\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_VIEWPORT_HEIGHT = 800;\n\nconst CRITICAL_SELECTORS = [\n  'html',\n  'body',\n  ':root',\n  '[data-critical]',\n  '[data-lcp]',\n  '.hero',\n  '.header',\n  '.nav',\n  '.logo',\n  'h1',\n  '.headline',\n];\n\nconst DEFERRED_PATTERNS = [\n  /footer/i,\n  /modal/i,\n  /tooltip/i,\n  /dropdown/i,\n  /sidebar/i,\n  /drawer/i,\n  /dialog/i,\n  /@media\\s+print/,\n];\n\n// ============================================================================\n// RegExp Pattern Cache\n// ============================================================================\n\n/**\n * Cache for compiled RegExp patterns to avoid creating new RegExp objects\n * on every call to isCriticalSelector\n */\nconst patternCache = new Map<string, RegExp>();\n\n/**\n * Get or create a cached RegExp pattern\n */\nfunction getCachedPattern(pattern: string, flags: string = 'i'): RegExp {\n  const cacheKey = `${pattern}:${flags}`;\n  let cached = patternCache.get(cacheKey);\n\n  if (!cached) {\n    cached = new RegExp(pattern, flags);\n    patternCache.set(cacheKey, cached);\n  }\n\n  return cached;\n}\n\n// Pre-compile critical selector patterns at module load time\nconst CRITICAL_SELECTOR_PATTERNS = CRITICAL_SELECTORS.map((pattern) =>\n  getCachedPattern(pattern, 'i')\n);\n\n// ============================================================================\n// CSS Analyzer\n// ============================================================================\n\n/**\n * Analyzes and classifies CSS rules\n */\nclass CSSAnalyzer {\n  private readonly viewportHeight: number;\n  // private __analyzedRules: Map<string, AnalyzedCSSRule> = new Map();\n  private aboveFoldElements: Set<Element> = new Set();\n\n  constructor(viewportHeight: number = DEFAULT_VIEWPORT_HEIGHT) {\n    this.viewportHeight = viewportHeight;\n  }\n\n  /**\n   * Analyze all stylesheets\n   */\n  analyzeStylesheets(): AnalyzedCSSRule[] {\n    this.collectAboveFoldElements();\n    const rules: AnalyzedCSSRule[] = [];\n\n    // Analyze all stylesheets\n    Array.from(document.styleSheets).forEach((stylesheet) => {\n      try {\n        const cssRules = stylesheet.cssRules ?? stylesheet.rules;\n        if (cssRules == null) return;\n\n        Array.from(cssRules).forEach((rule) => {\n          const analyzed = this.analyzeRule(rule, stylesheet.href ?? 'inline');\n          if (analyzed != null) {\n            rules.push(...analyzed);\n          }\n        });\n      } catch {\n        // CORS blocked stylesheet - skip\n      }\n    });\n\n    return rules;\n  }\n\n  /**\n   * Collect elements above the fold\n   */\n  private collectAboveFoldElements(): void {\n    this.aboveFoldElements.clear();\n\n    const walker = document.createTreeWalker(\n      document.body,\n      NodeFilter.SHOW_ELEMENT,\n      null\n    );\n\n    let node: Node | null;\n    while ((node = walker.nextNode())) {\n      const element = node as Element;\n      const rect = element.getBoundingClientRect();\n\n      // Element is above the fold if any part is visible\n      if (rect.top < this.viewportHeight) {\n        this.aboveFoldElements.add(element);\n      }\n    }\n  }\n\n  /**\n   * Analyze a single CSS rule\n   */\n  private analyzeRule(rule: CSSRule, source: string): AnalyzedCSSRule[] | null {\n    if (rule instanceof CSSStyleRule) {\n      return [this.analyzeStyleRule(rule, source)];\n    }\n\n    if (rule instanceof CSSMediaRule) {\n      return this.analyzeMediaRule(rule, source);\n    }\n\n    if (rule instanceof CSSKeyframesRule) {\n      // Keyframes are deferred unless used by critical elements\n      return [{\n        selector: `@keyframes ${rule.name}`,\n        declarations: rule.cssText,\n        ruleText: rule.cssText,\n        type: 'deferred',\n        specificity: 0,\n        source,\n      }];\n    }\n\n    if (rule instanceof CSSFontFaceRule) {\n      // Font-face rules are critical if font is used above fold\n      return [{\n        selector: '@font-face',\n        declarations: rule.cssText,\n        ruleText: rule.cssText,\n        type: this.isFontUsedAboveFold(rule) ? 'critical' : 'deferred',\n        specificity: 0,\n        source,\n      }];\n    }\n\n    return null;\n  }\n\n  /**\n   * Analyze style rule\n   */\n  private analyzeStyleRule(rule: CSSStyleRule, source: string): AnalyzedCSSRule {\n    const selector = rule.selectorText;\n    const declarations = rule.style.cssText;\n    const ruleText = rule.cssText;\n    const specificity = this.calculateSpecificity(selector);\n\n    // Determine rule type\n    let type: CSSRuleType = 'unused';\n\n    if (this.isCriticalSelector(selector)) {\n      type = 'critical';\n    } else if (this.isDeferredSelector(selector)) {\n      type = 'deferred';\n    } else if (this.matchesAboveFoldElement(selector)) {\n      type = 'above-fold';\n    }\n\n    return { selector, declarations, ruleText, type, specificity, source };\n  }\n\n  /**\n   * Analyze media rule\n   */\n  private analyzeMediaRule(rule: CSSMediaRule, source: string): AnalyzedCSSRule[] {\n    const mediaCondition = rule.conditionText;\n\n    // Print media is always deferred\n    if (mediaCondition.includes('print')) {\n      return [{\n        selector: `@media ${mediaCondition}`,\n        declarations: rule.cssText,\n        ruleText: rule.cssText,\n        type: 'deferred',\n        specificity: 0,\n        source,\n      }];\n    }\n\n    // Check if media query matches current viewport\n    if (!window.matchMedia(mediaCondition).matches) {\n      return [{\n        selector: `@media ${mediaCondition}`,\n        declarations: rule.cssText,\n        ruleText: rule.cssText,\n        type: 'deferred',\n        specificity: 0,\n        source,\n      }];\n    }\n\n    // Analyze inner rules\n    const innerRules: AnalyzedCSSRule[] = [];\n    Array.from(rule.cssRules).forEach((innerRule) => {\n      const analyzed = this.analyzeRule(innerRule, source);\n      if (analyzed) {\n        innerRules.push(...analyzed);\n      }\n    });\n\n    return innerRules;\n  }\n\n  /**\n   * Check if selector matches critical patterns\n   * Uses pre-compiled RegExp patterns from cache for performance\n   */\n  private isCriticalSelector(selector: string): boolean {\n    return CRITICAL_SELECTORS.some((pattern, index) => {\n      const regexPattern = CRITICAL_SELECTOR_PATTERNS[index];\n      return selector.includes(pattern) || regexPattern?.test(selector) === true;\n    });\n  }\n\n  /**\n   * Check if selector matches deferred patterns\n   */\n  private isDeferredSelector(selector: string): boolean {\n    return DEFERRED_PATTERNS.some((pattern) => pattern.test(selector));\n  }\n\n  /**\n   * Check if selector matches above-fold elements\n   */\n  private matchesAboveFoldElement(selector: string): boolean {\n    try {\n      for (const element of this.aboveFoldElements) {\n        if (element.matches(selector)) {\n          return true;\n        }\n      }\n    } catch {\n      // Invalid selector\n    }\n    return false;\n  }\n\n  /**\n   * Check if font is used above fold\n   */\n  private isFontUsedAboveFold(rule: CSSFontFaceRule): boolean {\n    const fontFamily = rule.style.getPropertyValue('font-family').replace(/[\"']/g, '');\n\n    for (const element of this.aboveFoldElements) {\n      const computedFont = window.getComputedStyle(element).fontFamily;\n      if (computedFont.includes(fontFamily)) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  /**\n   * Calculate specificity score\n   */\n  private calculateSpecificity(selector: string): number {\n    let score = 0;\n\n    // IDs\n    const ids = (selector.match(/#[a-zA-Z][\\w-]*/g) ?? []).length;\n    score += ids * 100;\n\n    // Classes, attributes, pseudo-classes\n    const classes = (selector.match(/\\.[a-zA-Z][\\w-]*/g) ?? []).length;\n    const attrs = (selector.match(/\\[[^\\]]+\\]/g) ?? []).length;\n    const pseudoClasses = (selector.match(/:[a-zA-Z][\\w-]*/g) ?? []).length;\n    score += (classes + attrs + pseudoClasses) * 10;\n\n    // Elements, pseudo-elements\n    const elements = (selector.match(/(?:^|\\s)[a-zA-Z][\\w-]*/g) ?? []).length;\n    const pseudoElements = (selector.match(/::[a-zA-Z][\\w-]*/g) ?? []).length;\n    score += elements + pseudoElements;\n\n    return score;\n  }\n}\n\n// ============================================================================\n// Critical CSS Extractor\n// ============================================================================\n\n/**\n * Extracts and categorizes critical CSS\n */\nexport class CriticalCSSExtractor {\n  private static instance: CriticalCSSExtractor;\n  private config: Required<CriticalCSSConfig>;\n  private analyzer: CSSAnalyzer;\n  private cache: Map<string, CriticalCSSResult> = new Map();\n\n  constructor(config: CriticalCSSConfig = {}) {\n    this.config = {\n      viewportHeight: config.viewportHeight ?? DEFAULT_VIEWPORT_HEIGHT,\n      autoExtract: config.autoExtract ?? false,\n      cacheCSS: config.cacheCSS ?? true,\n      routePatterns: config.routePatterns ?? {},\n      debug: config.debug ?? false,\n    };\n\n    this.analyzer = new CSSAnalyzer(this.config.viewportHeight);\n  }\n\n  /**\n   * Get singleton instance\n   */\n  static getInstance(config?: CriticalCSSConfig): CriticalCSSExtractor {\n    CriticalCSSExtractor.instance ??= new CriticalCSSExtractor(config);\n    return CriticalCSSExtractor.instance;\n  }\n\n  /**\n   * Reset singleton (for testing)\n   */\n  static reset(): void {\n    // Type-safe null assignment for singleton reset\n    (CriticalCSSExtractor as unknown as { instance: CriticalCSSExtractor | null }).instance = null;\n  }\n\n  /**\n   * Extract critical CSS\n   */\n  extract(routePath?: string): CriticalCSSResult {\n    const cacheKey = routePath ?? window.location.pathname;\n\n    // Check cache\n    if (this.config.cacheCSS && this.cache.has(cacheKey)) {\n      const cached = this.cache.get(cacheKey);\n      if (cached != null) return cached;\n    }\n\n    this.log('Extracting critical CSS...');\n\n    const rules = this.analyzer.analyzeStylesheets();\n\n    // Group rules by type\n    const criticalRules: string[] = [];\n    const aboveFoldRules: string[] = [];\n    const deferredRules: string[] = [];\n    const unusedRules: string[] = [];\n\n    rules.forEach((rule) => {\n      switch (rule.type) {\n        case 'critical':\n          criticalRules.push(rule.ruleText);\n          break;\n        case 'above-fold':\n          aboveFoldRules.push(rule.ruleText);\n          break;\n        case 'deferred':\n          deferredRules.push(rule.ruleText);\n          break;\n        case 'unused':\n          unusedRules.push(rule.ruleText);\n          break;\n      }\n    });\n\n    // Extract LCP element styles\n    const lcpStyles = this.extractLCPStyles();\n\n    // Extract font preloads\n    const fontPreloads = this.extractFontPreloads(rules);\n\n    const result: CriticalCSSResult = {\n      critical: this.minifyCSS(criticalRules.join('\\n')),\n      aboveFold: this.minifyCSS(aboveFoldRules.join('\\n')),\n      deferred: this.minifyCSS(deferredRules.join('\\n')),\n      unused: this.minifyCSS(unusedRules.join('\\n')),\n      lcpStyles: this.minifyCSS(lcpStyles),\n      fontPreloads,\n      timestamp: Date.now(),\n    };\n\n    // Cache result\n    if (this.config.cacheCSS) {\n      this.cache.set(cacheKey, result);\n    }\n\n    this.log('Critical CSS extraction complete', {\n      critical: result.critical.length,\n      aboveFold: result.aboveFold.length,\n      deferred: result.deferred.length,\n      unused: result.unused.length,\n    });\n\n    return result;\n  }\n\n  /**\n   * Clear cache\n   */\n  clearCache(): void {\n    this.cache.clear();\n  }\n\n  /**\n   * Extract LCP element styles\n   */\n  private extractLCPStyles(): string {\n    // Find potential LCP elements\n    const lcpCandidates = document.querySelectorAll(\n      'img[data-lcp], video[data-lcp], [data-lcp], h1, .hero img, .hero video'\n    );\n\n    const styles: string[] = [];\n\n    lcpCandidates.forEach((element) => {\n      const computedStyle = window.getComputedStyle(element);\n      const relevantProps = [\n        'width',\n        'height',\n        'max-width',\n        'max-height',\n        'aspect-ratio',\n        'object-fit',\n        'object-position',\n        'display',\n        'position',\n        'top',\n        'left',\n        'right',\n        'bottom',\n        'margin',\n        'padding',\n      ];\n\n      const selector = this.generateSelector(element);\n      const declarations = relevantProps\n        .map((prop) => `${prop}: ${computedStyle.getPropertyValue(prop)}`)\n        .filter((d) => !d.endsWith(': '))\n        .join('; ');\n\n      if (declarations) {\n        styles.push(`${selector} { ${declarations} }`);\n      }\n    });\n\n    return styles.join('\\n');\n  }\n\n  /**\n   * Generate unique selector for element\n   */\n  private generateSelector(element: Element): string {\n    if (element.id) {\n      return `#${element.id}`;\n    }\n\n    if (element.className) {\n      const classes = Array.from(element.classList).join('.');\n      return `${element.tagName.toLowerCase()}.${classes}`;\n    }\n\n    return element.tagName.toLowerCase();\n  }\n\n  /**\n   * Extract font preload URLs\n   */\n  private extractFontPreloads(rules: AnalyzedCSSRule[]): string[] {\n    const fontUrls: string[] = [];\n\n    rules.forEach((rule) => {\n      if (rule.type === 'critical' && rule.selector === '@font-face') {\n        const urlMatch = rule.declarations.match(/url\\(['\"]?([^'\")\\s]+)['\"]?\\)/);\n        const matchedUrl = urlMatch?.[1];\n        if (matchedUrl != null && matchedUrl !== '') {\n          fontUrls.push(matchedUrl);\n        }\n      }\n    });\n\n    return fontUrls;\n  }\n\n  /**\n   * Minify CSS (simple minification)\n   */\n  private minifyCSS(css: string): string {\n    return css\n      .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Remove comments\n      .replace(/\\s+/g, ' ') // Collapse whitespace\n      .replace(/\\s*([{}:;,])\\s*/g, '$1') // Remove space around symbols\n      .replace(/;}/g, '}') // Remove trailing semicolons\n      .trim();\n  }\n\n  /**\n   * Debug logging\n   */\n  private log(message: string, ...args: unknown[]): void {\n    if (this.config.debug) {\n      // eslint-disable-next-line no-console\n      console.log(`[CriticalCSS] ${message}`, ...args);\n    }\n  }\n}\n\n// ============================================================================\n// CSS Injection Utilities\n// ============================================================================\n\n/**\n * Inject critical CSS inline\n */\nexport function injectCriticalCSS(css: string, id = 'critical-css'): HTMLStyleElement {\n  const existing = document.getElementById(id) as HTMLStyleElement | null;\n  if (existing != null) {\n    existing.textContent = css;\n    return existing;\n  }\n\n  const style = document.createElement('style');\n  style.id = id;\n  style.textContent = css;\n\n  // Insert at the top of head for highest priority\n  const {head} = document;\n  const {firstChild} = head;\n  if (firstChild) {\n    head.insertBefore(style, firstChild);\n  } else {\n    head.appendChild(style);\n  }\n\n  return style;\n}\n\n/**\n * Load CSS asynchronously\n */\nexport async function loadCSSAsync(href: string, id?: string): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const link = document.createElement('link');\n    link.rel = 'stylesheet';\n    link.href = href;\n    if (id != null && id !== '') link.id = id;\n\n    link.onload = () => resolve();\n    link.onerror = () => reject(new Error(`Failed to load CSS: ${href}`));\n\n    document.head.appendChild(link);\n  });\n}\n\n/**\n * Preload font\n */\nexport function preloadFont(url: string, crossOrigin = true): HTMLLinkElement {\n  const link = document.createElement('link');\n  link.rel = 'preload';\n  link.as = 'font';\n  link.href = url;\n  link.type = 'font/woff2';\n  if (crossOrigin) {\n    link.crossOrigin = 'anonymous';\n  }\n\n  document.head.appendChild(link);\n  return link;\n}\n\n/**\n * Apply CSS containment to element\n */\nexport function applyContainment(element: HTMLElement, options: ContainmentOptions): void {\n  const containValues: string[] = [];\n\n  if (options.layout === true) containValues.push('layout');\n  if (options.paint === true) containValues.push('paint');\n  if (options.size === true) containValues.push('size');\n  if (options.style === true) containValues.push('style');\n\n  if (containValues.length > 0) {\n    element.style.contain = containValues.join(' ');\n  }\n\n  if (options.contentVisibility) {\n    element.style.contentVisibility = options.contentVisibility;\n  }\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Hook for critical CSS extraction and injection\n */\nexport function useCriticalCSS(config?: CriticalCSSConfig): {\n  result: CriticalCSSResult | null;\n  extract: () => CriticalCSSResult;\n  inject: () => void;\n  isExtracted: boolean;\n} {\n  const extractor = useRef(CriticalCSSExtractor.getInstance(config));\n  const [result, setResult] = useState<CriticalCSSResult | null>(null);\n  const [isExtracted, setIsExtracted] = useState(false);\n\n  const extract = useCallback(() => {\n    const extracted = extractor.current.extract();\n    setResult(extracted);\n    setIsExtracted(true);\n    return extracted;\n  }, []);\n\n  const inject = useCallback(() => {\n    if (result) {\n      injectCriticalCSS(result.critical);\n      result.fontPreloads.forEach((url) => preloadFont(url));\n    }\n  }, [result]);\n\n  return { result, extract, inject, isExtracted };\n}\n\n/**\n * Hook for CSS containment\n */\nexport function useCSSContainment(\n  options: ContainmentOptions = {}\n): React.RefObject<HTMLDivElement | null> {\n  const ref = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    if (ref.current) {\n      applyContainment(ref.current, options);\n    }\n  }, [options]);\n\n  return ref;\n}\n\n/**\n * Hook for deferred CSS loading\n */\nexport function useDeferredCSS(\n  stylesheets: string[],\n  options: { loadOnIdle?: boolean } = {}\n): { loaded: boolean; load: () => Promise<void> } {\n  const { loadOnIdle = true } = options;\n  const [loaded, setLoaded] = useState(false);\n\n  const load = useCallback(async () => {\n    await Promise.all(stylesheets.map(async (href) => loadCSSAsync(href)));\n    setLoaded(true);\n  }, [stylesheets]);\n\n  useEffect(() => {\n    if (!loadOnIdle || loaded) return;\n\n    if (typeof requestIdleCallback !== 'undefined') {\n      const id = requestIdleCallback(() => {\n        void load();\n      });\n      return () => cancelIdleCallback(id);\n    } else {\n      const id = setTimeout(() => {\n        void load();\n      }, 100);\n      return () => clearTimeout(id);\n    }\n  }, [load, loadOnIdle, loaded]);\n\n  return { loaded, load };\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Get the global critical CSS extractor\n */\nexport function getCriticalCSSExtractor(config?: CriticalCSSConfig): CriticalCSSExtractor {\n  return CriticalCSSExtractor.getInstance(config);\n}\n\n/**\n * Reset the extractor (for testing)\n */\nexport function resetCriticalCSSExtractor(): void {\n  CriticalCSSExtractor.reset();\n}\n\n/**\n * Extract and inject critical CSS in one call\n */\nexport function extractAndInjectCriticalCSS(config?: CriticalCSSConfig): CriticalCSSResult {\n  const extractor = CriticalCSSExtractor.getInstance(config);\n  const result = extractor.extract();\n\n  injectCriticalCSS(result.critical);\n  result.fontPreloads.forEach((url) => preloadFont(url));\n\n  return result;\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport default {\n  CriticalCSSExtractor,\n  getCriticalCSSExtractor,\n  resetCriticalCSSExtractor,\n  extractAndInjectCriticalCSS,\n  injectCriticalCSS,\n  loadCSSAsync,\n  preloadFont,\n  applyContainment,\n  useCriticalCSS,\n  useCSSContainment,\n  useDeferredCSS,\n};\n"],"names":["DEFAULT_VIEWPORT_HEIGHT","CRITICAL_SELECTORS","DEFERRED_PATTERNS","patternCache","getCachedPattern","pattern","flags","cacheKey","cached","CRITICAL_SELECTOR_PATTERNS","CSSAnalyzer","viewportHeight","rules","stylesheet","cssRules","rule","analyzed","walker","node","element","source","selector","declarations","ruleText","specificity","type","mediaCondition","innerRules","innerRule","index","regexPattern","fontFamily","score","ids","classes","attrs","pseudoClasses","elements","pseudoElements","CriticalCSSExtractor","config","routePath","criticalRules","aboveFoldRules","deferredRules","unusedRules","lcpStyles","fontPreloads","result","lcpCandidates","styles","computedStyle","relevantProps","prop","d","fontUrls","matchedUrl","css","message","args","injectCriticalCSS","id","existing","style","head","firstChild","loadCSSAsync","href","resolve","reject","link","preloadFont","url","crossOrigin","applyContainment","options","containValues","useCriticalCSS","extractor","useRef","setResult","useState","isExtracted","setIsExtracted","extract","useCallback","extracted","inject","useCSSContainment","ref","useEffect","useDeferredCSS","stylesheets","loadOnIdle","loaded","setLoaded","load","getCriticalCSSExtractor","resetCriticalCSSExtractor","extractAndInjectCriticalCSS"],"mappings":"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"}