Index: trip-planner-front/node_modules/critters/src/css.js
===================================================================
--- trip-planner-front/node_modules/critters/src/css.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/critters/src/css.js	(revision b73803523f0488ec52498c2ba88889f1642ad263)
@@ -15,27 +15,61 @@
  */
 
-import css from 'css';
+import { parse, stringify } from 'postcss';
 
 /**
  * Parse a textual CSS Stylesheet into a Stylesheet instance.
- * Stylesheet is a mutable ReworkCSS AST with format similar to CSSOM.
- * @see https://github.com/reworkcss/css
+ * Stylesheet is a mutable postcss AST with format similar to CSSOM.
+ * @see https://github.com/postcss/postcss/
  * @private
  * @param {String} stylesheet
  * @returns {css.Stylesheet} ast
  */
-export function parseStylesheet (stylesheet) {
-  return css.parse(stylesheet);
+export function parseStylesheet(stylesheet) {
+  return parse(stylesheet);
 }
 
 /**
- * Serialize a ReworkCSS Stylesheet to a String of CSS.
+ * Serialize a postcss Stylesheet to a String of CSS.
  * @private
  * @param {css.Stylesheet} ast          A Stylesheet to serialize, such as one returned from `parseStylesheet()`
- * @param {Object} options              Options to pass to `css.stringify()`
+ * @param {Object} options              Options used by the stringify logic
  * @param {Boolean} [options.compress]  Compress CSS output (removes comments, whitespace, etc)
  */
-export function serializeStylesheet (ast, options) {
-  return css.stringify(ast, options);
+export function serializeStylesheet(ast, options) {
+  let cssStr = '';
+
+  stringify(ast, (result, node, type) => {
+    if (!options.compress) {
+      cssStr += result;
+      return;
+    }
+
+    // Simple minification logic
+    if (node?.type === 'comment') return;
+
+    if (node?.type === 'decl') {
+      const prefix = node.prop + node.raws.between;
+
+      cssStr += result.replace(prefix, prefix.trim());
+      return;
+    }
+
+    if (type === 'start') {
+      if (node.type === 'rule' && node.selectors) {
+        cssStr += node.selectors.join(',') + '{';
+      } else {
+        cssStr += result.replace(/\s\{$/, '{');
+      }
+      return;
+    }
+
+    if (type === 'end' && result === '}' && node?.raws?.semicolon) {
+      cssStr = cssStr.slice(0, -1);
+    }
+
+    cssStr += result.trim();
+  });
+
+  return cssStr;
 }
 
@@ -47,6 +81,6 @@
  * @returns {(rule) => void} nonDestructiveIterator
  */
-export function markOnly (predicate) {
-  return rule => {
+export function markOnly(predicate) {
+  return (rule) => {
     const sel = rule.selectors;
     if (predicate(rule) === false) {
@@ -65,6 +99,6 @@
  * @private
  * @param {css.Rule} rule The Rule to apply marked selectors to (if they exist).
-*/
-export function applyMarkedSelectors (rule) {
+ */
+export function applyMarkedSelectors(rule) {
   if (rule.$$markedSelectors) {
     rule.selectors = rule.$$markedSelectors;
@@ -81,9 +115,7 @@
  * @param {Function} iterator   Invoked on each node in the tree. Return `false` to remove that node.
  */
-export function walkStyleRules (node, iterator) {
-  if (node.stylesheet) return walkStyleRules(node.stylesheet, iterator);
-
-  node.rules = node.rules.filter(rule => {
-    if (rule.rules) {
+export function walkStyleRules(node, iterator) {
+  node.nodes = node.nodes.filter((rule) => {
+    if (hasNestedRules(rule)) {
       walkStyleRules(rule, iterator);
     }
@@ -101,23 +133,36 @@
  * @param {Function} iterator   Invoked on each node in the tree. Return `false` to remove that node from the first tree, true to remove it from the second.
  */
-export function walkStyleRulesWithReverseMirror (node, node2, iterator) {
+export function walkStyleRulesWithReverseMirror(node, node2, iterator) {
   if (node2 === null) return walkStyleRules(node, iterator);
 
-  if (node.stylesheet) return walkStyleRulesWithReverseMirror(node.stylesheet, node2.stylesheet, iterator);
+  [node.nodes, node2.nodes] = splitFilter(
+    node.nodes,
+    node2.nodes,
+    (rule, index, rules, rules2) => {
+      const rule2 = rules2[index];
+      if (hasNestedRules(rule)) {
+        walkStyleRulesWithReverseMirror(rule, rule2, iterator);
+      }
+      rule._other = rule2;
+      rule.filterSelectors = filterSelectors;
+      return iterator(rule) !== false;
+    }
+  );
+}
 
-  [node.rules, node2.rules] = splitFilter(node.rules, node2.rules, (rule, index, rules, rules2) => {
-    const rule2 = rules2[index];
-    if (rule.rules) {
-      walkStyleRulesWithReverseMirror(rule, rule2, iterator);
-    }
-    rule._other = rule2;
-    rule.filterSelectors = filterSelectors;
-    return iterator(rule) !== false;
-  });
+// Checks if a node has nested rules, like @media
+// @keyframes are an exception since they are evaluated as a whole
+function hasNestedRules(rule) {
+  return (
+    rule.nodes &&
+    rule.nodes.length &&
+    rule.nodes.some((n) => n.type === 'rule' || n.type === 'atrule') &&
+    rule.name !== 'keyframes'
+  );
 }
 
 // Like [].filter(), but applies the opposite filtering result to a second copy of the Array without a second pass.
 // This is just a quicker version of generating the compliment of the set returned from a filter operation.
-function splitFilter (a, b, predicate) {
+function splitFilter(a, b, predicate) {
   const aOut = [];
   const bOut = [];
@@ -133,7 +178,11 @@
 
 // can be invoked on a style rule to subset its selectors (with reverse mirroring)
-function filterSelectors (predicate) {
+function filterSelectors(predicate) {
   if (this._other) {
-    const [a, b] = splitFilter(this.selectors, this._other.selectors, predicate);
+    const [a, b] = splitFilter(
+      this.selectors,
+      this._other.selectors,
+      predicate
+    );
     this.selectors = a;
     this._other.selectors = b;
Index: trip-planner-front/node_modules/critters/src/dom.js
===================================================================
--- trip-planner-front/node_modules/critters/src/dom.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/critters/src/dom.js	(revision b73803523f0488ec52498c2ba88889f1642ad263)
@@ -16,9 +16,8 @@
 
 import parse5 from 'parse5';
-import select from 'css-select';
+import { selectAll, selectOne } from 'css-select';
+import treeAdapter from 'parse5-htmlparser2-tree-adapter';
 
 // htmlparser2 has a relatively DOM-like tree format, which we'll massage into a DOM elsewhere
-const treeAdapter = require('parse5-htmlparser2-tree-adapter');
-
 const PARSE5_OPTS = {
   treeAdapter
@@ -31,5 +30,7 @@
  */
 export function createDocument(html) {
-  const document = parse5.parse(html, PARSE5_OPTS);
+  const document = /** @type {HTMLDocument} */ (
+    parse5.parse(html, PARSE5_OPTS)
+  );
 
   defineProperties(document, DocumentExtensions);
@@ -48,5 +49,5 @@
 /**
  * Serialize a Document to an HTML String
- * @param {Document} document   A Document, such as one created via `createDocument()`
+ * @param {HTMLDocument} document   A Document, such as one created via `createDocument()`
  */
 export function serializeDocument(document) {
@@ -54,9 +55,12 @@
 }
 
+/** @typedef {treeAdapter.Document & typeof ElementExtensions} HTMLDocument */
+
 /**
  * Methods and descriptors to mix into Element.prototype
+ * @private
  */
 const ElementExtensions = {
-  /** @extends htmlparser2.Element.prototype */
+  /** @extends treeAdapter.Element.prototype */
 
   nodeName: {
@@ -131,5 +135,5 @@
  */
 const DocumentExtensions = {
-  /** @extends htmlparser2.Document.prototype */
+  /** @extends treeAdapter.Document.prototype */
 
   // document is just an Element in htmlparser2, giving it a nodeType of ELEMENT_NODE.
@@ -196,5 +200,5 @@
 
   querySelector(sel) {
-    return select.selectOne(sel, this.documentElement);
+    return selectOne(sel, this.documentElement);
   },
 
@@ -203,5 +207,5 @@
       return this;
     }
-    return select(sel, this.documentElement);
+    return selectAll(sel, this.documentElement);
   }
 };
Index: trip-planner-front/node_modules/critters/src/dom2.js
===================================================================
--- trip-planner-front/node_modules/critters/src/dom2.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ 	(revision )
@@ -1,435 +1,0 @@
-/**
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-import parse5 from 'parse5';
-import nwsapi from 'nwsapi';
-// import crawl from 'tree-crawl';
-// import select from 'css-select';
-
-// htmlparser2 has a relatively DOM-like tree format, which we'll massage into a DOM elsewhere
-const treeAdapter = require('parse5-htmlparser2-tree-adapter');
-
-const PARSE5_OPTS = {
-  treeAdapter
-};
-
-/**
- * Parse HTML into a mutable, serializable DOM Document.
- * The DOM implementation is an htmlparser2 DOM enhanced with basic DOM mutation methods.
- * @param {String} html   HTML to parse into a Document instance
- */
-export function createDocument(html) {
-  const document = parse5.parse(html, PARSE5_OPTS);
-
-  defineProperties(document, DocumentExtensions);
-
-  // Extend Element.prototype with DOM manipulation methods.
-  const scratch = document.createElement('div');
-  // Get a reference to the base Node class - used by createTextNode()
-  document.$$Node = scratch.constructor;
-  const elementProto = Object.getPrototypeOf(scratch);
-  defineProperties(elementProto, ElementExtensions);
-  elementProto.ownerDocument = document;
-
-  // nwsapi is a selector engine that happens to work with Parse5's htmlparser2 DOM (they form the base of jsdom).
-  // It is exposed to the document so that it can be used within Element.prototype methods.
-  document.$match = nwsapi({ document });
-  document.$match.configure({
-    IDS_DUPES: false,
-    LIVECACHE: false,
-    MIXEDCASE: true,
-    LOGERRORS: false
-  });
-
-  return document;
-}
-
-/**
- * Serialize a Document to an HTML String
- * @param {Document} document   A Document, such as one created via `createDocument()`
- */
-export function serializeDocument(document) {
-  return parse5.serialize(document, PARSE5_OPTS);
-}
-
-/**
- * Methods and descriptors to mix into Element.prototype
- */
-const ElementExtensions = {
-  /** @extends htmlparser2.Element.prototype */
-
-  nodeName: {
-    get() {
-      return this.tagName.toUpperCase();
-    }
-  },
-
-  id: reflectedProperty('id'),
-
-  className: reflectedProperty('class'),
-
-  classList: {
-    get() {
-      return this.className ? this.className.split(' ') : [];
-    }
-  },
-
-  insertBefore(child, referenceNode) {
-    if (!referenceNode) return this.appendChild(child);
-    treeAdapter.insertBefore(this, child, referenceNode);
-    return child;
-  },
-
-  appendChild(child) {
-    treeAdapter.appendChild(this, child);
-    return child;
-  },
-
-  removeChild(child) {
-    treeAdapter.detachNode(child);
-  },
-
-  remove() {
-    treeAdapter.detachNode(this);
-  },
-
-  textContent: {
-    get() {
-      return this.children.map((node) => node.nodeValue).join('\n');
-    },
-
-    set(text) {
-      this.children = [];
-      treeAdapter.insertText(this, text);
-    }
-  },
-
-  setAttribute(name, value) {
-    if (this.attribs == null) this.attribs = {};
-    if (value == null) value = '';
-    this.attribs[name] = value;
-  },
-
-  removeAttribute(name) {
-    if (this.attribs != null) {
-      delete this.attribs[name];
-    }
-  },
-
-  getAttribute(name) {
-    return this.attribs != null && this.attribs[name];
-  },
-
-  hasAttribute(name) {
-    return this.attribs != null && this.attribs[name] != null;
-  },
-
-  getAttributeNode(name) {
-    const value = this.getAttribute(name);
-    if (value != null) return { specified: true, value };
-  },
-
-  // These are used by nwsapi to implement its selector engine.
-  parentElement: {
-    get() {
-      const parent = this.parentNode;
-      if (parent.nodeType === 1) return parent;
-      return null;
-    }
-  },
-  firstElementChild: {
-    get() {
-      const children = this.children;
-
-      return (
-        (children && children.find((child) => child.nodeType === 1)) || null
-      );
-    }
-  },
-  nextElementSibling: {
-    get() {
-      let sibling = this.nextSibling;
-      while (sibling && sibling.nodeType !== 1) {
-        sibling = sibling.nextSibling;
-      }
-
-      return sibling;
-    }
-  },
-  previousElementSibling: {
-    get() {
-      let sibling = this.previousSibling;
-      while (sibling && sibling.nodeType !== 1) {
-        sibling = sibling.previousSibling;
-      }
-
-      return sibling;
-    }
-  },
-
-  getElementsByTagName,
-  getElementsByClassName
-};
-
-/**
- * Methods and descriptors to mix into the global document instance
- * @private
- */
-const DocumentExtensions = {
-  /** @extends htmlparser2.Document.prototype */
-
-  // document is just an Element in htmlparser2, giving it a nodeType of ELEMENT_NODE.
-  // nwsapi requires that it at least report a correct nodeType of DOCUMENT_NODE.
-  nodeType: {
-    get() {
-      return 9;
-    }
-  },
-
-  contentType: {
-    get() {
-      return 'text/html';
-    }
-  },
-
-  nodeName: {
-    get() {
-      return '#document';
-    }
-  },
-
-  documentElement: {
-    get() {
-      // Find the first <html> element within the document
-      return this.childNodes.filter(
-        (child) => String(child.tagName).toLowerCase() === 'html'
-      )[0];
-    }
-  },
-
-  compatMode: {
-    get() {
-      const compatMode = {
-        'no-quirks': 'CSS1Compat',
-        quirks: 'BackCompat',
-        'limited-quirks': 'CSS1Compat'
-      };
-      return compatMode[treeAdapter.getDocumentMode(this)];
-    }
-  },
-
-  body: {
-    get() {
-      return this.querySelector('body');
-    }
-  },
-
-  createElement(name) {
-    return treeAdapter.createElement(name, null, []);
-  },
-
-  createTextNode(text) {
-    // there is no dedicated createTextNode equivalent exposed in htmlparser2's DOM
-    const Node = this.$$Node;
-    return new Node({
-      type: 'text',
-      data: text,
-      parent: null,
-      prev: null,
-      next: null
-    });
-  },
-
-  querySelector(sel) {
-    return this.$match.first(sel, this.documentElement);
-    // return select.selectOne(sel, this.documentElement);
-  },
-
-  querySelectorAll(sel) {
-    return this.$match.select(sel, this.documentElement);
-    // return select(sel, this.documentElement);
-  },
-
-  getElementsByTagName,
-  getElementsByClassName
-};
-
-/**
- * Essentially `Object.defineProperties()`, except function values are assigned as value descriptors for convenience.
- * @private
- */
-function defineProperties(obj, properties) {
-  for (const i in properties) {
-    const value = properties[i];
-    Object.defineProperty(
-      obj,
-      i,
-      typeof value === 'function' ? { value } : value
-    );
-  }
-}
-
-/**
- * A simple implementation of Element.prototype.getElementsByTagName().
- * This is used by nwsapi to implement its selector engine.
- * @private
- * @note
- *    If perf issues arise, 2 faster but more verbose implementations are benchmarked here:
- *      https://esbench.com/bench/5ac3b647f2949800a0f619e1
- */
-// function getElementsByTagName(tagName) {
-//   // Only return Element/Document nodes
-//   if (
-//     (this.nodeType !== 1 && this.nodeType !== 9) ||
-//     this.type === 'directive'
-//   ) {
-//     return [];
-//   }
-//   return Array.prototype.concat.apply(
-//     // Add current element if it matches tag
-//     tagName === '*' ||
-//       (this.tagName &&
-//         (this.tagName === tagName || this.nodeName === tagName.toUpperCase()))
-//       ? [this]
-//       : [],
-//     // Check children recursively
-//     this.children.map((child) => getElementsByTagName.call(child, tagName))
-//   );
-// }
-
-function getElementsByTagName(tagName) {
-  if (this.nodeType !== 1 && this.nodeType !== 9) return [];
-  const stack = [this];
-  const matches = [];
-  const isWildCard = tagName === '*';
-  const tagNameUpper = tagName.toUpperCase();
-  while (stack.length !== 0) {
-    const el = stack.pop();
-    let child = el.lastChild;
-    while (child) {
-      if (child.nodeType === 1) stack.push(child);
-      child = child.previousSibling;
-    }
-    if (
-      isWildCard ||
-      (el.tagName != null &&
-        (el.tagName === tagNameUpper ||
-          el.tagName.toUpperCase() === tagNameUpper))
-    ) {
-      matches.push(el);
-    }
-  }
-  return matches;
-}
-
-// function getElementsByTagName(tagName) {
-//   if (this.nodeType !== 1 && this.nodeType !== 9) return [];
-//   const matches = [];
-//   const isWildCard = tagName === '*';
-//   const tagNameUpper = tagName.toUpperCase();
-
-//   crawl(
-//     this,
-//     (node, context) => {
-//       if (node.nodeType !== 1) {
-//         context.skip();
-//       }
-
-//       if (
-//         isWildCard ||
-//         (node.tagName != null &&
-//           (node.tagName === tagNameUpper ||
-//             node.tagName.toUpperCase() === tagNameUpper))
-//       ) {
-//         matches.push(node);
-//       }
-//     },
-//     { order: 'pre' }
-//   );
-//   return matches;
-// }
-
-// function getElementsByClassName(className) {
-//   // Only return Element/Document nodes
-//   if (
-//     (this.nodeType !== 1 && this.nodeType !== 9) ||
-//     this.type === 'directive'
-//   ) {
-//     return [];
-//   }
-//   return Array.prototype.concat.apply(
-//     // Add current element if it matches tag
-//     className && this.classList.includes(className.trim()) ? [this] : [],
-//     // Check children recursively
-//     this.children.map((child) => getElementsByClassName.call(child, className))
-//   );
-// }
-
-function getElementsByClassName(className) {
-  if (this.nodeType !== 1 && this.nodeType !== 9) return [];
-  const stack = [...this.children];
-  const matches = [];
-  while (stack.length !== 0) {
-    const el = stack.pop();
-    let child = el.lastChild;
-    while (child) {
-      if (child.nodeType === 1) stack.push(child);
-      child = child.previousSibling;
-    }
-
-    // const classRe = new RegExp('(^|s)' + className + '(s|$)');
-    if (el.classList.includes(className.trim())) {
-      matches.push(el);
-    }
-  }
-  return matches;
-}
-
-// function getElementsByClassName(className) {
-//   if (this.nodeType !== 1 && this.nodeType !== 9) return [];
-//   const matches = [];
-
-//   crawl(
-//     this,
-//     (node, context) => {
-//       if (node.nodeType !== 1) {
-//         context.skip();
-//       }
-
-//       if (node.classList.includes(className)) {
-//         matches.push(node);
-//       }
-//     },
-//     { order: 'pre' }
-//   );
-
-//   return matches;
-// }
-
-/**
- * Create a property descriptor defining a getter/setter pair alias for a named attribute.
- * @private
- */
-function reflectedProperty(attributeName) {
-  return {
-    get() {
-      return this.getAttribute(attributeName);
-    },
-    set(value) {
-      this.setAttribute(attributeName, value);
-    }
-  };
-}
Index: trip-planner-front/node_modules/critters/src/dom4.js
===================================================================
--- trip-planner-front/node_modules/critters/src/dom4.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ 	(revision )
@@ -1,261 +1,0 @@
-/**
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-// import parse5 from 'parse5';
-// import { parseDOM, DomUtils } from 'htmlparser2';
-import select from 'css-select';
-
-const { parseDOM, DomUtils } = require('htmlparser2');
-
-// htmlparser2 has a relatively DOM-like tree format, which we'll massage into a DOM elsewhere
-const treeAdapter = require('parse5-htmlparser2-tree-adapter');
-
-const PARSE5_OPTS = {
-  treeAdapter,
-};
-
-/**
- * Parse HTML into a mutable, serializable DOM Document.
- * The DOM implementation is an htmlparser2 DOM enhanced with basic DOM mutation methods.
- * @param {String} html   HTML to parse into a Document instance
- */
-export function createDocument(html) {
-  // const document = parse5.parse(html, PARSE5_OPTS);
-  const document = parseDOM(html);
-
-  defineProperties(document, DocumentExtensions);
-
-  // Extend Element.prototype with DOM manipulation methods.
-  // const scratch = document.createElement('div');
-  // Get a reference to the base Node class - used by createTextNode()
-  // document.$$Node = scratch.constructor;
-  // const elementProto = Object.getPrototypeOf(scratch);
-  // defineProperties(elementProto, ElementExtensions);
-  // elementProto.ownerDocument = document;
-
-  return document;
-}
-
-/**
- * Serialize a Document to an HTML String
- * @param {Document} document   A Document, such as one created via `createDocument()`
- */
-export function serializeDocument(document) {
-  return DomUtils.getOuterHTML(document);
-}
-
-/**
- * Methods and descriptors to mix into Element.prototype
- */
-const ElementExtensions = {
-  /** @extends htmlparser2.Element.prototype */
-
-  nodeName: {
-    get() {
-      return this.tagName.toUpperCase();
-    },
-  },
-
-  id: reflectedProperty('id'),
-
-  className: reflectedProperty('class'),
-  parentNode: {
-    get() {
-      if (this.parent) defineProperties(this.parent, ElementExtensions);
-      return this.parent;
-    },
-  },
-
-  insertBefore(child, referenceNode) {
-    if (!referenceNode) return this.appendChild(child);
-    DomUtils.prepend(referenceNode, child);
-    return child;
-  },
-
-  appendChild(child) {
-    DomUtils.appendChild(this, child);
-    return child;
-  },
-
-  removeChild(child) {
-    DomUtils.removeElement(child);
-  },
-
-  remove() {
-    DomUtils.removeElement(this);
-  },
-
-  textContent: {
-    get() {
-      return DomUtils.getText(this);
-    },
-
-    set(text) {
-      this.children = [];
-      DomUtils.appendChild(this, createTextNode(text));
-    },
-  },
-
-  setAttribute(name, value) {
-    if (this.attribs == null) this.attribs = {};
-    if (value == null) value = '';
-    this.attribs[name] = value;
-  },
-
-  removeAttribute(name) {
-    if (this.attribs != null) {
-      delete this.attribs[name];
-    }
-  },
-
-  getAttribute(name) {
-    return this.attribs != null && this.attribs[name];
-  },
-
-  hasAttribute(name) {
-    return this.attribs != null && this.attribs[name] != null;
-  },
-
-  getAttributeNode(name) {
-    const value = this.getAttribute(name);
-    if (value != null) return { specified: true, value };
-  },
-};
-
-/**
- * Methods and descriptors to mix into the global document instance
- * @private
- */
-const DocumentExtensions = {
-  /** @extends htmlparser2.Document.prototype */
-
-  // document is just an Element in htmlparser2, giving it a nodeType of ELEMENT_NODE.
-  // TODO: verify if these are needed for css-select
-  nodeType: {
-    get() {
-      return 9;
-    },
-  },
-
-  contentType: {
-    get() {
-      return 'text/html';
-    },
-  },
-
-  nodeName: {
-    get() {
-      return '#document';
-    },
-  },
-
-  documentElement: {
-    get() {
-      // Find the first <html> element within the document
-      return this.filter(
-        (child) => String(child.tagName).toLowerCase() === 'html'
-      );
-    },
-  },
-
-  compatMode: {
-    get() {
-      const compatMode = {
-        'no-quirks': 'CSS1Compat',
-        quirks: 'BackCompat',
-        'limited-quirks': 'CSS1Compat',
-      };
-      return compatMode[treeAdapter.getDocumentMode(this)];
-    },
-  },
-
-  body: {
-    get() {
-      return this.querySelector('body');
-    },
-  },
-
-  createElement(tagName) {
-    const node = {
-      type: tagName === 'script' || tagName === 'style' ? tagName : 'tag',
-      name: tagName,
-      attribs: [],
-      children: [],
-      parent: null,
-      prev: null,
-      next: null,
-    };
-    defineProperties(node, ElementExtensions);
-    return node;
-  },
-
-  querySelector(sel) {
-    if (sel === ':root') {
-      return this.type === 'root';
-    }
-
-    const res = select.selectOne(sel, this.documentElement);
-    if (res) defineProperties(res, ElementExtensions);
-    return res;
-  },
-
-  querySelectorAll(sel) {
-    if (sel === ':root') {
-      return this.type === 'root';
-    }
-
-    const res = select(sel, this.documentElement);
-
-    res.forEach((r) => {
-      if (r) defineProperties(r, ElementExtensions);
-    });
-    return res;
-  },
-};
-
-/**
- * Essentially `Object.defineProperties()`, except function values are assigned as value descriptors for convenience.
- * @private
- */
-function defineProperties(obj, properties) {
-  for (const i in properties) {
-    const value = properties[i];
-    Object.defineProperty(
-      obj,
-      i,
-      typeof value === 'function' ? { value } : value
-    );
-  }
-}
-
-/**
- * Create a property descriptor defining a getter/setter pair alias for a named attribute.
- * @private
- */
-function reflectedProperty(attributeName) {
-  return {
-    get() {
-      return this.getAttribute(attributeName);
-    },
-    set(value) {
-      this.setAttribute(attributeName, value);
-    },
-  };
-}
-
-function createTextNode(text) {
-  return parseDOM(text)[0];
-}
Index: trip-planner-front/node_modules/critters/src/dom_temp.js
===================================================================
--- trip-planner-front/node_modules/critters/src/dom_temp.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/**
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-import { JSDOM } from 'jsdom';
-
-/**
- * Parse HTML into a mutable, serializable DOM Document, provided by JSDOM.
- * @private
- * @param {String} html   HTML to parse into a Document instance
- */
-export function createDocument (html) {
-  const jsdom = new JSDOM(html, {
-    contentType: 'text/html'
-  });
-  const { window } = jsdom;
-  const document = window.document;
-  document.$jsdom = jsdom;
-  return document;
-}
-/**
- * Serialize a Document to an HTML String
- * @private
- * @param {Document} document   A Document, such as one created via `createDocument()`
- */
-export function serializeDocument (document) {
-  return document.$jsdom.serialize();
-}
-
-/** Like node.textContent, except it works */
-export function setNodeText (node, text) {
-  while (node.lastChild) {
-    node.removeChild(node.lastChild);
-  }
-  node.appendChild(node.ownerDocument.createTextNode(text));
-}
Index: trip-planner-front/node_modules/critters/src/index.d.ts
===================================================================
--- trip-planner-front/node_modules/critters/src/index.d.ts	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/critters/src/index.d.ts	(revision b73803523f0488ec52498c2ba88889f1642ad263)
@@ -15,39 +15,54 @@
  */
 
-declare module 'critters' {
-  export interface Options {
-    path?: string;
-    publicPath?: string;
-    external?: boolean;
-    inlineThreshold?: number;
-    minimumExternalSize?: number;
-    pruneSource?: boolean;
-    mergeStylesheets?: boolean;
-    additionalStylesheets?: string[];
-    preload?: 'body' | 'media' | 'swap' | 'js' | 'js-lazy';
-    noscriptFallback?: boolean;
-    inlineFonts?: boolean;
-    preloadFonts?: boolean;
-    fonts?: boolean;
-    keyframes?: string;
-    compress?: boolean;
-    logLevel?: 'info' | 'warn' | 'error' | 'trace' | 'debug' | 'silent';
-    reduceInlineStyles?: boolean;
-    logger?: Logger;
-  }
+export default class Critters {
+  /**
+   * Create an instance of Critters with custom options.
+   * The `.process()` method can be called repeatedly to re-use this instance and its cache.
+   */
+  constructor(options: Options);
+  /**
+   * Process an HTML document to inline critical CSS from its stylesheets.
+   * @param {string} html String containing a full HTML document to be parsed.
+   * @returns {string} A modified copy of the provided HTML with critical CSS inlined.
+   */
+  process(html: string): Promise<string>;
+  /**
+   * Read the contents of a file from the specified filesystem or disk.
+   * Override this method to customize how stylesheets are loaded.
+   */
+  readFile(filename: string): Promise<string> | string;
+  /**
+   * Given a stylesheet URL, returns the corresponding CSS asset.
+   * Overriding this method requires doing your own URL normalization, so it's generally better to override `readFile()`.
+   */
+  getCssAsset(href: string): Promise<string | undefined> | string | undefined;
+}
 
-  export interface Logger {
-    trace?: (message: string) => void;
-    debug?: (message: string) => void;
-    info?: (message: string) => void;
-    warn?: (message: string) => void;
-    error?: (message: string) => void;
-  }
+export interface Options {
+  path?: string;
+  publicPath?: string;
+  external?: boolean;
+  inlineThreshold?: number;
+  minimumExternalSize?: number;
+  pruneSource?: boolean;
+  mergeStylesheets?: boolean;
+  additionalStylesheets?: string[];
+  preload?: 'body' | 'media' | 'swap' | 'js' | 'js-lazy';
+  noscriptFallback?: boolean;
+  inlineFonts?: boolean;
+  preloadFonts?: boolean;
+  fonts?: boolean;
+  keyframes?: string;
+  compress?: boolean;
+  logLevel?: 'info' | 'warn' | 'error' | 'trace' | 'debug' | 'silent';
+  reduceInlineStyles?: boolean;
+  logger?: Logger;
+}
 
-  class Critters {
-    constructor(options: Options);
-    process(html: string): Promise<string>;
-  }
-
-  export default Critters;
+export interface Logger {
+  trace?: (message: string) => void;
+  debug?: (message: string) => void;
+  info?: (message: string) => void;
+  warn?: (message: string) => void;
+  error?: (message: string) => void;
 }
Index: trip-planner-front/node_modules/critters/src/index.js
===================================================================
--- trip-planner-front/node_modules/critters/src/index.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/critters/src/index.js	(revision b73803523f0488ec52498c2ba88889f1642ad263)
@@ -30,4 +30,5 @@
 /**
  * The mechanism to use for lazy-loading stylesheets.
+ *
  * Note: <kbd>JS</kbd> indicates a strategy requiring JavaScript (falls back to `<noscript>` unless disabled).
  *
@@ -242,4 +243,10 @@
         .replace(/^\//, '');
     }
+
+    // Ignore remote stylesheets
+    if (/^https:\/\//.test(normalizedPath) || href.startsWith('//')) {
+      return undefined;
+    }
+
     const filename = path.resolve(outputPath, normalizedPath);
 
@@ -484,23 +491,21 @@
             }
           });
+
           // If there are no matched selectors, remove the rule:
-          if (rule.selectors.length === 0) {
+          if (!rule.selector) {
             return false;
           }
 
-          if (rule.declarations) {
-            for (let i = 0; i < rule.declarations.length; i++) {
-              const decl = rule.declarations[i];
+          if (rule.nodes) {
+            for (let i = 0; i < rule.nodes.length; i++) {
+              const decl = rule.nodes[i];
 
               // detect used fonts
-              if (decl.property && decl.property.match(/\bfont(-family)?\b/i)) {
+              if (decl.prop && decl.prop.match(/\bfont(-family)?\b/i)) {
                 criticalFonts += ' ' + decl.value;
               }
 
               // detect used keyframes
-              if (
-                decl.property === 'animation' ||
-                decl.property === 'animation-name'
-              ) {
+              if (decl.prop === 'animation' || decl.prop === 'animation-name') {
                 // @todo: parse animation declarations and extract only the name. for now we'll do a lazy match.
                 const names = decl.value.split(/\s+/);
@@ -515,8 +520,8 @@
 
         // keep font rules, they're handled in the second pass:
-        if (rule.type === 'font-face') return;
+        if (rule.type === 'atrule' && rule.name === 'font-face') return;
 
         // If there are no remaining rules, remove the whole rule:
-        const rules = rule.rules && rule.rules.filter((rule) => !rule.$$remove);
+        const rules = rule.nodes && rule.nodes.filter((rule) => !rule.$$remove);
         return !rules || rules.length !== 0;
       })
@@ -547,19 +552,19 @@
 
       // prune @keyframes rules
-      if (rule.type === 'keyframes') {
+      if (rule.type === 'atrule' && rule.name === 'keyframes') {
         if (keyframesMode === 'none') return false;
         if (keyframesMode === 'all') return true;
-        return criticalKeyframeNames.indexOf(rule.name) !== -1;
+        return criticalKeyframeNames.indexOf(rule.params) !== -1;
       }
 
       // prune @font-face rules
-      if (rule.type === 'font-face') {
+      if (rule.type === 'atrule' && rule.name === 'font-face') {
         let family, src;
-        for (let i = 0; i < rule.declarations.length; i++) {
-          const decl = rule.declarations[i];
-          if (decl.property === 'src') {
+        for (let i = 0; i < rule.nodes.length; i++) {
+          const decl = rule.nodes[i];
+          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.property === 'font-family') {
+          } else if (decl.prop === 'font-family') {
             family = decl.value;
           }
@@ -590,5 +595,5 @@
     sheet = serializeStylesheet(ast, {
       compress: this.options.compress !== false
-    }).trim();
+    });
 
     // If all rules were removed, get rid of the style element entirely
Index: trip-planner-front/node_modules/critters/src/index1.js
===================================================================
--- trip-planner-front/node_modules/critters/src/index1.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ 	(revision )
@@ -1,680 +1,0 @@
-/**
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-import path from 'path';
-import prettyBytes from 'pretty-bytes';
-import sources from 'webpack-sources';
-import postcss from 'postcss';
-import cssnano from 'cssnano';
-import log from 'webpack-log';
-import minimatch from 'minimatch';
-import { createDocument, serializeDocument, setNodeText } from './dom';
-import {
-  parseStylesheet,
-  serializeStylesheet,
-  walkStyleRules,
-  walkStyleRulesWithReverseMirror,
-  markOnly,
-  applyMarkedSelectors,
-} from './css';
-import { tap } from './util';
-
-// Used to annotate this plugin's hooks in Tappable invocations
-const PLUGIN_NAME = 'critters-webpack-plugin';
-
-/**
- * The mechanism to use for lazy-loading stylesheets.
- * _[JS]_ indicates that a strategy requires JavaScript (falls back to `<noscript>`).
- *
- * - **default:** Move stylesheet links to the end of the document and insert preload meta tags in their place.
- * - **"body":** Move all external stylesheet links to the end of the document.
- * - **"media":** Load stylesheets asynchronously by adding `media="not x"` and removing once loaded. _[JS]_
- * - **"swap":** Convert stylesheet links to preloads that swap to `rel="stylesheet"` once loaded. _[JS]_
- * - **"js":** Inject an asynchronous CSS loader similar to [LoadCSS](https://github.com/filamentgroup/loadCSS) and use it to load stylesheets. _[JS]_
- * - **"js-lazy":** Like `"js"`, but the stylesheet is disabled until fully loaded.
- * @typedef {(default|'body'|'media'|'swap'|'js'|'js-lazy')} PreloadStrategy
- * @public
- */
-
-/**
- * Controls which keyframes rules are inlined.
- *
- * - **"critical":** _(default)_ inline keyframes rules that are used by the critical CSS.
- * - **"all":** Inline all keyframes rules.
- * - **"none":** Remove all keyframes rules.
- * @typedef {('critical'|'all'|'none')} KeyframeStrategy
- * @private
- * @property {String} keyframes     Which {@link KeyframeStrategy keyframe strategy} to use (default: `critical`)_
- */
-
-/**
- * Controls log level of the plugin. Specifies the level the logger should use. A logger will
- * not produce output for any log level beneath the specified level. Available levels and order
- * are:
- *
- * - **"info"** _(default)_
- * - **"warn"**
- * - **"error"**
- * - **"trace"**
- * - **"debug"**
- * - **"silent"**
- * @typedef {('info'|'warn'|'error'|'trace'|'debug'|'silent')} LogLevel
- * @public
- */
-
-/**
- * All optional. Pass them to `new Critters({ ... })`.
- * @public
- * @typedef Options
- * @property {Boolean} external     Inline styles from external stylesheets _(default: `true`)_
- * @property {Number} inlineThreshold Inline external stylesheets smaller than a given size _(default: `0`)_
- * @property {Number} minimumExternalSize If the non-critical external stylesheet would be below this size, just inline it _(default: `0`)_
- * @property {Boolean} pruneSource  Remove inlined rules from the external stylesheet _(default: `true`)_
- * @property {Boolean} mergeStylesheets Merged inlined stylesheets into a single <style> tag _(default: `true`)_
- * @property {String[]} additionalStylesheets Glob for matching other stylesheets to be used while looking for critical CSS _(default: ``)_.
- * @property {String} preload       Which {@link PreloadStrategy preload strategy} to use
- * @property {Boolean} noscriptFallback Add `<noscript>` fallback to JS-based strategies
- * @property {Boolean} inlineFonts  Inline critical font-face rules _(default: `false`)_
- * @property {Boolean} preloadFonts Preloads critical fonts _(default: `true`)_
- * @property {Boolean} fonts        Shorthand for setting `inlineFonts`+`preloadFonts`
- *  - Values:
- *  - `true` to inline critical font-face rules and preload the fonts
- *  - `false` to don't inline any font-face rules and don't preload fonts
- * @property {String} keyframes     Controls which keyframes rules are inlined.
- *  - Values:
- *  - `"critical"`: _(default)_ inline keyframes rules used by the critical CSS
- *  - `"all"` inline all keyframes rules
- *  - `"none"` remove all keyframes rules
- * @property {Boolean} compress     Compress resulting critical CSS _(default: `true`)_
- * @property {String} logLevel      Controls {@link LogLevel log level} of the plugin _(default: `"info"`)_
- */
-
-/**
- * Create a Critters plugin instance with the given options.
- * @public
- * @param {Options} options Options to control how Critters inlines CSS.
- * @example
- * // webpack.config.js
- * module.exports = {
- *   plugins: [
- *     new Critters({
- *       // Outputs: <link rel="preload" onload="this.rel='stylesheet'">
- *       preload: 'swap',
- *
- *       // Don't inline critical font-face rules, but preload the font URLs:
- *       preloadFonts: true
- *     })
- *   ]
- * }
- */
-export default class Critters {
-  /** @private */
-  constructor(options) {
-    this.options = Object.assign(
-      { logLevel: 'info', externalStylesheets: [] },
-      options || {}
-    );
-    this.options.pruneSource = this.options.pruneSource !== false;
-    this.urlFilter = this.options.filter;
-    if (this.urlFilter instanceof RegExp) {
-      this.urlFilter = this.urlFilter.test.bind(this.urlFilter);
-    }
-    this.logger = log({
-      name: 'Critters',
-      unique: true,
-      level: this.options.logLevel,
-    });
-  }
-
-  /**
-   * Invoked by Webpack during plugin initialization
-   */
-  apply(compiler) {
-    // hook into the compiler to get a Compilation instance...
-    tap(compiler, 'compilation', PLUGIN_NAME, false, (compilation) => {
-      // ... which is how we get an "after" hook into html-webpack-plugin's HTML generation.
-      if (
-        compilation.hooks &&
-        compilation.hooks.htmlWebpackPluginAfterHtmlProcessing
-      ) {
-        tap(
-          compilation,
-          'html-webpack-plugin-after-html-processing',
-          PLUGIN_NAME,
-          true,
-          (htmlPluginData, callback) => {
-            this.process(compiler, compilation, htmlPluginData.html)
-              .then((html) => {
-                callback(null, { html });
-              })
-              .catch(callback);
-          }
-        );
-      } else {
-        // If html-webpack-plugin isn't used, process the first HTML asset as an optimize step
-        tap(
-          compilation,
-          'optimize-assets',
-          PLUGIN_NAME,
-          true,
-          (assets, callback) => {
-            let htmlAssetName;
-            for (const name in assets) {
-              if (name.match(/\.html$/)) {
-                htmlAssetName = name;
-                break;
-              }
-            }
-            if (!htmlAssetName) {
-              return callback(Error('Could not find HTML asset.'));
-            }
-            const html = assets[htmlAssetName].source();
-            if (!html) return callback(Error('Empty HTML asset.'));
-
-            this.process(compiler, compilation, String(html))
-              .then((html) => {
-                assets[htmlAssetName] = new sources.RawSource(html);
-                callback();
-              })
-              .catch(callback);
-          }
-        );
-      }
-    });
-  }
-
-  /**
-   * Read the contents of a file from Webpack's input filesystem
-   */
-  readFile(compilation, filename) {
-    const fs = this.fs || compilation.outputFileSystem;
-    return new Promise((resolve, reject) => {
-      const callback = (err, data) => {
-        if (err) reject(err);
-        else resolve(data);
-      };
-      if (fs && fs.readFile) {
-        fs.readFile(filename, callback);
-      } else {
-        require('fs').readFile(filename, 'utf8', callback);
-      }
-    });
-  }
-
-  /**
-   * Apply critical CSS processing to html-webpack-plugin
-   */
-  async process(compiler, compilation, html) {
-    const outputPath = compiler.options.output.path;
-    const publicPath = compiler.options.output.publicPath;
-
-    // Parse the generated HTML in a DOM we can mutate
-    const document = createDocument(html);
-
-    if (this.options.additionalStylesheets) {
-      const styleSheetsIncluded = [];
-      (this.options.additionalStylesheets || []).forEach((cssFile) => {
-        if (styleSheetsIncluded.includes(cssFile)) {
-          return;
-        }
-        styleSheetsIncluded.push(cssFile);
-        const webpackCssAssets = Object.keys(
-          compilation.assets
-        ).filter((file) => minimatch(file, cssFile));
-        webpackCssAssets.map((asset) => {
-          const tag = document.createElement('style');
-          tag.innerHTML = compilation.assets[asset].source();
-          document.head.appendChild(tag);
-        });
-      });
-    }
-
-    // `external:false` skips processing of external sheets
-    if (this.options.external !== false) {
-      const externalSheets = [].slice.call(
-        document.querySelectorAll('link[rel="stylesheet"]')
-      );
-      await Promise.all(
-        externalSheets.map((link) =>
-          this.embedLinkedStylesheet(link, compilation, outputPath, publicPath)
-        )
-      );
-    }
-
-    // go through all the style tags in the document and reduce them to only critical CSS
-    const styles = [].slice.call(document.querySelectorAll('style'));
-    await Promise.all(
-      styles.map((style) => this.processStyle(style, document))
-    );
-
-    if (this.options.mergeStylesheets !== false && styles.length !== 0) {
-      await this.mergeStylesheets(document);
-    }
-
-    // serialize the document back to HTML and we're done
-    return serializeDocument(document);
-  }
-
-  async mergeStylesheets(document) {
-    const styles = [].slice.call(document.querySelectorAll('style'));
-    if (styles.length === 0) {
-      this.logger.warn(
-        'Merging inline stylesheets into a single <style> tag skipped, no inline stylesheets to merge'
-      );
-      return;
-    }
-    const first = styles[0];
-    let sheet = first.textContent;
-    for (let i = 1; i < styles.length; i++) {
-      const node = styles[i];
-      sheet += node.textContent;
-      node.remove();
-    }
-    if (this.options.compress !== false) {
-      const before = sheet;
-      const processor = postcss([cssnano()]);
-      const result = await processor.process(before, { from: undefined });
-      // @todo sourcemap support (elsewhere first)
-      sheet = result.css;
-    }
-    setNodeText(first, sheet);
-  }
-
-  /**
-   * Inline the target stylesheet referred to by a <link rel="stylesheet"> (assuming it passes `options.filter`)
-   */
-  async embedLinkedStylesheet(link, compilation, outputPath, publicPath) {
-    const href = link.getAttribute('href');
-    const media = link.getAttribute('media');
-    const document = link.ownerDocument;
-
-    const preloadMode = this.options.preload;
-
-    // skip filtered resources, or network resources if no filter is provided
-    if (this.urlFilter ? this.urlFilter(href) : href.match(/^(https?:)?\/\//)) {
-      return Promise.resolve();
-    }
-
-    // path on disk (with output.publicPath removed)
-    let normalizedPath = href.replace(/^\//, '');
-    const pathPrefix = (publicPath || '').replace(/(^\/|\/$)/g, '') + '/';
-    if (normalizedPath.indexOf(pathPrefix) === 0) {
-      normalizedPath = normalizedPath
-        .substring(pathPrefix.length)
-        .replace(/^\//, '');
-    }
-    const filename = path.resolve(outputPath, normalizedPath);
-
-    // try to find a matching asset by filename in webpack's output (not yet written to disk)
-    const relativePath = path
-      .relative(outputPath, filename)
-      .replace(/^\.\//, '');
-    const asset = compilation.assets[relativePath];
-
-    // Attempt to read from assets, falling back to a disk read
-    let sheet = asset && asset.source();
-    if (!sheet) {
-      try {
-        sheet = await this.readFile(compilation, filename);
-        this.logger.warn(
-          `Stylesheet "${relativePath}" not found in assets, but a file was located on disk.${
-            this.options.pruneSource
-              ? ' This means pruneSource will not be applied.'
-              : ''
-          }`
-        );
-      } catch (e) {
-        this.logger.warn(`Unable to locate stylesheet: ${relativePath}`);
-        return;
-      }
-    }
-
-    // CSS loader is only injected for the first sheet, then this becomes an empty string
-    let cssLoaderPreamble = `function $loadcss(u,m,l){(l=document.createElement('link')).rel='stylesheet';l.href=u;document.head.appendChild(l)}`;
-    const lazy = preloadMode === 'js-lazy';
-    if (lazy) {
-      cssLoaderPreamble = cssLoaderPreamble.replace(
-        'l.href',
-        `l.media='print';l.onload=function(){l.media=m};l.href`
-      );
-    }
-
-    // the reduced critical CSS gets injected into a new <style> tag
-    const style = document.createElement('style');
-    style.appendChild(document.createTextNode(sheet));
-    link.parentNode.insertBefore(style, link);
-
-    if (
-      this.options.inlineThreshold &&
-      sheet.length < this.options.inlineThreshold
-    ) {
-      style.$$reduce = false;
-      this.logger.info(
-        `\u001b[32mInlined all of ${href} (${sheet.length} was below the threshold of ${this.options.inlineThreshold})\u001b[39m`
-      );
-      if (asset) {
-        delete compilation.assets[relativePath];
-      } else {
-        this.logger.warn(
-          `  > ${href} was not found in assets. the resource may still be emitted but will be unreferenced.`
-        );
-      }
-      link.parentNode.removeChild(link);
-      return;
-    }
-
-    // drop references to webpack asset locations onto the tag, used for later reporting and in-place asset updates
-    style.$$name = href;
-    style.$$asset = asset;
-    style.$$assetName = relativePath;
-    style.$$assets = compilation.assets;
-    style.$$links = [link];
-
-    // Allow disabling any mutation of the stylesheet link:
-    if (preloadMode === false) return;
-
-    let noscriptFallback = false;
-
-    if (preloadMode === 'body') {
-      document.body.appendChild(link);
-    } else {
-      link.setAttribute('rel', 'preload');
-      link.setAttribute('as', 'style');
-      if (preloadMode === 'js' || preloadMode === 'js-lazy') {
-        const script = document.createElement('script');
-        const js = `${cssLoaderPreamble}$loadcss(${JSON.stringify(href)}${
-          lazy ? ',' + JSON.stringify(media || 'all') : ''
-        })`;
-        script.appendChild(document.createTextNode(js));
-        link.parentNode.insertBefore(script, link.nextSibling);
-        style.$$links.push(script);
-        cssLoaderPreamble = '';
-        noscriptFallback = true;
-      } else if (preloadMode === 'media') {
-        // @see https://github.com/filamentgroup/loadCSS/blob/af1106cfe0bf70147e22185afa7ead96c01dec48/src/loadCSS.js#L26
-        link.setAttribute('rel', 'stylesheet');
-        link.removeAttribute('as');
-        link.setAttribute('media', 'print');
-        link.setAttribute('onload', `this.media='${media || 'all'}'`);
-        noscriptFallback = true;
-      } else if (preloadMode === 'swap') {
-        link.setAttribute('onload', "this.rel='stylesheet'");
-        noscriptFallback = true;
-      } else {
-        const bodyLink = document.createElement('link');
-        bodyLink.setAttribute('rel', 'stylesheet');
-        if (media) bodyLink.setAttribute('media', media);
-        bodyLink.setAttribute('href', href);
-        document.body.appendChild(bodyLink);
-        style.$$links.push(bodyLink);
-      }
-    }
-
-    if (this.options.noscriptFallback !== false && noscriptFallback) {
-      const noscript = document.createElement('noscript');
-      const noscriptLink = document.createElement('link');
-      noscriptLink.setAttribute('rel', 'stylesheet');
-      noscriptLink.setAttribute('href', href);
-      if (media) noscriptLink.setAttribute('media', media);
-      noscript.appendChild(noscriptLink);
-      link.parentNode.insertBefore(noscript, link.nextSibling);
-      style.$$links.push(noscript);
-    }
-  }
-
-  /**
-   * Parse the stylesheet within a <style> element, then reduce it to contain only rules used by the document.
-   */
-  async processStyle(style) {
-    if (style.$$reduce === false) return;
-
-    const name = style.$$name ? style.$$name.replace(/^\//, '') : 'inline CSS';
-    const options = this.options;
-    const document = style.ownerDocument;
-    const head = document.querySelector('head');
-    let keyframesMode = options.keyframes || 'critical';
-    // we also accept a boolean value for options.keyframes
-    if (keyframesMode === true) keyframesMode = 'all';
-    if (keyframesMode === false) keyframesMode = 'none';
-
-    // basically `.textContent`
-    let sheet =
-      style.childNodes.length > 0 &&
-      [].map.call(style.childNodes, (node) => node.nodeValue).join('\n');
-
-    // 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 = [];
-
-    // 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 === 'rule') {
-          // Filter the selector list down to only those match
-          rule.filterSelectors((sel) => {
-            // 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 = sel.replace(/(?:>\s*)?::?[a-z-]+\s*(\{|$)/gi, '$1').trim();
-            }
-            if (!sel) return false;
-
-            try {
-              return document.querySelector(sel) != null;
-            } catch (e) {
-              failedSelectors.push(sel + ' -> ' + e.message);
-              return false;
-            }
-          });
-          // If there are no matched selectors, remove the rule:
-          if (rule.selectors.length === 0) {
-            return false;
-          }
-
-          if (rule.declarations) {
-            for (let i = 0; i < rule.declarations.length; i++) {
-              const decl = rule.declarations[i];
-
-              // detect used fonts
-              if (decl.property && decl.property.match(/\bfont(-family)?\b/i)) {
-                criticalFonts += ' ' + decl.value;
-              }
-
-              // detect used keyframes
-              if (
-                decl.property === 'animation' ||
-                decl.property === 'animation-name'
-              ) {
-                // @todo: parse animation declarations and extract only the name. for now we'll do a lazy match.
-                const names = decl.value.split(/\s+/);
-                for (let j = 0; j < names.length; j++) {
-                  const name = names[j].trim();
-                  if (name) criticalKeyframeNames.push(name);
-                }
-              }
-            }
-          }
-        }
-
-        // keep font rules, they're handled in the second pass:
-        if (rule.type === 'font-face') return;
-
-        // If there are no remaining rules, remove the whole rule:
-        const rules = rule.rules && rule.rules.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 shouldPreloadFonts =
-      options.fonts === true || options.preloadFonts === true;
-    const shouldInlineFonts =
-      options.fonts !== false && options.inlineFonts === true;
-
-    const preloadedFonts = [];
-    // 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 === 'keyframes') {
-        if (keyframesMode === 'none') return false;
-        if (keyframesMode === 'all') return true;
-        return criticalKeyframeNames.indexOf(rule.name) !== -1;
-      }
-
-      // prune @font-face rules
-      if (rule.type === 'font-face') {
-        let family, src;
-        for (let i = 0; i < rule.declarations.length; i++) {
-          const decl = rule.declarations[i];
-          if (decl.property === '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.property === 'font-family') {
-            family = decl.value;
-          }
-        }
-
-        if (src && shouldPreloadFonts && preloadedFonts.indexOf(src) === -1) {
-          preloadedFonts.push(src);
-          const preload = document.createElement('link');
-          preload.setAttribute('rel', 'preload');
-          preload.setAttribute('as', 'font');
-          preload.setAttribute('crossorigin', 'anonymous');
-          preload.setAttribute('href', src.trim());
-          head.appendChild(preload);
-        }
-
-        // if we're missing info, if the font is unused, or if critical font inlining is disabled, remove the rule:
-        if (
-          !family ||
-          !src ||
-          criticalFonts.indexOf(family) === -1 ||
-          !shouldInlineFonts
-        ) {
-          return false;
-        }
-      }
-    });
-
-    sheet = serializeStylesheet(ast, {
-      compress: this.options.compress !== false,
-    }).trim();
-
-    // If all rules were removed, get rid of the style element entirely
-    if (sheet.trim().length === 0) {
-      if (style.parentNode) {
-        style.parentNode.removeChild(style);
-      }
-      return;
-    }
-
-    let afterText = '';
-    if (options.pruneSource) {
-      const sheetInverse = serializeStylesheet(astInverse, {
-        compress: this.options.compress !== false,
-      });
-      const asset = style.$$asset;
-      if (asset) {
-        // if external stylesheet would be below minimum size, just inline everything
-        const minSize = this.options.minimumExternalSize;
-        if (minSize && sheetInverse.length < minSize) {
-          this.logger.info(
-            `\u001b[32mInlined all of ${name} (non-critical external stylesheet would have been ${sheetInverse.length}b, which was below the threshold of ${minSize})\u001b[39m`
-          );
-          setNodeText(style, before);
-          // remove any associated external resources/loaders:
-          if (style.$$links) {
-            for (const link of style.$$links) {
-              const parent = link.parentNode;
-              if (parent) parent.removeChild(link);
-            }
-          }
-          // delete the webpack asset:
-          delete style.$$assets[style.$$assetName];
-          return;
-        }
-
-        const percent = (sheetInverse.length / before.length) * 100;
-        afterText = `, reducing non-inlined size ${
-          percent | 0
-        }% to ${prettyBytes(sheetInverse.length)}`;
-        style.$$assets[style.$$assetName] = new sources.LineToLineMappedSource(
-          sheetInverse,
-          style.$$assetName,
-          before
-        );
-      } else {
-        this.logger.warn(
-          'pruneSource is enabled, but a style (' +
-            name +
-            ') has no corresponding Webpack asset.'
-        );
-      }
-    }
-
-    // replace the inline stylesheet with its critical'd counterpart
-    setNodeText(style, sheet);
-
-    // output stats
-    const percent = ((sheet.length / before.length) * 100) | 0;
-    this.logger.info(
-      '\u001b[32mInlined ' +
-        prettyBytes(sheet.length) +
-        ' (' +
-        percent +
-        '% of original ' +
-        prettyBytes(before.length) +
-        ') of ' +
-        name +
-        afterText +
-        '.\u001b[39m'
-    );
-  }
-}
-
-// Original code picks 1 html and during prune removes CSS files from assets. What if theres another dependency
-// Handle error when parsing stylesheet
-// Most of our partner's CSS fails parsing
-// JSDOM css parsing fails even when css.parse works
-
Index: trip-planner-front/node_modules/critters/src/index2.js
===================================================================
--- trip-planner-front/node_modules/critters/src/index2.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ 	(revision )
@@ -1,672 +1,0 @@
-/**
- * Copyright 2018 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-import path from 'path';
-import postcss from 'postcss';
-import cssnano from 'cssnano';
-import prettyBytes from 'pretty-bytes';
-import { createDocument, serializeDocument } from './dom';
-import {
-  parseStylesheet,
-  serializeStylesheet,
-  walkStyleRules,
-  walkStyleRulesWithReverseMirror,
-  markOnly,
-  applyMarkedSelectors,
-} from './css';
-import { logger } from './util';
-
-/**
- * The mechanism to use for lazy-loading stylesheets.
- * _[JS]_ indicates that a strategy requires JavaScript (falls back to `<noscript>`).
- *
- * - **default:** Move stylesheet links to the end of the document and insert preload meta tags in their place.
- * - **"body":** Move all external stylesheet links to the end of the document.
- * - **"media":** Load stylesheets asynchronously by adding `media="not x"` and removing once loaded. _[JS]_
- * - **"swap":** Convert stylesheet links to preloads that swap to `rel="stylesheet"` once loaded. _[JS]_
- * - **"js":** Inject an asynchronous CSS loader similar to [LoadCSS](https://github.com/filamentgroup/loadCSS) and use it to load stylesheets. _[JS]_
- * - **"js-lazy":** Like `"js"`, but the stylesheet is disabled until fully loaded.
- * @typedef {(default|'body'|'media'|'swap'|'js'|'js-lazy')} PreloadStrategy
- * @public
- */
-
-/**
- * Controls which keyframes rules are inlined.
- *
- * - **"critical":** _(default)_ inline keyframes rules that are used by the critical CSS.
- * - **"all":** Inline all keyframes rules.
- * - **"none":** Remove all keyframes rules.
- * @typedef {('critical'|'all'|'none')} KeyframeStrategy
- * @private
- * @property {String} keyframes     Which {@link KeyframeStrategy keyframe strategy} to use (default: `critical`)_
- */
-
-/**
- * Controls log level of the plugin. Specifies the level the logger should use. A logger will
- * not produce output for any log level beneath the specified level. Available levels and order
- * are:
- *
- * - **"info"** _(default)_
- * - **"warn"**
- * - **"error"**
- * - **"trace"**
- * - **"debug"**
- * - **"silent"**
- * @typedef {('info'|'warn'|'error'|'trace'|'debug'|'silent')} LogLevel
- * @public
- */
-
-/**
- * All optional. Pass them to `new Critters({ ... })`.
- * @public
- * @typedef Options
- * @property {Boolean} external     Inline styles from external stylesheets _(default: `true`)_
- * @property {Number} inlineThreshold Inline external stylesheets smaller than a given size _(default: `0`)_
- * @property {Number} minimumExternalSize If the non-critical external stylesheet would be below this size, just inline it _(default: `0`)_
- * @property {Boolean} pruneSource  Remove inlined rules from the external stylesheet _(default: `false`)_
- * @property {Boolean} mergeStylesheets Merged inlined stylesheets into a single <style> tag _(default: `true`)_
- * @property {String[]} additionalStylesheets Glob for matching other stylesheets to be used while looking for critical CSS _(default: ``)_.
- * @property {String} preload       Which {@link PreloadStrategy preload strategy} to use
- * @property {Boolean} noscriptFallback Add `<noscript>` fallback to JS-based strategies
- * @property {Boolean} inlineFonts  Inline critical font-face rules _(default: `false`)_
- * @property {Boolean} preloadFonts Preloads critical fonts _(default: `true`)_
- * @property {Boolean} fonts        Shorthand for setting `inlineFonts`+`preloadFonts`
- *  - Values:
- *  - `true` to inline critical font-face rules and preload the fonts
- *  - `false` to don't inline any font-face rules and don't preload fonts
- * @property {String} keyframes     Controls which keyframes rules are inlined.
- *  - Values:
- *  - `"critical"`: _(default)_ inline keyframes rules used by the critical CSS
- *  - `"all"` inline all keyframes rules
- *  - `"none"` remove all keyframes rules
- * @property {Boolean} compress     Compress resulting critical CSS _(default: `true`)_
- * @property {String} logLevel      Controls {@link LogLevel log level} of the plugin _(default: `"info"`)_
- */
-
-export default class Critters {
-  /** @private */
-  constructor(options) {
-    this.options = Object.assign(
-      {
-        logLevel: 'info',
-        externalStylesheets: [],
-        outputPath: '',
-        publicPath: '',
-        reduceInlineStyles: true,
-        pruneSource: false,
-        additionalStylesheets: [],
-        ssrMode: false,
-      },
-      options || {}
-    );
-
-    this.urlFilter = this.options.filter;
-    if (this.urlFilter instanceof RegExp) {
-      this.urlFilter = this.urlFilter.test.bind(this.urlFilter);
-    }
-
-    this.logger = this.options.logger || logger;
-  }
-
-  /**
-   * Read the contents of a file from the specified filesystem or disk
-   */
-  readFile(filename) {
-    const fs = this.fs;
-    return new Promise((resolve, reject) => {
-      const callback = (err, data) => {
-        if (err) reject(err);
-        else resolve(data);
-      };
-      if (fs && fs.readFile) {
-        fs.readFile(filename, callback);
-      } else {
-        require('fs').readFile(filename, 'utf8', callback);
-      }
-    });
-  }
-
-  /**
-   * Apply critical CSS processing to the html
-   */
-  async process(html) {
-    // const start = process.hrtime.bigint();
-    console.time('critters');
-
-    // Parse the generated HTML in a DOM we can mutate
-    // console.time('createDoc');
-    const document = createDocument(html);
-    // console.timeEnd('createDoc');
-
-    if (this.options.additionalStylesheets.length > 0) {
-      this.embedAdditionalStylesheet(document);
-    }
-
-    // `external:false` skips processing of external sheets
-    if (this.options.external !== false) {
-      // console.time('externalSheets');
-      const externalSheets = [].slice.call(
-        document.querySelectorAll('link[rel="stylesheet"]')
-      );
-      // console.timeEnd('externalSheets');
-      // console.time('embedLinkedStylesheet');
-      await Promise.all(
-        externalSheets.map((link) => this.embedLinkedStylesheet(link))
-      );
-      // console.timeEnd('embedLinkedStylesheet');
-    }
-
-    // go through all the style tags in the document and reduce them to only critical CSS
-    // console.time('getAffectedStyleTags');
-    const styles = this.getAffectedStyleTags(document);
-    // console.timeEnd('getAffectedStyleTags');
-
-    // console.time('processStyle');
-    await Promise.all(
-      styles.map((style) => this.processStyle(style, document))
-    );
-    // console.timeEnd('processStyle');
-
-    if (this.options.mergeStylesheets !== false && styles.length !== 0) {
-      // console.time('mergeStylesheets');
-      await this.mergeStylesheets(document);
-      // console.timeEnd('mergeStylesheets');
-    }
-
-    // serialize the document back to HTML and we're done
-    // console.time('serializeDocument');
-    const output = serializeDocument(document);
-    // console.timeEnd('serializeDocument');
-    // const end = process.hrtime.bigint();
-    // console.log(`Time ${(end - start) / 1e6}`);
-    console.timeEnd('critters');
-    return output;
-  }
-
-  /**
-   * Get the style tags that need processing
-   */
-  getAffectedStyleTags(document) {
-    const styles = [].slice.call(document.querySelectorAll('style'));
-
-    // `inline:false` skips processing of inline stylesheets
-    if (this.options.reduceInlineStyles === false) {
-      return styles.filter((style) => style.$$external);
-    }
-    return styles;
-  }
-
-  async mergeStylesheets(document) {
-    const styles = this.getAffectedStyleTags(document);
-    if (styles.length === 0) {
-      this.logger.warn(
-        'Merging inline stylesheets into a single <style> tag skipped, no inline stylesheets to merge'
-      );
-      return;
-    }
-    const first = styles[0];
-    let sheet = first.textContent;
-    // console.log(sheet);
-    for (let i = 1; i < styles.length; i++) {
-      const node = styles[i];
-      // sheet.children.push(...node.children);
-      sheet += node.textContent;
-      // console.log(node);
-      // node.parent.children.splice(node.parent.children.indexOf(node), 1);
-      node.remove();
-    }
-    if (!this.options.ssrMode && this.options.compress !== false) {
-      const before = sheet;
-      const processor = postcss([cssnano()]);
-      const result = await processor.process(before, { from: undefined });
-      // @todo sourcemap support (elsewhere first)
-      sheet = result.css;
-    }
-    // setNodeText(first, sheet);
-    first.textContent = sheet;
-  }
-
-  /**
-   * Given href, find the corresponding CSS asset
-   */
-  async getCssAsset(href) {
-    const outputPath = this.options.outputPath;
-    const publicPath = this.options.publicPath;
-
-    // CHECK - the output path
-    // path on disk (with output.publicPath removed)
-    let normalizedPath = href.replace(/^\//, '');
-    const pathPrefix = (publicPath || '').replace(/(^\/|\/$)/g, '') + '/';
-    if (normalizedPath.indexOf(pathPrefix) === 0) {
-      normalizedPath = normalizedPath
-        .substring(pathPrefix.length)
-        .replace(/^\//, '');
-    }
-    const filename = path.resolve(outputPath, normalizedPath);
-
-    // // try to find a matching asset by filename in webpack's output (not yet written to disk)
-    // const relativePath = path
-    //   .relative(outputPath, filename)
-    //   .replace(/^\.\//, '');
-    // const asset = ''; // compilation.assets[relativePath];
-
-    // // console.log('filename ', filename);
-    // // Attempt to read from assets, falling back to a disk read
-    // let sheet = asset && asset.source();
-
-    let sheet;
-
-    try {
-      sheet = await this.readFile(filename);
-      // this.logger.warn(
-      //   `Stylesheet "${relativePath}" not found in assets, but a file was located on disk.${
-      //     this.options.pruneSource
-      //       ? ' This means pruneSource will not be applied.'
-      //       : ''
-      //   }`
-      // );
-    } catch (e) {
-      this.logger.warn(`Unable to locate stylesheet: ${filename}`);
-    }
-
-    return sheet;
-  }
-
-  checkInlineThreshold(link, style, sheet) {
-    if (
-      this.options.inlineThreshold &&
-      sheet.length < this.options.inlineThreshold
-    ) {
-      const href = style.$$name;
-      style.$$reduce = false;
-      this.logger.info(
-        `\u001b[32mInlined all of ${href} (${sheet.length} was below the threshold of ${this.options.inlineThreshold})\u001b[39m`
-      );
-      // if (asset) {
-      //   delete compilation.assets[relativePath];
-      // } else {
-      //   this.logger.warn(
-      //     `  > ${href} was not found in assets. the resource may still be emitted but will be unreferenced.`
-      //   );
-      // }
-      link.remove();
-      return true;
-    }
-
-    return false;
-  }
-
-  /**
-   * Inline the stylesheets from options.additionalStylesheets (assuming it passes `options.filter`)
-   */
-  async embedAdditionalStylesheet(document) {
-    const styleSheetsIncluded = [];
-
-    const sources = await Promise.all(
-      this.options.additionalStylesheets.map((cssFile) => {
-        if (styleSheetsIncluded.includes(cssFile)) {
-          return;
-        }
-        styleSheetsIncluded.push(cssFile);
-        const style = document.createElement('style');
-        style.$$external = true;
-        return this.getCssAsset(cssFile, style).then((sheet) => [sheet, style]);
-      })
-    );
-
-    sources.forEach(([sheet, style]) => {
-      if (!sheet) return;
-      style.textContent = sheet;
-      document.head.appendChild(style);
-    });
-  }
-
-  /**
-   * Inline the target stylesheet referred to by a <link rel="stylesheet"> (assuming it passes `options.filter`)
-   */
-  async embedLinkedStylesheet(link) {
-    const href = link.getAttribute('href');
-    const media = link.getAttribute('media');
-    const document = link.ownerDocument;
-
-    const preloadMode = this.options.preload;
-
-    // skip filtered resources, or network resources if no filter is provided
-    // if (this.urlFilter ? this.urlFilter(href) : href.match(/^(https?:)?\/\//)) {
-    if (this.urlFilter ? this.urlFilter(href) : !(href || '').match(/\.css$/)) {
-      return Promise.resolve();
-    }
-
-    // the reduced critical CSS gets injected into a new <style> tag
-    const style = document.createElement('style');
-    style.$$external = true;
-    const sheet = await this.getCssAsset(href, style);
-
-    if (!sheet) {
-      return;
-    }
-
-    // style.appendChild(document.createTextNode(sheet));
-    style.textContent = sheet;
-    // style.innerHTML = sheet;
-    style.$$name = href;
-    style.$$links = [link];
-    link.parentNode.insertBefore(style, link);
-
-    if (this.checkInlineThreshold(link, style, sheet)) {
-      return;
-    }
-
-    // CSS loader is only injected for the first sheet, then this becomes an empty string
-    let cssLoaderPreamble =
-      "function $loadcss(u,m,l){(l=document.createElement('link')).rel='stylesheet';l.href=u;document.head.appendChild(l)}";
-    const lazy = preloadMode === 'js-lazy';
-    if (lazy) {
-      cssLoaderPreamble = cssLoaderPreamble.replace(
-        'l.href',
-        "l.media='print';l.onload=function(){l.media=m};l.href"
-      );
-    }
-
-    // Allow disabling any mutation of the stylesheet link:
-    if (preloadMode === false) return;
-
-    let noscriptFallback = false;
-
-    if (preloadMode === 'body') {
-      document.body.appendChild(link);
-    } else {
-      link.setAttribute('rel', 'preload');
-      link.setAttribute('as', 'style');
-      if (preloadMode === 'js' || preloadMode === 'js-lazy') {
-        const script = document.createElement('script');
-        const js = `${cssLoaderPreamble}$loadcss(${JSON.stringify(href)}${
-          lazy ? ',' + JSON.stringify(media || 'all') : ''
-        })`;
-        // script.appendChild(document.createTextNode(js));
-        script.textContent = js;
-        link.parentNode.insertBefore(script, link.nextSibling);
-        style.$$links.push(script);
-        cssLoaderPreamble = '';
-        noscriptFallback = true;
-      } else if (preloadMode === 'media') {
-        // @see https://github.com/filamentgroup/loadCSS/blob/af1106cfe0bf70147e22185afa7ead96c01dec48/src/loadCSS.js#L26
-        link.setAttribute('rel', 'stylesheet');
-        link.removeAttribute('as');
-        link.setAttribute('media', 'print');
-        link.setAttribute('onload', `this.media='${media || 'all'}'`);
-        noscriptFallback = true;
-      } else if (preloadMode === 'swap') {
-        link.setAttribute('onload', "this.rel='stylesheet'");
-        noscriptFallback = true;
-      } else {
-        const bodyLink = document.createElement('link');
-        bodyLink.setAttribute('rel', 'stylesheet');
-        if (media) bodyLink.setAttribute('media', media);
-        bodyLink.setAttribute('href', href);
-        document.body.appendChild(bodyLink);
-        style.$$links.push(bodyLink);
-      }
-    }
-
-    if (this.options.noscriptFallback !== false && noscriptFallback) {
-      const noscript = document.createElement('noscript');
-      const noscriptLink = document.createElement('link');
-      noscriptLink.setAttribute('rel', 'stylesheet');
-      noscriptLink.setAttribute('href', href);
-      if (media) noscriptLink.setAttribute('media', media);
-      noscript.appendChild(noscriptLink);
-      link.parentNode.insertBefore(noscript, link.nextSibling);
-      style.$$links.push(noscript);
-    }
-  }
-
-  /**
-   * Prune the source CSS files
-   */
-  pruneSource(style, before, sheetInverse) {
-    // if external stylesheet would be below minimum size, just inline everything
-    const minSize = this.options.minimumExternalSize;
-    const name = style.$$name;
-    if (minSize && sheetInverse.length < minSize) {
-      this.logger.info(
-        `\u001b[32mInlined all of ${name} (non-critical external stylesheet would have been ${sheetInverse.length}b, which was below the threshold of ${minSize})\u001b[39m`
-      );
-      // setNodeText(style, before);
-      style.textContent = before;
-      // remove any associated external resources/loaders:
-      if (style.$$links) {
-        for (const link of style.$$links) {
-          const parent = link.parentNode;
-          if (parent) parent.removeChild(link);
-        }
-      }
-
-      return true;
-    }
-
-    return false;
-  }
-
-  /**
-   * Parse the stylesheet within a <style> element, then reduce it to contain only rules used by the document.
-   */
-  async processStyle(style, document) {
-    if (style.$$reduce === false) return;
-
-    const name = style.$$name ? style.$$name.replace(/^\//, '') : 'inline CSS';
-    const options = this.options;
-    // const document = style.ownerDocument;
-    const head = document.querySelector('head');
-    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 = [];
-
-    // 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 === 'rule') {
-          // Filter the selector list down to only those match
-          rule.filterSelectors((sel) => {
-            // 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 = sel.replace(/(?:>\s*)?::?[a-z-]+\s*(\{|$)/gi, '$1').trim();
-            }
-            if (!sel) return false;
-
-            try {
-              return document.querySelector(sel) != null;
-            } catch (e) {
-              failedSelectors.push(sel + ' -> ' + e.message);
-              return false;
-            }
-          });
-          // If there are no matched selectors, remove the rule:
-          if (rule.selectors.length === 0) {
-            return false;
-          }
-
-          if (rule.declarations) {
-            for (let i = 0; i < rule.declarations.length; i++) {
-              const decl = rule.declarations[i];
-
-              // detect used fonts
-              if (decl.property && decl.property.match(/\bfont(-family)?\b/i)) {
-                criticalFonts += ' ' + decl.value;
-              }
-
-              // detect used keyframes
-              if (
-                decl.property === 'animation' ||
-                decl.property === 'animation-name'
-              ) {
-                // @todo: parse animation declarations and extract only the name. for now we'll do a lazy match.
-                const names = decl.value.split(/\s+/);
-                for (let j = 0; j < names.length; j++) {
-                  const name = names[j].trim();
-                  if (name) criticalKeyframeNames.push(name);
-                }
-              }
-            }
-          }
-        }
-
-        // keep font rules, they're handled in the second pass:
-        if (rule.type === 'font-face') return;
-
-        // If there are no remaining rules, remove the whole rule:
-        const rules = rule.rules && rule.rules.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 shouldPreloadFonts =
-      options.fonts === true || options.preloadFonts === true;
-    const shouldInlineFonts =
-      options.fonts !== false && options.inlineFonts === true;
-
-    const preloadedFonts = [];
-    // 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 === 'keyframes') {
-        if (keyframesMode === 'none') return false;
-        if (keyframesMode === 'all') return true;
-        return criticalKeyframeNames.indexOf(rule.name) !== -1;
-      }
-
-      // prune @font-face rules
-      if (rule.type === 'font-face') {
-        let family, src;
-        for (let i = 0; i < rule.declarations.length; i++) {
-          const decl = rule.declarations[i];
-          if (decl.property === '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.property === 'font-family') {
-            family = decl.value;
-          }
-        }
-
-        if (src && shouldPreloadFonts && preloadedFonts.indexOf(src) === -1) {
-          preloadedFonts.push(src);
-          const preload = document.createElement('link');
-          preload.setAttribute('rel', 'preload');
-          preload.setAttribute('as', 'font');
-          preload.setAttribute('crossorigin', 'anonymous');
-          preload.setAttribute('href', src.trim());
-          head.appendChild(preload);
-        }
-
-        // if we're missing info, if the font is unused, or if critical font inlining is disabled, remove the rule:
-        if (
-          !family ||
-          !src ||
-          criticalFonts.indexOf(family) === -1 ||
-          !shouldInlineFonts
-        ) {
-          return false;
-        }
-      }
-    });
-
-    sheet = serializeStylesheet(ast, {
-      compress: this.options.compress !== false,
-    }).trim();
-
-    // 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 ${prettyBytes(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 ' +
-        prettyBytes(sheet.length) +
-        ' (' +
-        percent +
-        '% of original ' +
-        prettyBytes(before.length) +
-        ') of ' +
-        name +
-        afterText +
-        '.\u001b[39m'
-    );
-  }
-}
