Index: frontend/node_modules/postcss-nested/index.js
===================================================================
--- frontend/node_modules/postcss-nested/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/postcss-nested/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,361 @@
+const { AtRule, Rule } = require('postcss')
+let parser = require('postcss-selector-parser')
+
+/**
+ * Run a selector string through postcss-selector-parser
+ */
+function parse(rawSelector, rule) {
+  let nodes
+  try {
+    parser(parsed => {
+      nodes = parsed
+    }).processSync(rawSelector)
+  } catch (e) {
+    if (rawSelector.includes(':')) {
+      throw rule ? rule.error('Missed semicolon') : e
+    } else {
+      throw rule ? rule.error(e.message) : e
+    }
+  }
+  return nodes.at(0)
+}
+
+/**
+ * Replaces the "&" token in a node's selector with the parent selector
+ * similar to what SCSS does.
+ *
+ * Mutates the nodes list
+ */
+function interpolateAmpInSelector(nodes, parent) {
+  let replaced = false
+  nodes.each(node => {
+    if (node.type === 'nesting') {
+      let clonedParent = parent.clone({})
+      if (node.value !== '&') {
+        node.replaceWith(
+          parse(node.value.replace('&', clonedParent.toString()))
+        )
+      } else {
+        node.replaceWith(clonedParent)
+      }
+      replaced = true
+    } else if ('nodes' in node && node.nodes) {
+      if (interpolateAmpInSelector(node, parent)) {
+        replaced = true
+      }
+    }
+  })
+  return replaced
+}
+
+/**
+ * Combines parent and child selectors, in a SCSS-like way
+ */
+function mergeSelectors(parent, child) {
+  let merged = []
+  parent.selectors.forEach(sel => {
+    let parentNode = parse(sel, parent)
+
+    child.selectors.forEach(selector => {
+      if (!selector) {
+        return
+      }
+      let node = parse(selector, child)
+      let replaced = interpolateAmpInSelector(node, parentNode)
+      if (!replaced) {
+        node.prepend(parser.combinator({ value: ' ' }))
+        node.prepend(parentNode.clone({}))
+      }
+      merged.push(node.toString())
+    })
+  })
+  return merged
+}
+
+/**
+ * Move a child and its preceeding comment(s) to after "after"
+ */
+function breakOut(child, after) {
+  let prev = child.prev()
+  after.after(child)
+  while (prev && prev.type === 'comment') {
+    let nextPrev = prev.prev()
+    after.after(prev)
+    prev = nextPrev
+  }
+  return child
+}
+
+function createFnAtruleChilds(bubble) {
+  return function atruleChilds(rule, atrule, bubbling, mergeSels = bubbling) {
+    let children = []
+    atrule.each(child => {
+      if (child.type === 'rule' && bubbling) {
+        if (mergeSels) {
+          child.selectors = mergeSelectors(rule, child)
+        }
+      } else if (child.type === 'atrule' && child.nodes) {
+        if (bubble[child.name]) {
+          atruleChilds(rule, child, mergeSels)
+        } else if (atrule[rootRuleMergeSel] !== false) {
+          children.push(child)
+        }
+      } else {
+        children.push(child)
+      }
+    })
+    if (bubbling) {
+      if (children.length) {
+        let clone = rule.clone({ nodes: [] })
+        for (let child of children) {
+          clone.append(child)
+        }
+        atrule.prepend(clone)
+      }
+    }
+  }
+}
+
+function pickDeclarations(selector, declarations, after) {
+  let parent = new Rule({
+    nodes: [],
+    selector
+  })
+  parent.append(declarations)
+  after.after(parent)
+  return parent
+}
+
+function atruleNames(defaults, custom) {
+  let list = {}
+  for (let name of defaults) {
+    list[name] = true
+  }
+  if (custom) {
+    for (let name of custom) {
+      list[name.replace(/^@/, '')] = true
+    }
+  }
+  return list
+}
+
+function parseRootRuleParams(params) {
+  params = params.trim()
+  let braceBlock = params.match(/^\((.*)\)$/)
+  if (!braceBlock) {
+    return { selector: params, type: 'basic' }
+  }
+  let bits = braceBlock[1].match(/^(with(?:out)?):(.+)$/)
+  if (bits) {
+    let allowlist = bits[1] === 'with'
+    let rules = Object.fromEntries(
+      bits[2]
+        .trim()
+        .split(/\s+/)
+        .map(name => [name, true])
+    )
+    if (allowlist && rules.all) {
+      return { type: 'noop' }
+    }
+    let escapes = rule => !!rules[rule]
+    if (rules.all) {
+      escapes = () => true
+    } else if (allowlist) {
+      escapes = rule => (rule === 'all' ? false : !rules[rule])
+    }
+
+    return {
+      escapes,
+      type: 'withrules'
+    }
+  }
+  // Unrecognized brace block
+  return { type: 'unknown' }
+}
+
+function getAncestorRules(leaf) {
+  let lineage = []
+  let parent = leaf.parent
+
+  while (parent && parent instanceof AtRule) {
+    lineage.push(parent)
+    parent = parent.parent
+  }
+  return lineage
+}
+
+function unwrapRootRule(rule) {
+  let escapes = rule[rootRuleEscapes]
+
+  if (!escapes) {
+    rule.after(rule.nodes)
+  } else {
+    let nodes = rule.nodes
+
+    let topEscaped
+    let topEscapedIdx = -1
+    let breakoutLeaf
+    let breakoutRoot
+    let clone
+
+    let lineage = getAncestorRules(rule)
+    lineage.forEach((parent, i) => {
+      if (escapes(parent.name)) {
+        topEscaped = parent
+        topEscapedIdx = i
+        breakoutRoot = clone
+      } else {
+        let oldClone = clone
+        clone = parent.clone({ nodes: [] })
+        oldClone && clone.append(oldClone)
+        breakoutLeaf = breakoutLeaf || clone
+      }
+    })
+
+    if (!topEscaped) {
+      rule.after(nodes)
+    } else if (!breakoutRoot) {
+      topEscaped.after(nodes)
+    } else {
+      let leaf = breakoutLeaf
+      leaf.append(nodes)
+      topEscaped.after(breakoutRoot)
+    }
+
+    if (rule.next() && topEscaped) {
+      let restRoot
+      lineage.slice(0, topEscapedIdx + 1).forEach((parent, i, arr) => {
+        let oldRoot = restRoot
+        restRoot = parent.clone({ nodes: [] })
+        oldRoot && restRoot.append(oldRoot)
+
+        let nextSibs = []
+        let _child = arr[i - 1] || rule
+        let next = _child.next()
+        while (next) {
+          nextSibs.push(next)
+          next = next.next()
+        }
+        restRoot.append(nextSibs)
+      })
+      restRoot && (breakoutRoot || nodes[nodes.length - 1]).after(restRoot)
+    }
+  }
+
+  rule.remove()
+}
+
+const rootRuleMergeSel = Symbol('rootRuleMergeSel')
+const rootRuleEscapes = Symbol('rootRuleEscapes')
+
+function normalizeRootRule(rule) {
+  let { params } = rule
+  let { escapes, selector, type } = parseRootRuleParams(params)
+  if (type === 'unknown') {
+    throw rule.error(
+      `Unknown @${rule.name} parameter ${JSON.stringify(params)}`
+    )
+  }
+  if (type === 'basic' && selector) {
+    let selectorBlock = new Rule({ nodes: rule.nodes, selector })
+    rule.removeAll()
+    rule.append(selectorBlock)
+  }
+  rule[rootRuleEscapes] = escapes
+  rule[rootRuleMergeSel] = escapes ? !escapes('all') : type === 'noop'
+}
+
+const hasRootRule = Symbol('hasRootRule')
+
+module.exports = (opts = {}) => {
+  let bubble = atruleNames(
+    ['media', 'supports', 'layer', 'container', 'starting-style'],
+    opts.bubble
+  )
+  let atruleChilds = createFnAtruleChilds(bubble)
+  let unwrap = atruleNames(
+    [
+      'document',
+      'font-face',
+      'keyframes',
+      '-webkit-keyframes',
+      '-moz-keyframes'
+    ],
+    opts.unwrap
+  )
+  let rootRuleName = (opts.rootRuleName || 'at-root').replace(/^@/, '')
+  let preserveEmpty = opts.preserveEmpty
+
+  return {
+    Once(root) {
+      root.walkAtRules(rootRuleName, node => {
+        normalizeRootRule(node)
+        root[hasRootRule] = true
+      })
+    },
+
+    postcssPlugin: 'postcss-nested',
+
+    RootExit(root) {
+      if (root[hasRootRule]) {
+        root.walkAtRules(rootRuleName, unwrapRootRule)
+        root[hasRootRule] = false
+      }
+    },
+
+    Rule(rule) {
+      let unwrapped = false
+      let after = rule
+      let copyDeclarations = false
+      let declarations = []
+
+      rule.each(child => {
+        if (child.type === 'rule') {
+          if (declarations.length) {
+            after = pickDeclarations(rule.selector, declarations, after)
+            declarations = []
+          }
+
+          copyDeclarations = true
+          unwrapped = true
+          child.selectors = mergeSelectors(rule, child)
+          after = breakOut(child, after)
+        } else if (child.type === 'atrule') {
+          if (declarations.length) {
+            after = pickDeclarations(rule.selector, declarations, after)
+            declarations = []
+          }
+          if (child.name === rootRuleName) {
+            unwrapped = true
+            atruleChilds(rule, child, true, child[rootRuleMergeSel])
+            after = breakOut(child, after)
+          } else if (bubble[child.name]) {
+            copyDeclarations = true
+            unwrapped = true
+            atruleChilds(rule, child, true)
+            after = breakOut(child, after)
+          } else if (unwrap[child.name]) {
+            copyDeclarations = true
+            unwrapped = true
+            atruleChilds(rule, child, false)
+            after = breakOut(child, after)
+          } else if (copyDeclarations) {
+            declarations.push(child)
+          }
+        } else if (child.type === 'decl' && copyDeclarations) {
+          declarations.push(child)
+        }
+      })
+
+      if (declarations.length) {
+        after = pickDeclarations(rule.selector, declarations, after)
+      }
+
+      if (unwrapped && preserveEmpty !== true) {
+        rule.raws.semicolon = true
+        if (rule.nodes.length === 0) rule.remove()
+      }
+    }
+  }
+}
+module.exports.postcss = true
