Index: frontend/node_modules/postcss-normalize-string/LICENSE-MIT
===================================================================
--- frontend/node_modules/postcss-normalize-string/LICENSE-MIT	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize-string/LICENSE-MIT	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+Copyright (c) Ben Briggs <beneb.info@gmail.com> (http://beneb.info)
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
Index: frontend/node_modules/postcss-normalize-string/README.md
===================================================================
--- frontend/node_modules/postcss-normalize-string/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize-string/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+# [postcss][postcss]-normalize-string
+
+> Normalize strings with PostCSS.
+
+## Install
+
+With [npm](https://npmjs.org/package/postcss-normalize-string) do:
+
+```
+npm install postcss-normalize-string --save
+```
+
+## Example
+
+### Input
+
+```css
+p:after{ content: '\\'string\\' is intact' }
+```
+
+### Output
+
+```css
+p:after{ content:"'string' is intact" }
+```
+
+## Usage
+
+See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
+examples for your environment.
+
+## API
+
+### normalize([options])
+
+#### options
+
+##### preferredQuote
+
+Type: `string`
+Default: `double`
+
+Sets what type of quote to prefer. Possible values are `single` and `double`.
+
+```js
+var css = 'p:after{content:""}';
+console.log(postcss(normalize({preferredQuote: 'single'})).process(css).css);
+//=> p:after{content:''}
+```
+
+## Contributors
+
+See [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTORS.md).
+
+## License
+
+MIT © [Ben Briggs](http://beneb.info)
+
+[postcss]: https://github.com/postcss/postcss
Index: frontend/node_modules/postcss-normalize-string/package.json
===================================================================
--- frontend/node_modules/postcss-normalize-string/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize-string/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,41 @@
+{
+  "name": "postcss-normalize-string",
+  "version": "5.1.0",
+  "description": "Normalize wrapping quotes for CSS string literals.",
+  "main": "src/index.js",
+  "types": "types/index.d.ts",
+  "files": [
+    "src",
+    "LICENSE-MIT",
+    "types"
+  ],
+  "keywords": [
+    "css",
+    "postcss",
+    "postcss-plugin"
+  ],
+  "license": "MIT",
+  "homepage": "https://github.com/cssnano/cssnano",
+  "author": {
+    "name": "Ben Briggs",
+    "email": "beneb.info@gmail.com",
+    "url": "http://beneb.info"
+  },
+  "repository": "cssnano/cssnano",
+  "dependencies": {
+    "postcss-value-parser": "^4.2.0"
+  },
+  "bugs": {
+    "url": "https://github.com/cssnano/cssnano/issues"
+  },
+  "engines": {
+    "node": "^10 || ^12 || >=14.0"
+  },
+  "devDependencies": {
+    "postcss": "^8.2.15"
+  },
+  "peerDependencies": {
+    "postcss": "^8.2.15"
+  },
+  "readme": "# [postcss][postcss]-normalize-string\n\n> Normalize strings with PostCSS.\n\n## Install\n\nWith [npm](https://npmjs.org/package/postcss-normalize-string) do:\n\n```\nnpm install postcss-normalize-string --save\n```\n\n## Example\n\n### Input\n\n```css\np:after{ content: '\\\\'string\\\\' is intact' }\n```\n\n### Output\n\n```css\np:after{ content:\"'string' is intact\" }\n```\n\n## Usage\n\nSee the [PostCSS documentation](https://github.com/postcss/postcss#usage) for\nexamples for your environment.\n\n## API\n\n### normalize([options])\n\n#### options\n\n##### preferredQuote\n\nType: `string`\nDefault: `double`\n\nSets what type of quote to prefer. Possible values are `single` and `double`.\n\n```js\nvar css = 'p:after{content:\"\"}';\nconsole.log(postcss(normalize({preferredQuote: 'single'})).process(css).css);\n//=> p:after{content:''}\n```\n\n## Contributors\n\nSee [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTORS.md).\n\n## License\n\nMIT © [Ben Briggs](http://beneb.info)\n\n[postcss]: https://github.com/postcss/postcss\n"
+}
Index: frontend/node_modules/postcss-normalize-string/src/index.js
===================================================================
--- frontend/node_modules/postcss-normalize-string/src/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize-string/src/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,319 @@
+'use strict';
+const valueParser = require('postcss-value-parser');
+
+/*
+ * Constants (parser usage)
+ */
+
+const SINGLE_QUOTE = "'".charCodeAt(0);
+const DOUBLE_QUOTE = '"'.charCodeAt(0);
+const BACKSLASH = '\\'.charCodeAt(0);
+const NEWLINE = '\n'.charCodeAt(0);
+const SPACE = ' '.charCodeAt(0);
+const FEED = '\f'.charCodeAt(0);
+const TAB = '\t'.charCodeAt(0);
+const CR = '\r'.charCodeAt(0);
+
+const WORD_END = /[ \n\t\r\f'"\\]/g;
+
+/*
+ * Constants (node type strings)
+ */
+
+const C_STRING = 'string';
+const C_ESCAPED_SINGLE_QUOTE = 'escapedSingleQuote';
+const C_ESCAPED_DOUBLE_QUOTE = 'escapedDoubleQuote';
+const C_SINGLE_QUOTE = 'singleQuote';
+const C_DOUBLE_QUOTE = 'doubleQuote';
+const C_NEWLINE = 'newline';
+const C_SINGLE = 'single';
+
+/*
+ * Literals
+ */
+
+const L_SINGLE_QUOTE = `'`;
+const L_DOUBLE_QUOTE = `"`;
+const L_NEWLINE = `\\\n`;
+
+/*
+ * Parser nodes
+ */
+
+const T_ESCAPED_SINGLE_QUOTE = { type: C_ESCAPED_SINGLE_QUOTE, value: `\\'` };
+const T_ESCAPED_DOUBLE_QUOTE = { type: C_ESCAPED_DOUBLE_QUOTE, value: `\\"` };
+const T_SINGLE_QUOTE = { type: C_SINGLE_QUOTE, value: L_SINGLE_QUOTE };
+const T_DOUBLE_QUOTE = { type: C_DOUBLE_QUOTE, value: L_DOUBLE_QUOTE };
+const T_NEWLINE = { type: C_NEWLINE, value: L_NEWLINE };
+
+/** @typedef {T_ESCAPED_SINGLE_QUOTE | T_ESCAPED_DOUBLE_QUOTE | T_SINGLE_QUOTE | T_NEWLINE} StringAstNode */
+/**
+ * @typedef {{nodes: StringAstNode[],
+ *            types: {escapedSingleQuote: number, escapedDoubleQuote: number, singleQuote: number, doubleQuote: number},
+ *            quotes: boolean}} StringAst
+ */
+
+/**
+ * @param {StringAst} ast
+ * @return {string}
+ */
+function stringify(ast) {
+  return ast.nodes.reduce((str, { value }) => {
+    // Collapse multiple line strings automatically
+    if (value === L_NEWLINE) {
+      return str;
+    }
+
+    return str + value;
+  }, '');
+}
+
+/**
+ * @param {string} str
+ * @return {StringAst}
+ */
+function parse(str) {
+  let code, next, value;
+  let pos = 0;
+  let len = str.length;
+
+  /** @type StringAst */
+  const ast = {
+    nodes: [],
+    types: {
+      escapedSingleQuote: 0,
+      escapedDoubleQuote: 0,
+      singleQuote: 0,
+      doubleQuote: 0,
+    },
+    quotes: false,
+  };
+
+  while (pos < len) {
+    code = str.charCodeAt(pos);
+
+    switch (code) {
+      case SPACE:
+      case TAB:
+      case CR:
+      case FEED:
+        next = pos;
+
+        do {
+          next += 1;
+          code = str.charCodeAt(next);
+        } while (
+          code === SPACE ||
+          code === NEWLINE ||
+          code === TAB ||
+          code === CR ||
+          code === FEED
+        );
+
+        ast.nodes.push({
+          type: 'space',
+          value: str.slice(pos, next),
+        });
+        pos = next - 1;
+        break;
+      case SINGLE_QUOTE:
+        ast.nodes.push(T_SINGLE_QUOTE);
+        ast.types[C_SINGLE_QUOTE]++;
+        ast.quotes = true;
+        break;
+      case DOUBLE_QUOTE:
+        ast.nodes.push(T_DOUBLE_QUOTE);
+        ast.types[C_DOUBLE_QUOTE]++;
+        ast.quotes = true;
+        break;
+      case BACKSLASH:
+        next = pos + 1;
+
+        if (str.charCodeAt(next) === SINGLE_QUOTE) {
+          ast.nodes.push(T_ESCAPED_SINGLE_QUOTE);
+          ast.types[C_ESCAPED_SINGLE_QUOTE]++;
+          ast.quotes = true;
+          pos = next;
+          break;
+        } else if (str.charCodeAt(next) === DOUBLE_QUOTE) {
+          ast.nodes.push(T_ESCAPED_DOUBLE_QUOTE);
+          ast.types[C_ESCAPED_DOUBLE_QUOTE]++;
+          ast.quotes = true;
+          pos = next;
+          break;
+        } else if (str.charCodeAt(next) === NEWLINE) {
+          ast.nodes.push(T_NEWLINE);
+          pos = next;
+          break;
+        }
+      /*
+       * We need to fall through here to handle the token as
+       * a whole word. The missing 'break' is intentional.
+       */
+      default:
+        WORD_END.lastIndex = pos + 1;
+        WORD_END.test(str);
+
+        if (WORD_END.lastIndex === 0) {
+          next = len - 1;
+        } else {
+          next = WORD_END.lastIndex - 2;
+        }
+
+        value = str.slice(pos, next + 1);
+
+        ast.nodes.push({
+          type: C_STRING,
+          value,
+        });
+
+        pos = next;
+    }
+    pos++;
+  }
+
+  return ast;
+}
+
+/**
+ * @param {valueParser.StringNode} node
+ * @param {StringAst} ast
+ * @return {void}
+ */
+function changeWrappingQuotes(node, ast) {
+  const { types } = ast;
+
+  if (types[C_SINGLE_QUOTE] || types[C_DOUBLE_QUOTE]) {
+    return;
+  }
+
+  if (
+    node.quote === L_SINGLE_QUOTE &&
+    types[C_ESCAPED_SINGLE_QUOTE] > 0 &&
+    !types[C_ESCAPED_DOUBLE_QUOTE]
+  ) {
+    node.quote = L_DOUBLE_QUOTE;
+  }
+
+  if (
+    node.quote === L_DOUBLE_QUOTE &&
+    types[C_ESCAPED_DOUBLE_QUOTE] > 0 &&
+    !types[C_ESCAPED_SINGLE_QUOTE]
+  ) {
+    node.quote = L_SINGLE_QUOTE;
+  }
+
+  ast.nodes = changeChildQuotes(ast.nodes, node.quote);
+}
+/**
+ * @param {StringAstNode[]} childNodes
+ * @param {string} parentQuote
+ * @return {StringAstNode[]}
+ */
+function changeChildQuotes(childNodes, parentQuote) {
+  const updatedChildren = [];
+  for (const child of childNodes) {
+    if (
+      child.type === C_ESCAPED_DOUBLE_QUOTE &&
+      parentQuote === L_SINGLE_QUOTE
+    ) {
+      updatedChildren.push(T_DOUBLE_QUOTE);
+    } else if (
+      child.type === C_ESCAPED_SINGLE_QUOTE &&
+      parentQuote === L_DOUBLE_QUOTE
+    ) {
+      updatedChildren.push(T_SINGLE_QUOTE);
+    } else {
+      updatedChildren.push(child);
+    }
+  }
+  return updatedChildren;
+}
+
+/**
+ * @param {string} value
+ * @param {'single' | 'double'} preferredQuote
+ * @return {string}
+ */
+function normalize(value, preferredQuote) {
+  if (!value || !value.length) {
+    return value;
+  }
+
+  return valueParser(value)
+    .walk((child) => {
+      if (child.type !== C_STRING) {
+        return;
+      }
+
+      const ast = parse(child.value);
+
+      if (ast.quotes) {
+        changeWrappingQuotes(child, ast);
+      } else if (preferredQuote === C_SINGLE) {
+        child.quote = L_SINGLE_QUOTE;
+      } else {
+        child.quote = L_DOUBLE_QUOTE;
+      }
+
+      child.value = stringify(ast);
+    })
+    .toString();
+}
+
+/**
+ * @param {string} original
+ * @param {Map<string, string>} cache
+ * @param {'single' | 'double'} preferredQuote
+ * @return {string}
+ */
+function minify(original, cache, preferredQuote) {
+  const key = original + '|' + preferredQuote;
+  if (cache.has(key)) {
+    return /** @type {string} */ (cache.get(key));
+  }
+  const newValue = normalize(original, preferredQuote);
+  cache.set(key, newValue);
+  return newValue;
+}
+
+/** @typedef {{preferredQuote?: 'double' | 'single'}} Options */
+/**
+ * @type {import('postcss').PluginCreator<Options>}
+ * @param {Options} opts
+ * @return {import('postcss').Plugin}
+ */
+function pluginCreator(opts) {
+  const { preferredQuote } = Object.assign(
+    {},
+    {
+      preferredQuote: 'double',
+    },
+    opts
+  );
+
+  return {
+    postcssPlugin: 'postcss-normalize-string',
+
+    OnceExit(css) {
+      const cache = new Map();
+
+      css.walk((node) => {
+        switch (node.type) {
+          case 'rule':
+            node.selector = minify(node.selector, cache, preferredQuote);
+            break;
+          case 'decl':
+            node.value = minify(node.value, cache, preferredQuote);
+            break;
+          case 'atrule':
+            node.params = minify(node.params, cache, preferredQuote);
+            break;
+        }
+      });
+    },
+  };
+}
+
+pluginCreator.postcss = true;
+module.exports = pluginCreator;
Index: frontend/node_modules/postcss-normalize-string/types/index.d.ts
===================================================================
--- frontend/node_modules/postcss-normalize-string/types/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize-string/types/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+export = pluginCreator;
+/** @typedef {{preferredQuote?: 'double' | 'single'}} Options */
+/**
+ * @type {import('postcss').PluginCreator<Options>}
+ * @param {Options} opts
+ * @return {import('postcss').Plugin}
+ */
+declare function pluginCreator(opts: Options): import('postcss').Plugin;
+declare namespace pluginCreator {
+    export { postcss, StringAstNode, StringAst, Options };
+}
+type Options = {
+    preferredQuote?: 'double' | 'single';
+};
+declare var postcss: true;
+type StringAstNode = {
+    type: string;
+    value: string;
+} | {
+    type: string;
+    value: string;
+} | {
+    type: string;
+    value: string;
+} | {
+    type: string;
+    value: string;
+};
+type StringAst = {
+    nodes: StringAstNode[];
+    types: {
+        escapedSingleQuote: number;
+        escapedDoubleQuote: number;
+        singleQuote: number;
+        doubleQuote: number;
+    };
+    quotes: boolean;
+};
