Index: frontend/node_modules/postcss-normalize/LICENSE.md
===================================================================
--- frontend/node_modules/postcss-normalize/LICENSE.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize/LICENSE.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,108 @@
+# CC0 1.0 Universal
+
+## Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an “owner”) of an original work of
+authorship and/or a database (each, a “Work”).
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific works
+(“Commons”) that the public can reliably and without fear of later claims of
+infringement build upon, modify, incorporate in other works, reuse and
+redistribute as freely as possible in any form whatsoever and for any purposes,
+including without limitation commercial purposes. These owners may contribute
+to the Commons to promote the ideal of a free culture and the further
+production of creative, cultural and scientific works, or to gain reputation or
+greater distribution for their Work in part through the use and efforts of
+others.
+
+For these and/or other purposes and motivations, and without any expectation of
+additional consideration or compensation, the person associating CC0 with a
+Work (the “Affirmer”), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and
+publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+   protected by copyright and related or neighboring rights (“Copyright and
+   Related Rights”). Copyright and Related Rights include, but are not limited
+   to, the following:
+   1. the right to reproduce, adapt, distribute, perform, display, communicate,
+      and translate a Work;
+   2. moral rights retained by the original author(s) and/or performer(s);
+   3. publicity and privacy rights pertaining to a person’s image or likeness
+      depicted in a Work;
+   4. rights protecting against unfair competition in regards to a Work,
+      subject to the limitations in paragraph 4(i), below;
+   5. rights protecting the extraction, dissemination, use and reuse of data in
+      a Work;
+   6. database rights (such as those arising under Directive 96/9/EC of the
+      European Parliament and of the Council of 11 March 1996 on the legal
+      protection of databases, and under any national implementation thereof,
+      including any amended or successor version of such directive); and
+   7. other similar, equivalent or corresponding rights throughout the world
+      based on applicable law or treaty, and any national implementations
+      thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+   applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+   unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright
+   and Related Rights and associated claims and causes of action, whether now
+   known or unknown (including existing as well as future claims and causes of
+   action), in the Work (i) in all territories worldwide, (ii) for the maximum
+   duration provided by applicable law or treaty (including future time
+   extensions), (iii) in any current or future medium and for any number of
+   copies, and (iv) for any purpose whatsoever, including without limitation
+   commercial, advertising or promotional purposes (the “Waiver”). Affirmer
+   makes the Waiver for the benefit of each member of the public at large and
+   to the detriment of Affirmer’s heirs and successors, fully intending that
+   such Waiver shall not be subject to revocation, rescission, cancellation,
+   termination, or any other legal or equitable action to disrupt the quiet
+   enjoyment of the Work by the public as contemplated by Affirmer’s express
+   Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+   judged legally invalid or ineffective under applicable law, then the Waiver
+   shall be preserved to the maximum extent permitted taking into account
+   Affirmer’s express Statement of Purpose. In addition, to the extent the
+   Waiver is so judged Affirmer hereby grants to each affected person a
+   royalty-free, non transferable, non sublicensable, non exclusive,
+   irrevocable and unconditional license to exercise Affirmer’s Copyright and
+   Related Rights in the Work (i) in all territories worldwide, (ii) for the
+   maximum duration provided by applicable law or treaty (including future time
+   extensions), (iii) in any current or future medium and for any number of
+   copies, and (iv) for any purpose whatsoever, including without limitation
+   commercial, advertising or promotional purposes (the “License”). The License
+   shall be deemed effective as of the date CC0 was applied by Affirmer to the
+   Work. Should any part of the License for any reason be judged legally
+   invalid or ineffective under applicable law, such partial invalidity or
+   ineffectiveness shall not invalidate the remainder of the License, and in
+   such case Affirmer hereby affirms that he or she will not (i) exercise any
+   of his or her remaining Copyright and Related Rights in the Work or (ii)
+   assert any associated claims and causes of action with respect to the Work,
+   in either case contrary to Affirmer’s express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+   1. No trademark or patent rights held by Affirmer are waived, abandoned,
+      surrendered, licensed or otherwise affected by this document.
+   2. Affirmer offers the Work as-is and makes no representations or warranties
+      of any kind concerning the Work, express, implied, statutory or
+      otherwise, including without limitation warranties of title,
+      merchantability, fitness for a particular purpose, non infringement, or
+      the absence of latent or other defects, accuracy, or the present or
+      absence of errors, whether or not discoverable, all to the greatest
+      extent permissible under applicable law.
+   3. Affirmer disclaims responsibility for clearing rights of other persons
+      that may apply to the Work or any use thereof, including without
+      limitation any person’s Copyright and Related Rights in the Work.
+      Further, Affirmer disclaims responsibility for obtaining any necessary
+      consents, permissions or other rights required for any use of the Work.
+   4. Affirmer understands and acknowledges that Creative Commons is not a
+      party to this document and has no duty or obligation with respect to this
+      CC0 or use of the Work.
+
+For more information, please see
+http://creativecommons.org/publicdomain/zero/1.0/.
Index: frontend/node_modules/postcss-normalize/README.md
===================================================================
--- frontend/node_modules/postcss-normalize/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,210 @@
+# PostCSS Normalize [<img src="https://postcss.github.io/postcss/logo.svg" alt="PostCSS" width="90" height="90" align="right">][postcss]
+
+[<img alt="npm version" src="https://img.shields.io/npm/v/postcss-normalize.svg" height="20">][npm-url]
+[<img alt="build status" src="https://img.shields.io/travis/csstools/postcss-normalize/main.svg" height="20">][cli-url]
+[<img alt="support chat" src="https://img.shields.io/badge/support-chat-blue.svg" height="20">][git-url]
+
+[PostCSS Normalize] lets you use the parts of [normalize.css] or [sanitize.css]
+that you need from your [browserslist].
+
+```css
+@import "normalize.css";
+```
+
+```css
+@import "sanitize.css";
+```
+
+**PostCSS Normalize** uses a non-opinionated version of [normalize.css], but
+an opinionated version may also be used.
+
+```css
+@import "normalize.css/opinionated.css";
+```
+
+### Examples
+
+Here is a sample of what **normalize.css** looks like when the **browserslist**
+is `ie >= 9`:
+
+```css
+/**
+ * Add the correct display in IE 9-.
+ */
+
+audio,
+video {
+  display: inline-block;
+}
+
+/**
+ * Remove the border on images inside links in IE 10-.
+ */
+
+img {
+  border-style: none;
+}
+```
+
+And here is the same sample when the **browserslist** is `ie >= 10`:
+
+```css
+/**
+ * Remove the border on images inside links in IE 10-.
+ */
+
+img {
+  border-style: none;
+}
+```
+
+## Usage
+
+Add [PostCSS Normalize] to your project:
+
+```bash
+npm install postcss-normalize --save-dev
+```
+
+Add a [browserslist] entry in `package.json`:
+
+```json
+{
+  "browserslist": "last 2 versions"
+}
+```
+
+Use **PostCSS Normalize** to process your CSS:
+
+```js
+const postcssNormalize = require('postcss-normalize')
+
+postcssNormalize.process(YOUR_CSS /*, processOptions, pluginOptions */)
+```
+
+Or use it as a [PostCSS] plugin:
+
+```js
+const postcss = require('postcss')
+const postcssNormalize = require('postcss-normalize')
+
+postcss([
+  postcssNormalize(/* pluginOptions */)
+]).process(YOUR_CSS /*, processOptions */)
+```
+
+**PostCSS Normalize** runs in all Node environments, with special instructions
+for:
+
+| [Node](INSTALL.md#node) | [PostCSS CLI](INSTALL.md#postcss-cli) | [Webpack](INSTALL.md#webpack) | [Create React App](INSTALL.md#create-react-app) | [Gulp](INSTALL.md#gulp) | [Grunt](INSTALL.md#grunt) |
+| --- | --- | --- | --- | --- | --- |
+
+## PostCSS Import Usage
+
+**PostCSS Normalize** includes a `postcssImport` function to configure
+[PostCSS Import] and allow you to continue using the `@import` syntax.
+
+```js
+const postcss = require('postcss')
+const postcssImport = require('postcss-import')
+const postcssNormalize = require('postcss-normalize')
+
+postcss([
+  postcssImport(
+    postcssNormalize(
+      /* pluginOptions (for PostCSS Normalize) */
+    ).postcssImport(
+      /* pluginOptions (for PostCSS Import) */
+    )
+  )
+]) // now you can use @import "normalize.css", etc. again
+```
+
+Alternatively, use `@import-normalize` or `@import-sanitize` to avoid conflicts
+with `@import` transforms.
+
+```pcss
+@import-normalize;
+```
+
+```pcss
+@import-normalize "opinionated.css";
+```
+
+```pcss
+@import-sanitize;
+```
+
+## Options
+
+### allowDuplicates
+
+The `allowDuplicates` option determines whether multiple, duplicate insertions
+of CSS libraries are allowed. By default, duplicate libraries are omitted.
+
+```js
+postcssNormalize({ allowDuplicates: true })
+```
+
+### forceImport
+
+The `forceImport` option defines CSS libraries that will be inserted at the
+beginning of the CSS file. Unless overriden by `allowDuplicates`, duplicate
+CSS libraries would still be omitted.
+
+```js
+postcssNormalize({ forceImport: true })
+```
+
+Specific CSS libraries may be defined.
+
+```js
+postcssNormalize({
+  forceImport: 'sanitize.css'
+})
+```
+
+### browsers
+
+The `browsers` option defines an override of the project’s **browserslist** for
+**PostCSS Normalize**. This option should be avoided in leui of a browserslist
+file.
+
+```js
+postcssNormalize({ browsers: 'last 2 versions' })
+```
+
+## CSS Libraries
+
+**PostCSS Normalize** can include [normalize.css] or [sanitize.css] and
+configure either with the following combinations:
+
+```css
+@import "normalize"; /* also, @import "normalize.css" */
+@import "normalize/opinionated"; /* also, @import "normalize.css/opinionated.css", @import "normalize.css/*" */
+@import "sanitize"; /* also, @import "sanitize.css" */
+@import "sanitize/assets"; /* also, @import "sanitize.css/assets.css" */
+@import "sanitize/forms"; /* also, @import "sanitize.css/forms.css" */
+@import "sanitize/reduce-motion"; /* also, @import "sanitize.css/reduce-motion.css" */
+@import "sanitize/system-ui"; /* also, @import "sanitize.css/system-ui.css" */
+@import "sanitize/typography"; /* also, @import "sanitize.css/typography.css" */
+@import "sanitize/ui-monospace"; /* also, @import "sanitize.css/ui-monospace.css" */
+@import "sanitize/*"; /* also, @import "sanitize.css/*" (sanitize + all additions) */
+```
+
+[cli-img]: https://img.shields.io/travis/csstools/postcss-normalize/main.svg
+[cli-url]: https://travis-ci.org/csstools/postcss-normalize
+[git-img]: https://img.shields.io/badge/support-chat-blue.svg
+[git-url]: https://gitter.im/postcss/postcss
+[npm-img]: https://img.shields.io/npm/v/postcss-normalize.svg
+[npm-url]: https://www.npmjs.com/package/postcss-normalize
+
+[browserslist]: http://browserl.ist/
+[CSS Libraries]: #css-libraries
+[normalize.css]: https://github.com/csstools/normalize.css
+[Options]: #options
+[PostCSS]: https://github.com/postcss/postcss
+[PostCSS Import]: https://github.com/postcss/postcss-import
+[PostCSS Import Usage]: #postcss-import-usage
+[PostCSS Normalize]: https://github.com/csstools/postcss-normalize
+[sanitize.css]: https://github.com/csstools/sanitize.css
Index: frontend/node_modules/postcss-normalize/index.cjs
===================================================================
--- frontend/node_modules/postcss-normalize/index.cjs	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize/index.cjs	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,197 @@
+var postcssBrowserComments = require('postcss-browser-comments');
+var Module = require('module');
+var path = require('path');
+
+var fs = require('fs');
+var postcss = require('postcss');
+
+function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
+
+var postcssBrowserComments__default = /*#__PURE__*/_interopDefaultLegacy(postcssBrowserComments);
+var Module__default = /*#__PURE__*/_interopDefaultLegacy(Module);
+var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
+var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
+var postcss__default = /*#__PURE__*/_interopDefaultLegacy(postcss);
+
+const assign = (...objects) => Object.assign(...objects);
+const create = (...objects) => assign(Object.create(null), ...objects);
+
+const currentFilename = __filename;
+const currentDirname = path__default['default'].dirname(currentFilename); // get resolved filenames for normalize.css
+
+const normalizeCSS = resolve('@csstools/normalize.css');
+const normalizeDir = path__default['default'].dirname(normalizeCSS);
+const normalizeOpinionatedCSS = path__default['default'].join(normalizeDir, 'opinionated.css'); // get resolved filenames for sanitize.css
+
+const sanitizeCSS = resolve('sanitize.css');
+const sanitizeDir = path__default['default'].dirname(sanitizeCSS);
+const sanitizeAssetsCSS = path__default['default'].join(sanitizeDir, 'assets.css');
+const sanitizeFormsCSS = path__default['default'].join(sanitizeDir, 'forms.css');
+const sanitizeReduceMotionCSS = path__default['default'].join(sanitizeDir, 'reduce-motion.css');
+const sanitizeTypographyCSS = path__default['default'].join(sanitizeDir, 'typography.css');
+const sanitizeSystemUiCSS = path__default['default'].join(sanitizeDir, 'system-ui.css');
+const sanitizeUiMonospace = path__default['default'].join(sanitizeDir, 'ui-monospace.css'); // export a hashmap of css library filenames
+
+const parsableFilenames = create({
+  [normalizeCSS]: true,
+  [normalizeOpinionatedCSS]: true,
+  [sanitizeCSS]: true,
+  [sanitizeAssetsCSS]: true,
+  [sanitizeFormsCSS]: true,
+  [sanitizeReduceMotionCSS]: true,
+  [sanitizeTypographyCSS]: true,
+  [sanitizeSystemUiCSS]: true,
+  [sanitizeUiMonospace]: true
+}); // export a hashmap of css library filenames by id
+
+const resolvedFilenamesById = create({
+  'normalize': [normalizeCSS],
+  'normalize/opinionated': [normalizeOpinionatedCSS],
+  'normalize/*': [normalizeOpinionatedCSS],
+  'sanitize': [sanitizeCSS],
+  'sanitize/assets': [sanitizeAssetsCSS],
+  'sanitize/forms': [sanitizeCSS, sanitizeFormsCSS],
+  'sanitize/page': [sanitizeAssetsCSS],
+  // deprecated; remaining for v10.0.0 compatibility
+  'sanitize/reduce-motion': [sanitizeCSS, sanitizeReduceMotionCSS],
+  'sanitize/system-ui': [sanitizeCSS, sanitizeSystemUiCSS],
+  'sanitize/typography': [sanitizeCSS, sanitizeTypographyCSS],
+  'sanitize/ui-monospace': [sanitizeCSS, sanitizeUiMonospace],
+  'sanitize/*': [sanitizeCSS, sanitizeFormsCSS]
+}); // get the resolved filename of a package/module
+
+function resolve(id) {
+  return resolve[id] = resolve[id] || Module__default['default']._resolveFilename(id, {
+    id: currentFilename,
+    filename: currentFilename,
+    paths: Module__default['default']._nodeModulePaths(currentDirname)
+  });
+}
+
+const cache$1 = create();
+async function readFile(filename) {
+  filename = path__default['default'].resolve(filename);
+  cache$1[filename] = cache$1[filename] || create();
+  return new Promise((resolve, reject) => fs__default['default'].stat(filename, (statsError, {
+    mtime
+  }) => statsError ? reject(statsError) : mtime === cache$1[filename].mtime ? resolve(cache$1[filename].data) : fs__default['default'].readFile(filename, 'utf8', (readFileError, data) => readFileError ? reject(readFileError) : resolve((cache$1[filename] = {
+    data,
+    mtime
+  }).data))));
+}
+
+const cache = create(null);
+var parse = ((filename, transformer) => readFile(filename).then( // cache the parsed css root
+css => cache[css] = cache[css] || postcss__default['default'].parse(css, {
+  from: filename
+})).then( // clone the cached root
+root => root.clone()).then( // transform the cloned root
+clone => Promise.resolve(transformer(clone)).then( // resolve the cloned root
+() => clone)));
+
+var postcssImportNormalize = (commentsTransformer => opts => {
+  opts = create(opts); // return an postcss-import configuration
+
+  return create({
+    load(filename, importOptions) {
+      return filename in parsableFilenames // parse the file (the file and css are conservatively cached)
+      ? parse(filename, commentsTransformer).then(root => root.toResult({
+        to: filename,
+        map: true
+      }).css) : typeof opts.load === 'function' // otherwise, use the override loader
+      ? opts.load.call(null, filename, importOptions) // otherwise, return the (conservatively cached) contents of the file
+      : readFile(filename);
+    },
+
+    resolve(id, basedir, importOptions) {
+      // get the css id by removing css extensions
+      const cssId = id.replace(cssExtRegExp$1, '');
+      return cssId in resolvedFilenamesById // return the known resolved path for the css id
+      ? resolvedFilenamesById[cssId] : typeof opts.resolve === 'function' // otherwise, use the override resolver
+      ? opts.resolve.call(null, id, basedir, importOptions) // otherwise, return the id to be resolved by postcss-import
+      : id;
+    }
+
+  });
+});
+const cssExtRegExp$1 = /\.css\b/g;
+
+const postcssPlugin = (commentsTransformer, opts) => root => {
+  const promises = [];
+  const insertedFilenames = {}; // use @import insertion point
+
+  root.walkAtRules(importRegExp, atrule => {
+    // get name as a fallback value for the library (e.g. @import-normalize is like @import "normalize.css")
+    const name = atrule.name.match(importRegExp)[1]; // get url from "library", 'library', url("library"), url('library'), or the fallback value
+
+    const url = (atrule.params.match(paramsRegExp) || []).slice(1).find(part => part) || name;
+
+    if (url) {
+      // get the css id by removing css extensions
+      const cssId = url.replace(cssExtRegExp, '');
+
+      if (cssId in resolvedFilenamesById) {
+        // promise the library import is replaced with its contents
+        promises.push(Promise.all(resolvedFilenamesById[cssId].filter( // ignore filenames that have already been inserted
+        filename => insertedFilenames[filename] = opts.allowDuplicates || !(filename in insertedFilenames)).map( // parse the file (the file and css are conservatively cached)
+        filename => parse(filename, commentsTransformer))).then(roots => {
+          if (roots.length) {
+            // combine all the library nodes returned by the parsed files
+            const nodes = roots.reduce((all, root) => all.concat(root.nodes), []); // replace the import with all the library nodes
+
+            atrule.replaceWith(...nodes);
+          }
+        }));
+      }
+    }
+  });
+  return Promise.all([].concat( // promise the library imports are replaced with their contents
+  promises, // promise certain libraries are prepended
+  Promise.all([].concat(opts.forceImport || []).reduce( // filter the id to be a known id or boolean true
+  (all, id) => {
+    if (id === true) {
+      all.push(...resolvedFilenamesById.normalize);
+    } else if (typeof id === 'string') {
+      const cssId = id.replace(cssExtRegExp, '');
+
+      if (cssId in resolvedFilenamesById) {
+        all.push(...resolvedFilenamesById[cssId]);
+      }
+    }
+
+    return all;
+  }, []).filter( // ignore filenames that have already been inserted
+  filename => insertedFilenames[filename] = opts.allowDuplicates || !(filename in insertedFilenames)).map( // parse the file (the file and css are conservatively cached)
+  filename => parse(filename, commentsTransformer))).then(roots => {
+    if (roots.length) {
+      // combine all the library nodes returned by the parsed files
+      const nodes = roots.reduce((all, root) => all.concat(root.nodes), []); // prepend the stylesheet with all the library nodes
+
+      root.prepend(...nodes);
+    }
+  })));
+};
+
+const cssExtRegExp = /\.css\b/g;
+const importRegExp = /^import(?:-(normalize|sanitize))?$/;
+const paramsRegExp = /^\s*(?:url\((?:"(.+)"|'(.+)')\)|"(.+)"|'(.+)')[\W\w]*$/;
+
+const plugin = opts => {
+  opts = create(opts);
+  const commentsTransformer = postcssBrowserComments__default['default'](opts).Once;
+  const normalizeTransformer = postcssPlugin(commentsTransformer, opts);
+  const postcssImportConfig = postcssImportNormalize(commentsTransformer);
+  return {
+    postcssPlugin: 'postcss-normalize',
+
+    Once(root) {
+      return normalizeTransformer(root);
+    },
+
+    postcssImport: postcssImportConfig
+  };
+};
+
+plugin.postcss = true;
+
+module.exports = plugin;
Index: frontend/node_modules/postcss-normalize/index.d.ts
===================================================================
--- frontend/node_modules/postcss-normalize/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,26 @@
+import type * as PostCSS from 'postcss'
+
+export type PluginOptions = {
+	/** Determines whether multiple, duplicate insertions are allowed */
+	allowDuplicates?: boolean
+	/** Defines an override of the project’s browserslist for this plugin. */
+	browsers?: string
+	/** Defines whether imports from this plugin will always be inserted at the beginning of a CSS file. */
+	forceImport?: boolean
+}
+
+export type Plugin = {
+	(pluginOptions?: PluginOptions): {
+		postcssPlugin: 'postcss-normalize'
+		Once(root: PostCSS.Root): void
+		postcssImport: {
+			load(filename: string, importOptions: any): {}
+			resolve(id: string, basedir: string, importOptions: any): {}
+		}
+	}
+	postcss: true
+}
+
+declare const plugin: Plugin
+
+export default plugin
Index: frontend/node_modules/postcss-normalize/index.mjs
===================================================================
--- frontend/node_modules/postcss-normalize/index.mjs	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize/index.mjs	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,190 @@
+import postcssBrowserComments from 'postcss-browser-comments';
+import Module from 'module';
+import path from 'path';
+import { URL } from 'url';
+import fs from 'fs';
+import postcss from 'postcss';
+
+const assign = (...objects) => Object.assign(...objects);
+const create = (...objects) => assign(Object.create(null), ...objects);
+
+const currentURL = import.meta.url;
+const currentFilename = new URL(currentURL).pathname;
+const currentDirname = path.dirname(currentFilename); // get resolved filenames for normalize.css
+
+const normalizeCSS = resolve('@csstools/normalize.css');
+const normalizeDir = path.dirname(normalizeCSS);
+const normalizeOpinionatedCSS = path.join(normalizeDir, 'opinionated.css'); // get resolved filenames for sanitize.css
+
+const sanitizeCSS = resolve('sanitize.css');
+const sanitizeDir = path.dirname(sanitizeCSS);
+const sanitizeAssetsCSS = path.join(sanitizeDir, 'assets.css');
+const sanitizeFormsCSS = path.join(sanitizeDir, 'forms.css');
+const sanitizeReduceMotionCSS = path.join(sanitizeDir, 'reduce-motion.css');
+const sanitizeTypographyCSS = path.join(sanitizeDir, 'typography.css');
+const sanitizeSystemUiCSS = path.join(sanitizeDir, 'system-ui.css');
+const sanitizeUiMonospace = path.join(sanitizeDir, 'ui-monospace.css'); // export a hashmap of css library filenames
+
+const parsableFilenames = create({
+  [normalizeCSS]: true,
+  [normalizeOpinionatedCSS]: true,
+  [sanitizeCSS]: true,
+  [sanitizeAssetsCSS]: true,
+  [sanitizeFormsCSS]: true,
+  [sanitizeReduceMotionCSS]: true,
+  [sanitizeTypographyCSS]: true,
+  [sanitizeSystemUiCSS]: true,
+  [sanitizeUiMonospace]: true
+}); // export a hashmap of css library filenames by id
+
+const resolvedFilenamesById = create({
+  'normalize': [normalizeCSS],
+  'normalize/opinionated': [normalizeOpinionatedCSS],
+  'normalize/*': [normalizeOpinionatedCSS],
+  'sanitize': [sanitizeCSS],
+  'sanitize/assets': [sanitizeAssetsCSS],
+  'sanitize/forms': [sanitizeCSS, sanitizeFormsCSS],
+  'sanitize/page': [sanitizeAssetsCSS],
+  // deprecated; remaining for v10.0.0 compatibility
+  'sanitize/reduce-motion': [sanitizeCSS, sanitizeReduceMotionCSS],
+  'sanitize/system-ui': [sanitizeCSS, sanitizeSystemUiCSS],
+  'sanitize/typography': [sanitizeCSS, sanitizeTypographyCSS],
+  'sanitize/ui-monospace': [sanitizeCSS, sanitizeUiMonospace],
+  'sanitize/*': [sanitizeCSS, sanitizeFormsCSS]
+}); // get the resolved filename of a package/module
+
+function resolve(id) {
+  return resolve[id] = resolve[id] || Module._resolveFilename(id, {
+    id: currentFilename,
+    filename: currentFilename,
+    paths: Module._nodeModulePaths(currentDirname)
+  });
+}
+
+const cache$1 = create();
+async function readFile(filename) {
+  filename = path.resolve(filename);
+  cache$1[filename] = cache$1[filename] || create();
+  return new Promise((resolve, reject) => fs.stat(filename, (statsError, {
+    mtime
+  }) => statsError ? reject(statsError) : mtime === cache$1[filename].mtime ? resolve(cache$1[filename].data) : fs.readFile(filename, 'utf8', (readFileError, data) => readFileError ? reject(readFileError) : resolve((cache$1[filename] = {
+    data,
+    mtime
+  }).data))));
+}
+
+const cache = create(null);
+var parse = ((filename, transformer) => readFile(filename).then( // cache the parsed css root
+css => cache[css] = cache[css] || postcss.parse(css, {
+  from: filename
+})).then( // clone the cached root
+root => root.clone()).then( // transform the cloned root
+clone => Promise.resolve(transformer(clone)).then( // resolve the cloned root
+() => clone)));
+
+var postcssImportNormalize = (commentsTransformer => opts => {
+  opts = create(opts); // return an postcss-import configuration
+
+  return create({
+    load(filename, importOptions) {
+      return filename in parsableFilenames // parse the file (the file and css are conservatively cached)
+      ? parse(filename, commentsTransformer).then(root => root.toResult({
+        to: filename,
+        map: true
+      }).css) : typeof opts.load === 'function' // otherwise, use the override loader
+      ? opts.load.call(null, filename, importOptions) // otherwise, return the (conservatively cached) contents of the file
+      : readFile(filename);
+    },
+
+    resolve(id, basedir, importOptions) {
+      // get the css id by removing css extensions
+      const cssId = id.replace(cssExtRegExp$1, '');
+      return cssId in resolvedFilenamesById // return the known resolved path for the css id
+      ? resolvedFilenamesById[cssId] : typeof opts.resolve === 'function' // otherwise, use the override resolver
+      ? opts.resolve.call(null, id, basedir, importOptions) // otherwise, return the id to be resolved by postcss-import
+      : id;
+    }
+
+  });
+});
+const cssExtRegExp$1 = /\.css\b/g;
+
+const postcssPlugin = (commentsTransformer, opts) => root => {
+  const promises = [];
+  const insertedFilenames = {}; // use @import insertion point
+
+  root.walkAtRules(importRegExp, atrule => {
+    // get name as a fallback value for the library (e.g. @import-normalize is like @import "normalize.css")
+    const name = atrule.name.match(importRegExp)[1]; // get url from "library", 'library', url("library"), url('library'), or the fallback value
+
+    const url = (atrule.params.match(paramsRegExp) || []).slice(1).find(part => part) || name;
+
+    if (url) {
+      // get the css id by removing css extensions
+      const cssId = url.replace(cssExtRegExp, '');
+
+      if (cssId in resolvedFilenamesById) {
+        // promise the library import is replaced with its contents
+        promises.push(Promise.all(resolvedFilenamesById[cssId].filter( // ignore filenames that have already been inserted
+        filename => insertedFilenames[filename] = opts.allowDuplicates || !(filename in insertedFilenames)).map( // parse the file (the file and css are conservatively cached)
+        filename => parse(filename, commentsTransformer))).then(roots => {
+          if (roots.length) {
+            // combine all the library nodes returned by the parsed files
+            const nodes = roots.reduce((all, root) => all.concat(root.nodes), []); // replace the import with all the library nodes
+
+            atrule.replaceWith(...nodes);
+          }
+        }));
+      }
+    }
+  });
+  return Promise.all([].concat( // promise the library imports are replaced with their contents
+  promises, // promise certain libraries are prepended
+  Promise.all([].concat(opts.forceImport || []).reduce( // filter the id to be a known id or boolean true
+  (all, id) => {
+    if (id === true) {
+      all.push(...resolvedFilenamesById.normalize);
+    } else if (typeof id === 'string') {
+      const cssId = id.replace(cssExtRegExp, '');
+
+      if (cssId in resolvedFilenamesById) {
+        all.push(...resolvedFilenamesById[cssId]);
+      }
+    }
+
+    return all;
+  }, []).filter( // ignore filenames that have already been inserted
+  filename => insertedFilenames[filename] = opts.allowDuplicates || !(filename in insertedFilenames)).map( // parse the file (the file and css are conservatively cached)
+  filename => parse(filename, commentsTransformer))).then(roots => {
+    if (roots.length) {
+      // combine all the library nodes returned by the parsed files
+      const nodes = roots.reduce((all, root) => all.concat(root.nodes), []); // prepend the stylesheet with all the library nodes
+
+      root.prepend(...nodes);
+    }
+  })));
+};
+
+const cssExtRegExp = /\.css\b/g;
+const importRegExp = /^import(?:-(normalize|sanitize))?$/;
+const paramsRegExp = /^\s*(?:url\((?:"(.+)"|'(.+)')\)|"(.+)"|'(.+)')[\W\w]*$/;
+
+const plugin = opts => {
+  opts = create(opts);
+  const commentsTransformer = postcssBrowserComments(opts).Once;
+  const normalizeTransformer = postcssPlugin(commentsTransformer, opts);
+  const postcssImportConfig = postcssImportNormalize(commentsTransformer);
+  return {
+    postcssPlugin: 'postcss-normalize',
+
+    Once(root) {
+      return normalizeTransformer(root);
+    },
+
+    postcssImport: postcssImportConfig
+  };
+};
+
+plugin.postcss = true;
+
+export { plugin as default };
Index: frontend/node_modules/postcss-normalize/package.json
===================================================================
--- frontend/node_modules/postcss-normalize/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-normalize/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,96 @@
+{
+  "name": "postcss-normalize",
+  "version": "10.0.1",
+  "description": "Use the parts of normalize.css or sanitize.css you need from your browserslist",
+  "author": "Jonathan Neal <jonathantneal@hotmail.com>",
+  "license": "CC0-1.0",
+  "repository": "csstools/postcss-normalize",
+  "homepage": "https://github.com/csstools/postcss-normalize#readme",
+  "bugs": "https://github.com/csstools/postcss-normalize/issues",
+  "main": "./index.cjs",
+  "module": "./index.mjs",
+  "types": "./index.d.ts",
+  "exports": {
+    "require": "./index.cjs",
+    "import": "./index.mjs",
+    "default": "./index.mjs"
+  },
+  "files": [
+    "index.d.ts",
+    "index.cjs",
+    "index.mjs"
+  ],
+  "scripts": {
+    "prepublishOnly": "npm test",
+    "build": "rollup --config .rollup.js --silent",
+    "lint": "package-check && eslint --cache .gitignore --quiet",
+    "test": "npm run lint && npm run build && npm run tape",
+    "tape": "postcss-tape"
+  },
+  "engines": {
+    "node": ">= 12"
+  },
+  "peerDependencies": {
+    "browserslist": ">= 4",
+    "postcss": ">= 8"
+  },
+  "dependencies": {
+    "@csstools/normalize.css": "*",
+    "postcss-browser-comments": "^4",
+    "sanitize.css": "*"
+  },
+  "devDependencies": {
+    "@babel/core": "^7.15.5",
+    "@babel/plugin-syntax-import-meta": "^7.10.4",
+    "@babel/preset-env": "^7.15.6",
+    "@skypack/package-check": "^0.2.2",
+    "browserslist": "^4.16.5",
+    "eslint": "^7.32.0",
+    "postcss": "^8.2.13",
+    "postcss-import": "^14.0.2",
+    "postcss-tape": "^6.0.1",
+    "pre-commit": "^1.2.2",
+    "rollup": "^2.56.3",
+    "rollup-plugin-babel": "^4.4.0"
+  },
+  "babel": {
+    "plugins": [
+      "@babel/plugin-syntax-import-meta"
+    ],
+    "presets": [
+      [
+        "@babel/env",
+        {
+          "targets": "maintained node versions"
+        }
+      ]
+    ]
+  },
+  "eslintConfig": {
+    "extends": "eslint:recommended",
+    "ignorePatterns": [
+      ".tape.js"
+    ],
+    "parserOptions": {
+      "ecmaVersion": 12,
+      "sourceType": "module",
+      "ecmaFeatures": {
+        "modules": true
+      }
+    },
+    "rules": {
+      "semi": [
+        "error",
+        "never"
+      ]
+    }
+  },
+  "keywords": [
+    "postcss",
+    "css",
+    "postcss-plugin",
+    "normalizes",
+    "browsers",
+    "fixes"
+  ]
+}
