async processStyle(style, document) {
    if (style.$$reduce === false) return;

    const name = style.$$name ? style.$$name.replace(/^\//, '') : 'inline CSS';
    const options = this.options;
    const crittersContainer = document.crittersContainer;
    let keyframesMode = options.keyframes || 'critical';
    // we also accept a boolean value for options.keyframes
    if (keyframesMode === true) keyframesMode = 'all';
    if (keyframesMode === false) keyframesMode = 'none';

    let sheet = style.textContent;

    // store a reference to the previous serialized stylesheet for reporting stats
    const before = sheet;

    // Skip empty stylesheets
    if (!sheet) return;

    const ast = parseStylesheet(sheet);
    const astInverse = options.pruneSource ? parseStylesheet(sheet) : null;

    // a string to search for font names (very loose)
    let criticalFonts = '';

    const failedSelectors = [];

    const criticalKeyframeNames = new Set();

    let includeNext = false;
    let includeAll = false;
    let excludeNext = false;
    let excludeAll = false;

    const shouldPreloadFonts =
      options.fonts === true || options.preloadFonts === true;
    const shouldInlineFonts =
      options.fonts !== false && options.inlineFonts === true;

    // Walk all CSS rules, marking unused rules with `.$$remove=true` for removal in the second pass.
    // This first pass is also used to collect font and keyframe usage used in the second pass.
    walkStyleRules(
      ast,
      markOnly((rule) => {
        if (rule.type === 'comment') {
          // we might want to remove a leading ! on comment blocks
          // critters can be part of "legal comments" which aren't striped on build
          const crittersComment = rule.text.match(/^(?<!\! )critters:(.*)/);
          const command = crittersComment && crittersComment[1];

          if (command) {
            switch (command) {
              case 'include':
                includeNext = true;
                break;
              case 'exclude':
                excludeNext = true;
                break;
              case 'include start':
                includeAll = true;
                break;
              case 'include end':
                includeAll = false;
                break;
              case 'exclude start':
                excludeAll = true;
                break;
              case 'exclude end':
                excludeAll = false;
                break;
            }
          }
        }

        if (rule.type === 'rule') {
          // Handle comment based markers
          if (includeNext) {
            includeNext = false;
            return true;
          }

          if (excludeNext) {
            excludeNext = false;
            return false;
          }

          if (includeAll) {
            return true;
          }

          if (excludeAll) {
            return false;
          }

          // Filter the selector list down to only those match
          rule.filterSelectors((sel) => {
            // Validate rule with 'allowRules' option
            const isAllowedRule = options.allowRules.some((exp) => {
              if (exp instanceof RegExp) {
                return exp.test(sel);
              }
              return exp === sel;
            });
            if (isAllowedRule) return true;

            // Strip pseudo-elements and pseudo-classes, since we only care that their associated elements exist.
            // This means any selector for a pseudo-element or having a pseudo-class will be inlined if the rest of the selector matches.
            if (
              sel === ':root' ||
              sel === 'html' ||
              sel === 'body' ||
              /^::?(before|after)$/.test(sel)
            ) {
              return true;
            }
            sel = sel
              .replace(/(?<!\\)::?[a-z-]+(?![a-z-(])/gi, '')
              .replace(/::?not\(\s*\)/g, '')
              // Remove tailing or leading commas from cleaned sub selector `is(.active, :hover)` -> `is(.active)`.
              .replace(/\(\s*,/g, '(')
              .replace(/,\s*\)/g, ')')
              .trim();
            if (!sel) return false;

            try {
              return crittersContainer.exists(sel);
            } catch (e) {
              failedSelectors.push(sel + ' -> ' + e.message);
              return false;
            }
          });

          // If there are no matched selectors, remove the rule:
          if (!rule.selector) {
            return false;
          }

          if (rule.nodes) {
            for (const decl of rule.nodes) {
              // detect used fonts
              if (
                shouldInlineFonts &&
                decl.prop &&
                /\bfont(-family)?\b/i.test(decl.prop)
              ) {
                criticalFonts += ' ' + decl.value;
              }

              // detect used keyframes
              if (decl.prop === 'animation' || decl.prop === 'animation-name') {
                for (const name of decl.value.split(/\s+/)) {
                  // @todo: parse animation declarations and extract only the name. for now we'll do a lazy match.
                  const nameTrimmed = name.trim();
                  if (nameTrimmed) criticalKeyframeNames.add(nameTrimmed);
                }
              }
            }
          }
        }

        // keep font rules, they're handled in the second pass:
        if (rule.type === 'atrule' && rule.name === 'font-face') return;

        // If there are no remaining rules, remove the whole rule:
        const rules = rule.nodes?.filter((rule) => !rule.$$remove);
        return !rules || rules.length !== 0;
      })
    );

    if (failedSelectors.length !== 0) {
      this.logger.warn(
        `${
          failedSelectors.length
        } rules skipped due to selector errors:\n  ${failedSelectors.join(
          '\n  '
        )}`
      );
    }

    const preloadedFonts = new Set();
    // Second pass, using data picked up from the first
    walkStyleRulesWithReverseMirror(ast, astInverse, (rule) => {
      // remove any rules marked in the first pass
      if (rule.$$remove === true) return false;

      applyMarkedSelectors(rule);

      // prune @keyframes rules
      if (rule.type === 'atrule' && rule.name === 'keyframes') {
        if (keyframesMode === 'none') return false;
        if (keyframesMode === 'all') return true;
        return criticalKeyframeNames.has(rule.params);
      }

      // prune @font-face rules
      if (rule.type === 'atrule' && rule.name === 'font-face') {
        let family, src;
        for (const decl of rule.nodes) {
          if (decl.prop === 'src') {
            // @todo parse this properly and generate multiple preloads with type="font/woff2" etc
            src = (decl.value.match(/url\s*\(\s*(['"]?)(.+?)\1\s*\)/) || [])[2];
          } else if (decl.prop === 'font-family') {
            family = decl.value;
          }
        }

        if (src && shouldPreloadFonts && !preloadedFonts.has(src)) {
          preloadedFonts.add(src);
          const preload = document.createElement('link');
          preload.setAttribute('rel', 'preload');
          preload.setAttribute('as', 'font');
          preload.setAttribute('crossorigin', 'anonymous');
          preload.setAttribute('href', src.trim());
          document.head.appendChild(preload);
        }

        // if we're missing info, if the font is unused, or if critical font inlining is disabled, remove the rule:
        if (
          !shouldInlineFonts ||
          !family ||
          !src ||
          !criticalFonts.includes(family)
        ) {
          return false;
        }
      }
    });

    sheet = serializeStylesheet(ast, {
      compress: this.options.compress !== false
    });

    // If all rules were removed, get rid of the style element entirely
    if (sheet.trim().length === 0) {
      if (style.parentNode) {
        style.remove();
      }
      return;
    }

    let afterText = '';
    let styleInlinedCompletely = false;
    if (options.pruneSource) {
      const sheetInverse = serializeStylesheet(astInverse, {
        compress: this.options.compress !== false
      });

      styleInlinedCompletely = this.pruneSource(style, before, sheetInverse);

      if (styleInlinedCompletely) {
        const percent = (sheetInverse.length / before.length) * 100;
        afterText = `, reducing non-inlined size ${
          percent | 0
        }% to ${formatSize(sheetInverse.length)}`;
      }
    }

    // replace the inline stylesheet with its critical'd counterpart
    if (!styleInlinedCompletely) {
      style.textContent = sheet;
    }

    // output stats
    const percent = ((sheet.length / before.length) * 100) | 0;
    this.logger.info(
      '\u001b[32mInlined ' +
        formatSize(sheet.length) +
        ' (' +
        percent +
        '% of original ' +
        formatSize(before.length) +
        ') of ' +
        name +
        afterText +
        '.\u001b[39m'
    );
  }
Parse the stylesheet within a <style> element, then reduce it to contain only rules used by the document.