Index: trip-planner-front/node_modules/svgo/plugins/inlineStyles.js
===================================================================
--- trip-planner-front/node_modules/svgo/plugins/inlineStyles.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/svgo/plugins/inlineStyles.js	(revision 571e0df9a7a5e798c9941a85842f785177bedbbd)
@@ -1,22 +1,41 @@
 'use strict';
 
+/**
+ * @typedef {import('../lib/types').Specificity} Specificity
+ * @typedef {import('../lib/types').XastElement} XastElement
+ * @typedef {import('../lib/types').XastParent} XastParent
+ */
+
 const csstree = require('css-tree');
-const { querySelectorAll, closestByName } = require('../lib/xast.js');
-const cssTools = require('../lib/css-tools');
-
+// @ts-ignore not defined in @types/csso
+const specificity = require('csso/lib/restructure/prepare/specificity');
+const stable = require('stable');
+const {
+  visitSkip,
+  querySelectorAll,
+  detachNodeFromParent,
+} = require('../lib/xast.js');
+
+exports.type = 'visitor';
 exports.name = 'inlineStyles';
-
-exports.type = 'full';
-
 exports.active = true;
-
-exports.params = {
-  onlyMatchedOnce: true,
-  removeMatchedSelectors: true,
-  useMqs: ['', 'screen'],
-  usePseudos: [''],
+exports.description = 'inline styles (additional options)';
+
+/**
+ * Compares two selector specificities.
+ * extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211
+ *
+ * @type {(a: Specificity, b: Specificity) => number}
+ */
+const compareSpecificity = (a, b) => {
+  for (var i = 0; i < 4; i += 1) {
+    if (a[i] < b[i]) {
+      return -1;
+    } else if (a[i] > b[i]) {
+      return 1;
+    }
+  }
+  return 0;
 };
-
-exports.description = 'inline styles (additional options)';
 
 /**
@@ -39,266 +58,322 @@
  *     empty string element for all non-pseudo-classes and/or -elements
  *
- * @param {Object} root document element
- * @param {Object} opts plugin params
- *
  * @author strarsis <strarsis@gmail.com>
+ *
+ * @type {import('../lib/types').Plugin<{
+ *   onlyMatchedOnce?: boolean,
+ *   removeMatchedSelectors?: boolean,
+ *   useMqs?: Array<string>,
+ *   usePseudos?: Array<string>
+ * }>}
  */
-exports.fn = function (root, opts) {
-  // collect <style/>s
-  var styleEls = querySelectorAll(root, 'style');
-
-  //no <styles/>s, nothing to do
-  if (styleEls.length === 0) {
-    return root;
-  }
-
-  var styles = [],
-    selectors = [];
-
-  for (var styleEl of styleEls) {
-    // values other than the empty string or text/css are not used
-    if (
-      styleEl.attributes.type != null &&
-      styleEl.attributes.type !== '' &&
-      styleEl.attributes.type !== 'text/css'
-    ) {
-      continue;
-    }
-    // skip empty <style/>s or <foreignObject> content.
-    if (
-      styleEl.children.length === 0 ||
-      closestByName(styleEl, 'foreignObject')
-    ) {
-      continue;
-    }
-
-    var cssStr = cssTools.getCssStr(styleEl);
-
-    // collect <style/>s and their css ast
-    var cssAst = {};
-    try {
-      cssAst = csstree.parse(cssStr, {
-        parseValue: false,
-        parseCustomProperty: false,
-      });
-    } catch (parseError) {
-      // console.warn('Warning: Parse error of styles of <style/> element, skipped. Error details: ' + parseError);
-      continue;
-    }
-
-    styles.push({
-      styleEl: styleEl,
-      cssAst: cssAst,
-    });
-
-    selectors = selectors.concat(cssTools.flattenToSelectors(cssAst));
-  }
-
-  // filter for mediaqueries to be used or without any mediaquery
-  var selectorsMq = cssTools.filterByMqs(selectors, opts.useMqs);
-
-  // filter for pseudo elements to be used
-  var selectorsPseudo = cssTools.filterByPseudos(selectorsMq, opts.usePseudos);
-
-  // remove PseudoClass from its SimpleSelector for proper matching
-  cssTools.cleanPseudos(selectorsPseudo);
-
-  // stable sort selectors
-  var sortedSelectors = cssTools.sortSelectors(selectorsPseudo).reverse();
-
-  var selector, selectedEl;
-
-  // match selectors
-  for (selector of sortedSelectors) {
-    var selectorStr = csstree.generate(selector.item.data),
-      selectedEls = null;
-
-    try {
-      selectedEls = querySelectorAll(root, selectorStr);
-    } catch (selectError) {
-      // console.warn('Warning: Syntax error when trying to select \n\n' + selectorStr + '\n\n, skipped. Error details: ' + selectError);
-      continue;
-    }
-
-    if (selectedEls.length === 0) {
-      // nothing selected
-      continue;
-    }
-
-    selector.selectedEls = selectedEls;
-  }
-
-  // apply <style/> styles to matched elements
-  for (selector of sortedSelectors) {
-    if (!selector.selectedEls) {
-      continue;
-    }
-
-    if (
-      opts.onlyMatchedOnce &&
-      selector.selectedEls !== null &&
-      selector.selectedEls.length > 1
-    ) {
-      // skip selectors that match more than once if option onlyMatchedOnce is enabled
-      continue;
-    }
-
-    // apply <style/> to matched elements
-    for (selectedEl of selector.selectedEls) {
-      if (selector.rule === null) {
-        continue;
-      }
-      const styleDeclarationList = csstree.parse(
-        selectedEl.attributes.style == null ? '' : selectedEl.attributes.style,
-        {
-          context: 'declarationList',
-          parseValue: false,
-        }
-      );
-      const styleDeclarationItems = new Map();
-      csstree.walk(styleDeclarationList, {
-        visit: 'Declaration',
-        enter(node, item) {
-          styleDeclarationItems.set(node.property, item);
-        },
-      });
-      // merge declarations
-      csstree.walk(selector.rule, {
-        visit: 'Declaration',
-        enter(ruleDeclaration) {
-          // existing inline styles have higher priority
-          // no inline styles, external styles,                                    external styles used
-          // inline styles,    external styles same   priority as inline styles,   inline   styles used
-          // inline styles,    external styles higher priority than inline styles, external styles used
-          const matchedItem = styleDeclarationItems.get(
-            ruleDeclaration.property
-          );
-          const ruleDeclarationItem =
-            styleDeclarationList.children.createItem(ruleDeclaration);
-          if (matchedItem == null) {
-            styleDeclarationList.children.append(ruleDeclarationItem);
-          } else if (
-            matchedItem.data.important !== true &&
-            ruleDeclaration.important === true
+exports.fn = (root, params) => {
+  const {
+    onlyMatchedOnce = true,
+    removeMatchedSelectors = true,
+    useMqs = ['', 'screen'],
+    usePseudos = [''],
+  } = params;
+
+  /**
+   * @type {Array<{ node: XastElement, parentNode: XastParent, cssAst: csstree.StyleSheet }>}
+   */
+  const styles = [];
+  /**
+   * @type {Array<{
+   *   node: csstree.Selector,
+   *   item: csstree.ListItem<csstree.CssNode>,
+   *   rule: csstree.Rule,
+   *   matchedElements?: Array<XastElement>
+   * }>}
+   */
+  let selectors = [];
+
+  return {
+    element: {
+      enter: (node, parentNode) => {
+        // skip <foreignObject /> content
+        if (node.name === 'foreignObject') {
+          return visitSkip;
+        }
+        // collect only non-empty <style /> elements
+        if (node.name !== 'style' || node.children.length === 0) {
+          return;
+        }
+        // values other than the empty string or text/css are not used
+        if (
+          node.attributes.type != null &&
+          node.attributes.type !== '' &&
+          node.attributes.type !== 'text/css'
+        ) {
+          return;
+        }
+        // parse css in style element
+        let cssText = '';
+        for (const child of node.children) {
+          if (child.type === 'text' || child.type === 'cdata') {
+            cssText += child.value;
+          }
+        }
+        /**
+         * @type {null | csstree.CssNode}
+         */
+        let cssAst = null;
+        try {
+          cssAst = csstree.parse(cssText, {
+            parseValue: false,
+            parseCustomProperty: false,
+          });
+        } catch {
+          return;
+        }
+        if (cssAst.type === 'StyleSheet') {
+          styles.push({ node, parentNode, cssAst });
+        }
+
+        // collect selectors
+        csstree.walk(cssAst, {
+          visit: 'Selector',
+          enter(node, item) {
+            const atrule = this.atrule;
+            const rule = this.rule;
+            if (rule == null) {
+              return;
+            }
+
+            // skip media queries not included into useMqs param
+            let mq = '';
+            if (atrule != null) {
+              mq = atrule.name;
+              if (atrule.prelude != null) {
+                mq += ` ${csstree.generate(atrule.prelude)}`;
+              }
+            }
+            if (useMqs.includes(mq) === false) {
+              return;
+            }
+
+            /**
+             * @type {Array<{
+             *   item: csstree.ListItem<csstree.CssNode>,
+             *   list: csstree.List<csstree.CssNode>
+             * }>}
+             */
+            const pseudos = [];
+            if (node.type === 'Selector') {
+              node.children.each((childNode, childItem, childList) => {
+                if (
+                  childNode.type === 'PseudoClassSelector' ||
+                  childNode.type === 'PseudoElementSelector'
+                ) {
+                  pseudos.push({ item: childItem, list: childList });
+                }
+              });
+            }
+
+            // skip pseudo classes and pseudo elements not includes into usePseudos param
+            const pseudoSelectors = csstree.generate({
+              type: 'Selector',
+              children: new csstree.List().fromArray(
+                pseudos.map((pseudo) => pseudo.item.data)
+              ),
+            });
+            if (usePseudos.includes(pseudoSelectors) === false) {
+              return;
+            }
+
+            // remove pseudo classes and elements to allow querySelector match elements
+            // TODO this is not very accurate since some pseudo classes like first-child
+            // are used for selection
+            for (const pseudo of pseudos) {
+              pseudo.list.remove(pseudo.item);
+            }
+
+            selectors.push({ node, item, rule });
+          },
+        });
+      },
+    },
+
+    root: {
+      exit: () => {
+        if (styles.length === 0) {
+          return;
+        }
+        // stable sort selectors
+        const sortedSelectors = stable(selectors, (a, b) => {
+          const aSpecificity = specificity(a.item.data);
+          const bSpecificity = specificity(b.item.data);
+          return compareSpecificity(aSpecificity, bSpecificity);
+        }).reverse();
+
+        for (const selector of sortedSelectors) {
+          // match selectors
+          const selectorText = csstree.generate(selector.item.data);
+          /**
+           * @type {Array<XastElement>}
+           */
+          const matchedElements = [];
+          try {
+            for (const node of querySelectorAll(root, selectorText)) {
+              if (node.type === 'element') {
+                matchedElements.push(node);
+              }
+            }
+          } catch (selectError) {
+            continue;
+          }
+          // nothing selected
+          if (matchedElements.length === 0) {
+            continue;
+          }
+
+          // apply styles to matched elements
+          // skip selectors that match more than once if option onlyMatchedOnce is enabled
+          if (onlyMatchedOnce && matchedElements.length > 1) {
+            continue;
+          }
+
+          // apply <style/> to matched elements
+          for (const selectedEl of matchedElements) {
+            const styleDeclarationList = csstree.parse(
+              selectedEl.attributes.style == null
+                ? ''
+                : selectedEl.attributes.style,
+              {
+                context: 'declarationList',
+                parseValue: false,
+              }
+            );
+            if (styleDeclarationList.type !== 'DeclarationList') {
+              continue;
+            }
+            const styleDeclarationItems = new Map();
+            csstree.walk(styleDeclarationList, {
+              visit: 'Declaration',
+              enter(node, item) {
+                styleDeclarationItems.set(node.property, item);
+              },
+            });
+            // merge declarations
+            csstree.walk(selector.rule, {
+              visit: 'Declaration',
+              enter(ruleDeclaration) {
+                // existing inline styles have higher priority
+                // no inline styles, external styles,                                    external styles used
+                // inline styles,    external styles same   priority as inline styles,   inline   styles used
+                // inline styles,    external styles higher priority than inline styles, external styles used
+                const matchedItem = styleDeclarationItems.get(
+                  ruleDeclaration.property
+                );
+                const ruleDeclarationItem =
+                  styleDeclarationList.children.createItem(ruleDeclaration);
+                if (matchedItem == null) {
+                  styleDeclarationList.children.append(ruleDeclarationItem);
+                } else if (
+                  matchedItem.data.important !== true &&
+                  ruleDeclaration.important === true
+                ) {
+                  styleDeclarationList.children.replace(
+                    matchedItem,
+                    ruleDeclarationItem
+                  );
+                  styleDeclarationItems.set(
+                    ruleDeclaration.property,
+                    ruleDeclarationItem
+                  );
+                }
+              },
+            });
+            selectedEl.attributes.style =
+              csstree.generate(styleDeclarationList);
+          }
+
+          if (
+            removeMatchedSelectors &&
+            matchedElements.length !== 0 &&
+            selector.rule.prelude.type === 'SelectorList'
           ) {
-            styleDeclarationList.children.replace(
-              matchedItem,
-              ruleDeclarationItem
+            // clean up matching simple selectors if option removeMatchedSelectors is enabled
+            selector.rule.prelude.children.remove(selector.item);
+          }
+          selector.matchedElements = matchedElements;
+        }
+
+        // no further processing required
+        if (removeMatchedSelectors === false) {
+          return;
+        }
+
+        // clean up matched class + ID attribute values
+        for (const selector of sortedSelectors) {
+          if (selector.matchedElements == null) {
+            continue;
+          }
+
+          if (onlyMatchedOnce && selector.matchedElements.length > 1) {
+            // skip selectors that match more than once if option onlyMatchedOnce is enabled
+            continue;
+          }
+
+          for (const selectedEl of selector.matchedElements) {
+            // class
+            const classList = new Set(
+              selectedEl.attributes.class == null
+                ? null
+                : selectedEl.attributes.class.split(' ')
             );
-            styleDeclarationItems.set(
-              ruleDeclaration.property,
-              ruleDeclarationItem
-            );
-          }
-        },
-      });
-      selectedEl.attributes.style = csstree.generate(styleDeclarationList);
-    }
-
-    if (
-      opts.removeMatchedSelectors &&
-      selector.selectedEls !== null &&
-      selector.selectedEls.length > 0
-    ) {
-      // clean up matching simple selectors if option removeMatchedSelectors is enabled
-      selector.rule.prelude.children.remove(selector.item);
-    }
-  }
-
-  if (!opts.removeMatchedSelectors) {
-    return root; // no further processing required
-  }
-
-  // clean up matched class + ID attribute values
-  for (selector of sortedSelectors) {
-    if (!selector.selectedEls) {
-      continue;
-    }
-
-    if (
-      opts.onlyMatchedOnce &&
-      selector.selectedEls !== null &&
-      selector.selectedEls.length > 1
-    ) {
-      // skip selectors that match more than once if option onlyMatchedOnce is enabled
-      continue;
-    }
-
-    for (selectedEl of selector.selectedEls) {
-      // class
-      const classList = new Set(
-        selectedEl.attributes.class == null
-          ? null
-          : selectedEl.attributes.class.split(' ')
-      );
-      const firstSubSelector = selector.item.data.children.first();
-      if (firstSubSelector.type === 'ClassSelector') {
-        classList.delete(firstSubSelector.name);
-      }
-      if (classList.size === 0) {
-        delete selectedEl.attributes.class;
-      } else {
-        selectedEl.attributes.class = Array.from(classList).join(' ');
-      }
-
-      // ID
-      if (firstSubSelector.type === 'IdSelector') {
-        if (selectedEl.attributes.id === firstSubSelector.name) {
-          delete selectedEl.attributes.id;
-        }
-      }
-    }
-  }
-
-  // clean up now empty elements
-  for (var style of styles) {
-    csstree.walk(style.cssAst, {
-      visit: 'Rule',
-      enter: function (node, item, list) {
-        // clean up <style/> atrules without any rulesets left
-        if (
-          node.type === 'Atrule' &&
-          // only Atrules containing rulesets
-          node.block !== null &&
-          node.block.children.isEmpty()
-        ) {
-          list.remove(item);
-          return;
-        }
-
-        // clean up <style/> rulesets without any css selectors left
-        if (node.type === 'Rule' && node.prelude.children.isEmpty()) {
-          list.remove(item);
+            const firstSubSelector = selector.node.children.first();
+            if (
+              firstSubSelector != null &&
+              firstSubSelector.type === 'ClassSelector'
+            ) {
+              classList.delete(firstSubSelector.name);
+            }
+            if (classList.size === 0) {
+              delete selectedEl.attributes.class;
+            } else {
+              selectedEl.attributes.class = Array.from(classList).join(' ');
+            }
+
+            // ID
+            if (
+              firstSubSelector != null &&
+              firstSubSelector.type === 'IdSelector'
+            ) {
+              if (selectedEl.attributes.id === firstSubSelector.name) {
+                delete selectedEl.attributes.id;
+              }
+            }
+          }
+        }
+
+        for (const style of styles) {
+          csstree.walk(style.cssAst, {
+            visit: 'Rule',
+            enter: function (node, item, list) {
+              // clean up <style/> rulesets without any css selectors left
+              if (
+                node.type === 'Rule' &&
+                node.prelude.type === 'SelectorList' &&
+                node.prelude.children.isEmpty()
+              ) {
+                list.remove(item);
+              }
+            },
+          });
+
+          if (style.cssAst.children.isEmpty()) {
+            // remove emtpy style element
+            detachNodeFromParent(style.node, style.parentNode);
+          } else {
+            // update style element if any styles left
+            const firstChild = style.node.children[0];
+            if (firstChild.type === 'text' || firstChild.type === 'cdata') {
+              firstChild.value = csstree.generate(style.cssAst);
+            }
+          }
         }
       },
-    });
-
-    if (style.cssAst.children.isEmpty()) {
-      // clean up now emtpy <style/>s
-      var styleParentEl = style.styleEl.parentNode;
-      styleParentEl.spliceContent(
-        styleParentEl.children.indexOf(style.styleEl),
-        1
-      );
-
-      if (
-        styleParentEl.name === 'defs' &&
-        styleParentEl.children.length === 0
-      ) {
-        // also clean up now empty <def/>s
-        var defsParentEl = styleParentEl.parentNode;
-        defsParentEl.spliceContent(
-          defsParentEl.children.indexOf(styleParentEl),
-          1
-        );
-      }
-
-      continue;
-    }
-
-    // update existing, left over <style>s
-    cssTools.setCssStr(style.styleEl, csstree.generate(style.cssAst));
-  }
-
-  return root;
+    },
+  };
 };
Index: trip-planner-front/node_modules/svgo/plugins/prefixIds.js
===================================================================
--- trip-planner-front/node_modules/svgo/plugins/prefixIds.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/svgo/plugins/prefixIds.js	(revision 571e0df9a7a5e798c9941a85842f785177bedbbd)
@@ -207,13 +207,14 @@
             node.attributes[name].length !== 0
           ) {
-            // extract id reference from url(...) value
-            const matches = /url\((.*?)\)/gi.exec(node.attributes[name]);
-            if (matches != null) {
-              const value = matches[1];
-              const prefixed = prefixReference(prefix, value);
-              if (prefixed != null) {
-                node.attributes[name] = `url(${prefixed})`;
+            node.attributes[name] = node.attributes[name].replace(
+              /url\((.*?)\)/gi,
+              (match, url) => {
+                const prefixed = prefixReference(prefix, url);
+                if (prefixed == null) {
+                  return match;
+                }
+                return `url(${prefixed})`;
               }
-            }
+            );
           }
         }
Index: trip-planner-front/node_modules/svgo/plugins/removeEmptyAttrs.js
===================================================================
--- trip-planner-front/node_modules/svgo/plugins/removeEmptyAttrs.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/svgo/plugins/removeEmptyAttrs.js	(revision 571e0df9a7a5e798c9941a85842f785177bedbbd)
@@ -3,10 +3,7 @@
 const { attrsGroups } = require('./_collections.js');
 
+exports.type = 'visitor';
 exports.name = 'removeEmptyAttrs';
-
-exports.type = 'perItem';
-
 exports.active = true;
-
 exports.description = 'removes empty attributes';
 
@@ -14,20 +11,23 @@
  * Remove attributes with empty values.
  *
- * @param {Object} item current iteration item
- * @return {Boolean} if false, item will be filtered out
+ * @author Kir Belevich
  *
- * @author Kir Belevich
+ * @type {import('../lib/types').Plugin<void>}
  */
-exports.fn = function (item) {
-  if (item.type === 'element') {
-    for (const [name, value] of Object.entries(item.attributes)) {
-      if (
-        value === '' &&
-        // empty conditional processing attributes prevents elements from rendering
-        attrsGroups.conditionalProcessing.includes(name) === false
-      ) {
-        delete item.attributes[name];
-      }
-    }
-  }
+exports.fn = () => {
+  return {
+    element: {
+      enter: (node) => {
+        for (const [name, value] of Object.entries(node.attributes)) {
+          if (
+            value === '' &&
+            // empty conditional processing attributes prevents elements from rendering
+            attrsGroups.conditionalProcessing.includes(name) === false
+          ) {
+            delete node.attributes[name];
+          }
+        }
+      },
+    },
+  };
 };
Index: trip-planner-front/node_modules/svgo/plugins/removeXMLNS.js
===================================================================
--- trip-planner-front/node_modules/svgo/plugins/removeXMLNS.js	(revision 6a3a178323fd905112b5392bd9d3cb83b66ef2d3)
+++ trip-planner-front/node_modules/svgo/plugins/removeXMLNS.js	(revision 571e0df9a7a5e798c9941a85842f785177bedbbd)
@@ -26,4 +26,5 @@
   if (item.type === 'element' && item.name === 'svg') {
     delete item.attributes.xmlns;
+    delete item.attributes['xmlns:xlink'];
   }
 };
