[epiphany] Update highlight.js to 11.0.0



commit ddb6d73666e07de66fc979d9a440e521aa8dc3ad
Author: Jim Mason <jmason ibinx com>
Date:   Tue Jun 1 11:51:12 2021 +0000

    Update highlight.js to 11.0.0

 embed/ephy-view-source-handler.c                   |    2 +-
 third-party/highlightjs/README.epiphany            |    4 +-
 third-party/highlightjs/highlight.js               | 4080 ++++++++++----------
 third-party/highlightjs/highlightjs.gresource.xml  |    2 +-
 third-party/highlightjs/nnfx-dark.css              |   64 +-
 .../highlightjs/{nnfx.css => nnfx-light.css}       |   64 +-
 6 files changed, 2104 insertions(+), 2112 deletions(-)
---
diff --git a/embed/ephy-view-source-handler.c b/embed/ephy-view-source-handler.c
index ab9574908..115f4b718 100644
--- a/embed/ephy-view-source-handler.c
+++ b/embed/ephy-view-source-handler.c
@@ -124,7 +124,7 @@ web_resource_data_cb (WebKitWebResource     *resource,
   escaped_str = g_markup_escape_text ((const char *)data, length);
 
   html = g_strdup_printf ("<head>"
-                          "  <link rel='stylesheet' 
href='ephy-resource:///org/gnome/epiphany/highlightjs/nnfx.css' media='(prefers-color-scheme: no-preference), 
(prefers-color-scheme: light)'>"
+                          "  <link rel='stylesheet' 
href='ephy-resource:///org/gnome/epiphany/highlightjs/nnfx-light.css' media='(prefers-color-scheme: 
no-preference), (prefers-color-scheme: light)'>"
                           "  <link rel='stylesheet' 
href='ephy-resource:///org/gnome/epiphany/highlightjs/nnfx-dark.css' media='(prefers-color-scheme: dark)'>"
                           "  <link rel='stylesheet' 
href='ephy-resource:///org/gnome/epiphany/highlightjs/epiphany.css'>"
                           "  <title>%s</title>"
diff --git a/third-party/highlightjs/README.epiphany b/third-party/highlightjs/README.epiphany
index a86599554..73a36cd6c 100644
--- a/third-party/highlightjs/README.epiphany
+++ b/third-party/highlightjs/README.epiphany
@@ -11,8 +11,8 @@ npm install
 node tools/build.js -n css javascript xml
 
 Copy build/highlight.js to <epiphany-source>/third-party/highlightjs/
-Copy src/styles/nnfx.css to <epiphany-source>third-party/highlightjs/
-Copy src/styles/nnfx-dark.css to <epiphany-source>third-party/highlightjs/
+Copy src/styles/nnfx-light.css to <epiphany-source>/third-party/highlightjs/
+Copy src/styles/nnfx-dark.css to <epiphany-source>/third-party/highlightjs/
 
 # Highlight.js line numbers plugin:
 
diff --git a/third-party/highlightjs/highlight.js b/third-party/highlightjs/highlight.js
index 4dbbae9d4..601ae20b3 100644
--- a/third-party/highlightjs/highlight.js
+++ b/third-party/highlightjs/highlight.js
@@ -1,11 +1,13 @@
-/*
-  Highlight.js 10.7.1 (421b23b0)
+/*!
+  Highlight.js v11.0.0 (git: 21857218b9)
+  (c) 2006-2021 Ivan Sagalaev and other contributors
   License: BSD-3-Clause
-  Copyright (c) 2006-2021, Ivan Sagalaev
-*/
+ */
 var hljs = (function () {
     'use strict';
 
+    var deepFreezeEs6 = {exports: {}};
+
     function deepFreeze(obj) {
         if (obj instanceof Map) {
             obj.clear = obj.delete = obj.set = function () {
@@ -32,11 +34,15 @@ var hljs = (function () {
         return obj;
     }
 
-    var deepFreezeEs6 = deepFreeze;
-    var _default = deepFreeze;
-    deepFreezeEs6.default = _default;
+    deepFreezeEs6.exports = deepFreeze;
+    deepFreezeEs6.exports.default = deepFreeze;
+
+    var deepFreeze$1 = deepFreezeEs6.exports;
 
     
+    /** @typedef {import('highlight.js').CompiledMode} CompiledMode */
+    /** @implements CallbackResponse */
+
     class Response {
       /**
        * @param {CompiledMode} mode
@@ -75,7 +81,7 @@ var hljs = (function () {
      * @param {Record<string,any>[]} objects
      * @returns {T} a single new object
      */
-    function inherit(original, ...objects) {
+    function inherit$1(original, ...objects) {
       /** @type Record<string,any> */
       const result = Object.create(null);
 
@@ -112,6 +118,22 @@ var hljs = (function () {
       return !!node.kind;
     };
 
+    /**
+     *
+     * @param {string} name
+     * @param {{prefix:string}} options
+     */
+    const expandScopeName = (name, { prefix }) => {
+      if (name.includes(".")) {
+        const pieces = name.split(".");
+        return [
+          `${prefix}${pieces.shift()}`,
+          ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`))
+        ].join(" ");
+      }
+      return `${prefix}${name}`;
+    };
+
     /** @type {Renderer} */
     class HTMLRenderer {
       /**
@@ -141,11 +163,13 @@ var hljs = (function () {
       openNode(node) {
         if (!emitsWrappingTags(node)) return;
 
-        let className = node.kind;
-        if (!node.sublanguage) {
-          className = `${this.classPrefix}${className}`;
+        let scope = node.kind;
+        if (node.sublanguage) {
+          scope = `language-${scope}`;
+        } else {
+          scope = expandScopeName(scope, { prefix: this.classPrefix });
         }
-        this.span(className);
+        this.span(scope);
       }
 
       /**
@@ -178,6 +202,7 @@ var hljs = (function () {
 
     /** @typedef {{kind?: string, sublanguage?: boolean, children: Node[]} | string} Node */
     /** @typedef {{kind?: string, sublanguage?: boolean, children: Node[]} } DataNode */
+    /** @typedef {import('highlight.js').Emitter} Emitter */
     /**  */
 
     class TokenTree {
@@ -343,9 +368,6 @@ var hljs = (function () {
      * @param {string} value
      * @returns {RegExp}
      * */
-    function escape(value) {
-      return new RegExp(value.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'), 'm');
-    }
 
     /**
      * @param {RegExp | string } re
@@ -358,6 +380,22 @@ var hljs = (function () {
       return re.source;
     }
 
+    /**
+     * @param {RegExp | string } re
+     * @returns {string}
+     */
+    function lookahead(re) {
+      return concat('(?=', re, ')');
+    }
+
+    /**
+     * @param {RegExp | string } re
+     * @returns {string}
+     */
+    function optional(re) {
+      return concat('(?:', re, ')?');
+    }
+
     /**
      * @param {...(RegExp | string) } args
      * @returns {string}
@@ -367,6 +405,17 @@ var hljs = (function () {
       return joined;
     }
 
+    function stripOptionsFromArgs(args) {
+      const opts = args[args.length - 1];
+
+      if (typeof opts === 'object' && opts.constructor === Object) {
+        args.splice(args.length - 1, 1);
+        return opts;
+      } else {
+        return {};
+      }
+    }
+
     /**
      * Any of the passed expresssions may match
      *
@@ -375,7 +424,10 @@ var hljs = (function () {
      * @returns {string}
      */
     function either(...args) {
-      const joined = '(' + args.map((x) => source(x)).join("|") + ")";
+      const opts = stripOptionsFromArgs(args);
+      const joined = '(' +
+        (opts.capture ? "" : "?:") +
+        args.map((x) => source(x)).join("|") + ")";
       return joined;
     }
 
@@ -406,6 +458,7 @@ var hljs = (function () {
     //   follow the '(' with a '?'.
     const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
 
+    // **INTERNAL** Not intended for outside usage
     // join logically computes regexps.join(separator), but fixes the
     // backreferences so they continue to match.
     // it also places each individual regular expression into it's own
@@ -413,10 +466,10 @@ var hljs = (function () {
     // is currently an exercise for the caller. :-)
     /**
      * @param {(string | RegExp)[]} regexps
-     * @param {string} separator
+     * @param {{joinWith: string}} opts
      * @returns {string}
      */
-    function join(regexps, separator = "|") {
+    function _rewriteBackreferences(regexps, { joinWith }) {
       let numCaptures = 0;
 
       return regexps.map((regex) => {
@@ -444,12 +497,15 @@ var hljs = (function () {
           }
         }
         return out;
-      }).map(re => `(${re})`).join(separator);
+      }).map(re => `(${re})`).join(joinWith);
     }
 
+    /** @typedef {import('highlight.js').Mode} Mode */
+    /** @typedef {import('highlight.js').ModeCallback} ModeCallback */
+
     // Common regexps
     const MATCH_NOTHING_RE = /\b\B/;
-    const IDENT_RE = '[a-zA-Z]\\w*';
+    const IDENT_RE$1 = '[a-zA-Z]\\w*';
     const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';
     const NUMBER_RE = '\\b\\d+(\\.\\d+)?';
     const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 
0..., decimal, float
@@ -468,8 +524,8 @@ var hljs = (function () {
           opts.binary,
           /\b.*/);
       }
-      return inherit({
-        className: 'meta',
+      return inherit$1({
+        scope: 'meta',
         begin: beginShebang,
         end: /$/,
         relevance: 0,
@@ -485,14 +541,14 @@ var hljs = (function () {
       begin: '\\\\[\\s\\S]', relevance: 0
     };
     const APOS_STRING_MODE = {
-      className: 'string',
+      scope: 'string',
       begin: '\'',
       end: '\'',
       illegal: '\\n',
       contains: [BACKSLASH_ESCAPE]
     };
     const QUOTE_STRING_MODE = {
-      className: 'string',
+      scope: 'string',
       begin: '"',
       end: '"',
       illegal: '\\n',
@@ -510,54 +566,88 @@ var hljs = (function () {
      * @returns {Partial<Mode>}
      */
     const COMMENT = function(begin, end, modeOptions = {}) {
-      const mode = inherit(
+      const mode = inherit$1(
         {
-          className: 'comment',
+          scope: 'comment',
           begin,
           end,
           contains: []
         },
         modeOptions
       );
-      mode.contains.push(PHRASAL_WORDS_MODE);
       mode.contains.push({
-        className: 'doctag',
-        begin: '(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):',
+        scope: 'doctag',
+        // hack to avoid the space from being included. the space is necessary to
+        // match here to prevent the plain text rule below from gobbling up doctags
+        begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)',
+        end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,
+        excludeBegin: true,
         relevance: 0
       });
+      const ENGLISH_WORD = either(
+        // list of common 1 and 2 letter words in English
+        "I",
+        "a",
+        "is",
+        "so",
+        "us",
+        "to",
+        "at",
+        "if",
+        "in",
+        "it",
+        "on",
+        // note: this is not an exhaustive list of contractions, just popular ones
+        /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc
+        /[A-Za-z]+[-][a-z]+/, // `no-way`, etc.
+        /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences
+      );
+      // looking like plain text, more likely to be a comment
+      mode.contains.push(
+        {
+          // TODO: how to include ", (, ) without breaking grammars that use these for
+          // comment delimiters?
+          // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ 
]|\))){3}/
+          // ---
+
+          // this tries to find sequences of 3 english words in a row (without any
+          // "programming" type syntax) this gives us a strong signal that we've
+          // TRULY found a comment - vs perhaps scanning with the wrong language.
+          // It's possible to find something that LOOKS like the start of the
+          // comment - but then if there is no readable text - good chance it is a
+          // false match and not a comment.
+          //
+          // for a visual example please see:
+          // https://github.com/highlightjs/highlight.js/issues/2827
+
+          begin: concat(
+            /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */
+            '(',
+            ENGLISH_WORD,
+            /[.]?[:]?([.][ ]|[ ])/,
+            '){3}') // look for 3 words in a row
+        }
+      );
       return mode;
     };
     const C_LINE_COMMENT_MODE = COMMENT('//', '$');
     const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/');
     const HASH_COMMENT_MODE = COMMENT('#', '$');
     const NUMBER_MODE = {
-      className: 'number',
+      scope: 'number',
       begin: NUMBER_RE,
       relevance: 0
     };
     const C_NUMBER_MODE = {
-      className: 'number',
+      scope: 'number',
       begin: C_NUMBER_RE,
       relevance: 0
     };
     const BINARY_NUMBER_MODE = {
-      className: 'number',
+      scope: 'number',
       begin: BINARY_NUMBER_RE,
       relevance: 0
     };
-    const CSS_NUMBER_MODE = {
-      className: 'number',
-      begin: NUMBER_RE + '(' +
-        '%|em|ex|ch|rem' +
-        '|vw|vh|vmin|vmax' +
-        '|cm|mm|in|pt|pc|px' +
-        '|deg|grad|rad|turn' +
-        '|s|ms' +
-        '|Hz|kHz' +
-        '|dpi|dpcm|dppx' +
-        ')?',
-      relevance: 0
-    };
     const REGEXP_MODE = {
       // this outer rule makes sure we actually have a WHOLE regex and not simply
       // an expression such as:
@@ -567,7 +657,7 @@ var hljs = (function () {
       // (which will then blow up when regex's `illegal` sees the newline)
       begin: /(?=\/[^/\n]*\/)/,
       contains: [{
-        className: 'regexp',
+        scope: 'regexp',
         begin: /\//,
         end: /\/[gimuy]*/,
         illegal: /\n/,
@@ -583,12 +673,12 @@ var hljs = (function () {
       }]
     };
     const TITLE_MODE = {
-      className: 'title',
-      begin: IDENT_RE,
+      scope: 'title',
+      begin: IDENT_RE$1,
       relevance: 0
     };
     const UNDERSCORE_TITLE_MODE = {
-      className: 'title',
+      scope: 'title',
       begin: UNDERSCORE_IDENT_RE,
       relevance: 0
     };
@@ -615,10 +705,10 @@ var hljs = (function () {
         });
     };
 
-    var MODES = /*#__PURE__*/Object.freeze({
+    var MODES$1 = /*#__PURE__*/Object.freeze({
         __proto__: null,
         MATCH_NOTHING_RE: MATCH_NOTHING_RE,
-        IDENT_RE: IDENT_RE,
+        IDENT_RE: IDENT_RE$1,
         UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE,
         NUMBER_RE: NUMBER_RE,
         C_NUMBER_RE: C_NUMBER_RE,
@@ -636,7 +726,6 @@ var hljs = (function () {
         NUMBER_MODE: NUMBER_MODE,
         C_NUMBER_MODE: C_NUMBER_MODE,
         BINARY_NUMBER_MODE: BINARY_NUMBER_MODE,
-        CSS_NUMBER_MODE: CSS_NUMBER_MODE,
         REGEXP_MODE: REGEXP_MODE,
         TITLE_MODE: TITLE_MODE,
         UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE,
@@ -644,6 +733,11 @@ var hljs = (function () {
         END_SAME_AS_BEGIN: END_SAME_AS_BEGIN
     });
 
+    /**
+    @typedef {import('highlight.js').CallbackResponse} CallbackResponse
+    @typedef {import('highlight.js').CompilerExt} CompilerExt
+    */
+
     // Grammar extensions / plugins
     // See: https://github.com/highlightjs/highlight.js/issues/2833
 
@@ -668,13 +762,24 @@ var hljs = (function () {
      * @param {RegExpMatchArray} match
      * @param {CallbackResponse} response
      */
-    function skipIfhasPrecedingDot(match, response) {
+    function skipIfHasPrecedingDot(match, response) {
       const before = match.input[match.index - 1];
       if (before === ".") {
         response.ignoreMatch();
       }
     }
 
+    /**
+     *
+     * @type {CompilerExt}
+     */
+    function scopeClassName(mode, _parent) {
+      // eslint-disable-next-line no-undefined
+      if (mode.className !== undefined) {
+        mode.scope = mode.className;
+        delete mode.className;
+      }
+    }
 
     /**
      * `beginKeywords` syntactic sugar
@@ -690,7 +795,7 @@ var hljs = (function () {
       // doesn't allow spaces in keywords anyways and we still check for the boundary
       // first
       mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)';
-      mode.__beforeBegin = skipIfhasPrecedingDot;
+      mode.__beforeBegin = skipIfHasPrecedingDot;
       mode.keywords = mode.keywords || mode.beginKeywords;
       delete mode.beginKeywords;
 
@@ -731,6 +836,30 @@ var hljs = (function () {
       if (mode.relevance === undefined) mode.relevance = 1;
     }
 
+    // allow beforeMatch to act as a "qualifier" for the match
+    // the full match begin must be [beforeMatch][begin]
+    const beforeMatchExt = (mode, parent) => {
+      if (!mode.beforeMatch) return;
+      // starts conflicts with endsParent which we need to make sure the child
+      // rule is not matched multiple times
+      if (mode.starts) throw new Error("beforeMatch cannot be used with starts");
+
+      const originalMode = Object.assign({}, mode);
+      Object.keys(mode).forEach((key) => { delete mode[key]; });
+
+      mode.keywords = originalMode.keywords;
+      mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin));
+      mode.starts = {
+        relevance: 0,
+        contains: [
+          Object.assign(originalMode, { endsParent: true })
+        ]
+      };
+      mode.relevance = 0;
+
+      delete originalMode.beforeMatch;
+    };
+
     // keywords that should have no default relevance value
     const COMMON_KEYWORDS = [
       'of',
@@ -746,7 +875,7 @@ var hljs = (function () {
       'value' // common variable name
     ];
 
-    const DEFAULT_KEYWORD_CLASSNAME = "keyword";
+    const DEFAULT_KEYWORD_SCOPE = "keyword";
 
     /**
      * Given raw keywords from a language definition, compile them.
@@ -754,22 +883,22 @@ var hljs = (function () {
      * @param {string | Record<string,string|string[]> | Array<string>} rawKeywords
      * @param {boolean} caseInsensitive
      */
-    function compileKeywords(rawKeywords, caseInsensitive, className = DEFAULT_KEYWORD_CLASSNAME) {
+    function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) {
       /** @type KeywordDict */
-      const compiledKeywords = {};
+      const compiledKeywords = Object.create(null);
 
       // input can be a string of keywords, an array of keywords, or a object with
-      // named keys representing className (which can then point to a string or array)
+      // named keys representing scopeName (which can then point to a string or array)
       if (typeof rawKeywords === 'string') {
-        compileList(className, rawKeywords.split(" "));
+        compileList(scopeName, rawKeywords.split(" "));
       } else if (Array.isArray(rawKeywords)) {
-        compileList(className, rawKeywords);
+        compileList(scopeName, rawKeywords);
       } else {
-        Object.keys(rawKeywords).forEach(function(className) {
+        Object.keys(rawKeywords).forEach(function(scopeName) {
           // collapse all our objects back into the parent object
           Object.assign(
             compiledKeywords,
-            compileKeywords(rawKeywords[className], caseInsensitive, className)
+            compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName)
           );
         });
       }
@@ -782,16 +911,16 @@ var hljs = (function () {
        *
        * Ex: "for if when while|5"
        *
-       * @param {string} className
+       * @param {string} scopeName
        * @param {Array<string>} keywordList
        */
-      function compileList(className, keywordList) {
+      function compileList(scopeName, keywordList) {
         if (caseInsensitive) {
           keywordList = keywordList.map(x => x.toLowerCase());
         }
         keywordList.forEach(function(keyword) {
           const pair = keyword.split('|');
-          compiledKeywords[pair[0]] = [className, scoreForKeyword(pair[0], pair[1])];
+          compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])];
         });
       }
     }
@@ -822,6 +951,183 @@ var hljs = (function () {
       return COMMON_KEYWORDS.includes(keyword.toLowerCase());
     }
 
+    /*
+
+    For the reasoning behind this please see:
+    https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419
+
+    */
+
+    /**
+     * @type {Record<string, boolean>}
+     */
+    const seenDeprecations = {};
+
+    /**
+     * @param {string} message
+     */
+    const error = (message) => {
+      console.error(message);
+    };
+
+    /**
+     * @param {string} message
+     * @param {any} args
+     */
+    const warn = (message, ...args) => {
+      console.log(`WARN: ${message}`, ...args);
+    };
+
+    /**
+     * @param {string} version
+     * @param {string} message
+     */
+    const deprecated = (version, message) => {
+      if (seenDeprecations[`${version}/${message}`]) return;
+
+      console.log(`Deprecated as of ${version}. ${message}`);
+      seenDeprecations[`${version}/${message}`] = true;
+    };
+
+    /* eslint-disable no-throw-literal */
+
+    /**
+    @typedef {import('highlight.js').CompiledMode} CompiledMode
+    */
+
+    const MultiClassError = new Error();
+
+    /**
+     * Renumbers labeled scope names to account for additional inner match
+     * groups that otherwise would break everything.
+     *
+     * Lets say we 3 match scopes:
+     *
+     *   { 1 => ..., 2 => ..., 3 => ... }
+     *
+     * So what we need is a clean match like this:
+     *
+     *   (a)(b)(c) => [ "a", "b", "c" ]
+     *
+     * But this falls apart with inner match groups:
+     *
+     * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ]
+     *
+     * Our scopes are now "out of alignment" and we're repeating `b` 3 times.
+     * What needs to happen is the numbers are remapped:
+     *
+     *   { 1 => ..., 2 => ..., 5 => ... }
+     *
+     * We also need to know that the ONLY groups that should be output
+     * are 1, 2, and 5.  This function handles this behavior.
+     *
+     * @param {CompiledMode} mode
+     * @param {Array<RegExp>} regexes
+     * @param {{key: "beginScope"|"endScope"}} opts
+     */
+    function remapScopeNames(mode, regexes, { key }) {
+      let offset = 0;
+      const scopeNames = mode[key];
+      /** @type Record<number,boolean> */
+      const emit = {};
+      /** @type Record<number,string> */
+      const positions = {};
+
+      for (let i = 1; i <= regexes.length; i++) {
+        positions[i + offset] = scopeNames[i];
+        emit[i + offset] = true;
+        offset += countMatchGroups(regexes[i - 1]);
+      }
+      // we use _emit to keep track of which match groups are "top-level" to avoid double
+      // output from inside match groups
+      mode[key] = positions;
+      mode[key]._emit = emit;
+      mode[key]._multi = true;
+    }
+
+    /**
+     * @param {CompiledMode} mode
+     */
+    function beginMultiClass(mode) {
+      if (!Array.isArray(mode.begin)) return;
+
+      if (mode.skip || mode.excludeBegin || mode.returnBegin) {
+        error("skip, excludeBegin, returnBegin not compatible with beginScope: {}");
+        throw MultiClassError;
+      }
+
+      if (typeof mode.beginScope !== "object" || mode.beginScope === null) {
+        error("beginScope must be object");
+        throw MultiClassError;
+      }
+
+      remapScopeNames(mode, mode.begin, {key: "beginScope"});
+      mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" });
+    }
+
+    /**
+     * @param {CompiledMode} mode
+     */
+    function endMultiClass(mode) {
+      if (!Array.isArray(mode.end)) return;
+
+      if (mode.skip || mode.excludeEnd || mode.returnEnd) {
+        error("skip, excludeEnd, returnEnd not compatible with endScope: {}");
+        throw MultiClassError;
+      }
+
+      if (typeof mode.endScope !== "object" || mode.endScope === null) {
+        error("endScope must be object");
+        throw MultiClassError;
+      }
+
+      remapScopeNames(mode, mode.end, {key: "endScope"});
+      mode.end = _rewriteBackreferences(mode.end, { joinWith: "" });
+    }
+
+    /**
+     * this exists only to allow `scope: {}` to be used beside `match:`
+     * Otherwise `beginScope` would necessary and that would look weird
+
+      {
+        match: [ /def/, /\w+/ ]
+        scope: { 1: "keyword" , 2: "title" }
+      }
+
+     * @param {CompiledMode} mode
+     */
+    function scopeSugar(mode) {
+      if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) {
+        mode.beginScope = mode.scope;
+        delete mode.scope;
+      }
+    }
+
+    /**
+     * @param {CompiledMode} mode
+     */
+    function MultiClass(mode) {
+      scopeSugar(mode);
+
+      if (typeof mode.beginScope === "string") {
+        mode.beginScope = { _wrap: mode.beginScope };
+      }
+      if (typeof mode.endScope === "string") {
+        mode.endScope = { _wrap: mode.endScope };
+      }
+
+      beginMultiClass(mode);
+      endMultiClass(mode);
+    }
+
+    /**
+    @typedef {import('highlight.js').Mode} Mode
+    @typedef {import('highlight.js').CompiledMode} CompiledMode
+    @typedef {import('highlight.js').Language} Language
+    @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin
+    @typedef {import('highlight.js').CompiledLanguage} CompiledLanguage
+    */
+
     // compilation
 
     /**
@@ -830,12 +1136,11 @@ var hljs = (function () {
      * Given the raw result of a language definition (Language), compiles this so
      * that it is ready for highlighting code.
      * @param {Language} language
-     * @param {{plugins: HLJSPlugin[]}} opts
      * @returns {CompiledLanguage}
      */
-    function compileLanguage(language, { plugins }) {
+    function compileLanguage(language) {
       /**
-       * Builds a regex with the case sensativility of the current language
+       * Builds a regex with the case sensitivity of the current language
        *
        * @param {RegExp | string} value
        * @param {boolean} [global]
@@ -885,7 +1190,7 @@ var hljs = (function () {
             this.exec = () => null;
           }
           const terminators = this.regexes.map(el => el[1]);
-          this.matcherRe = langRe(join(terminators), true);
+          this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true);
           this.lastIndex = 0;
         }
 
@@ -1098,9 +1403,12 @@ var hljs = (function () {
         if (mode.isCompiled) return cmode;
 
         [
+          scopeClassName,
           // do this early so compiler extensions generally don't have to worry about
           // the distinction between match/begin
-          compileMatch
+          compileMatch,
+          MultiClass,
+          beforeMatchExt
         ].forEach(ext => ext(mode, parent));
 
         language.compilerExtensions.forEach(ext => ext(mode, parent));
@@ -1120,29 +1428,25 @@ var hljs = (function () {
         mode.isCompiled = true;
 
         let keywordPattern = null;
-        if (typeof mode.keywords === "object") {
+        if (typeof mode.keywords === "object" && mode.keywords.$pattern) {
+          // we need a copy because keywords might be compiled multiple times
+          // so we can't go deleting $pattern from the original on the first
+          // pass
+          mode.keywords = Object.assign({}, mode.keywords);
           keywordPattern = mode.keywords.$pattern;
           delete mode.keywords.$pattern;
         }
+        keywordPattern = keywordPattern || /\w+/;
 
         if (mode.keywords) {
           mode.keywords = compileKeywords(mode.keywords, language.case_insensitive);
         }
 
-        // both are not allowed
-        if (mode.lexemes && keywordPattern) {
-          throw new Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see 
mode reference) ");
-        }
-
-        // `mode.lexemes` was the old standard before we added and now recommend
-        // using `keywords.$pattern` to pass the keyword pattern
-        keywordPattern = keywordPattern || mode.lexemes || /\w+/;
         cmode.keywordPatternRe = langRe(keywordPattern, true);
 
         if (parent) {
           if (!mode.begin) mode.begin = /\B|\b/;
           cmode.beginRe = langRe(mode.begin);
-          if (mode.endSameAsBegin) mode.end = mode.begin;
           if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/;
           if (mode.end) cmode.endRe = langRe(mode.end);
           cmode.terminatorEnd = source(mode.end) || '';
@@ -1174,7 +1478,7 @@ var hljs = (function () {
       }
 
       // we need a null object, which inherit will guarantee
-      language.classNameAliases = inherit(language.classNameAliases || {});
+      language.classNameAliases = inherit$1(language.classNameAliases || {});
 
       return compileMode(/** @type Mode */ (language));
     }
@@ -1209,7 +1513,7 @@ var hljs = (function () {
     function expandOrCloneMode(mode) {
       if (mode.variants && !mode.cachedVariants) {
         mode.cachedVariants = mode.variants.map(function(variant) {
-          return inherit(mode, { variants: null }, variant);
+          return inherit$1(mode, { variants: null }, variant);
         });
       }
 
@@ -1225,344 +1529,112 @@ var hljs = (function () {
       // instance of ourselves, so we can be reused with many
       // different parents without issue
       if (dependencyOnParent(mode)) {
-        return inherit(mode, { starts: mode.starts ? inherit(mode.starts) : null });
+        return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null });
       }
 
       if (Object.isFrozen(mode)) {
-        return inherit(mode);
+        return inherit$1(mode);
       }
 
       // no special dependency issues, just return ourselves
       return mode;
     }
 
-    var version = "10.7.1";
-
-    // @ts-nocheck
-
-    function hasValueOrEmptyAttribute(value) {
-      return Boolean(value || value === "");
-    }
-
-    function BuildVuePlugin(hljs) {
-      const Component = {
-        props: ["language", "code", "autodetect"],
-        data: function() {
-          return {
-            detectedLanguage: "",
-            unknownLanguage: false
-          };
-        },
-        computed: {
-          className() {
-            if (this.unknownLanguage) return "";
-
-            return "hljs " + this.detectedLanguage;
-          },
-          highlighted() {
-            // no idea what language to use, return raw code
-            if (!this.autoDetect && !hljs.getLanguage(this.language)) {
-              console.warn(`The language "${this.language}" you specified could not be found.`);
-              this.unknownLanguage = true;
-              return escapeHTML(this.code);
-            }
-
-            let result = {};
-            if (this.autoDetect) {
-              result = hljs.highlightAuto(this.code);
-              this.detectedLanguage = result.language;
-            } else {
-              result = hljs.highlight(this.language, this.code, this.ignoreIllegals);
-              this.detectedLanguage = this.language;
-            }
-            return result.value;
-          },
-          autoDetect() {
-            return !this.language || hasValueOrEmptyAttribute(this.autodetect);
-          },
-          ignoreIllegals() {
-            return true;
-          }
-        },
-        // this avoids needing to use a whole Vue compilation pipeline just
-        // to build Highlight.js
-        render(createElement) {
-          return createElement("pre", {}, [
-            createElement("code", {
-              class: this.className,
-              domProps: { innerHTML: this.highlighted }
-            })
-          ]);
-        }
-        // template: `<pre><code :class="className" v-html="highlighted"></code></pre>`
-      };
-
-      const VuePlugin = {
-        install(Vue) {
-          Vue.component('highlightjs', Component);
-        }
-      };
-
-      return { Component, VuePlugin };
-    }
-
-    /* plugin itself */
-
-    /** @type {HLJSPlugin} */
-    const mergeHTMLPlugin = {
-      "after:highlightElement": ({ el, result, text }) => {
-        const originalStream = nodeStream(el);
-        if (!originalStream.length) return;
+    var version = "11.0.0";
 
-        const resultNode = document.createElement('div');
-        resultNode.innerHTML = result.value;
-        result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
-      }
-    };
-
-    /* Stream merging support functions */
+    /*
+    Syntax highlighting with language autodetection.
+    https://highlightjs.org/
+    */
 
     /**
-     * @typedef Event
-     * @property {'start'|'stop'} event
-     * @property {number} offset
-     * @property {Node} node
-     */
+    @typedef {import('highlight.js').Mode} Mode
+    @typedef {import('highlight.js').CompiledMode} CompiledMode
+    @typedef {import('highlight.js').Language} Language
+    @typedef {import('highlight.js').HLJSApi} HLJSApi
+    @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin
+    @typedef {import('highlight.js').PluginEvent} PluginEvent
+    @typedef {import('highlight.js').HLJSOptions} HLJSOptions
+    @typedef {import('highlight.js').LanguageFn} LanguageFn
+    @typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement
+    @typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext
+    @typedef {import('highlight.js/private').MatchType} MatchType
+    @typedef {import('highlight.js/private').KeywordData} KeywordData
+    @typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch
+    @typedef {import('highlight.js/private').AnnotatedError} AnnotatedError
+    @typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult
+    @typedef {import('highlight.js').HighlightOptions} HighlightOptions
+    @typedef {import('highlight.js').HighlightResult} HighlightResult
+    */
 
-    /**
-     * @param {Node} node
-     */
-    function tag(node) {
-      return node.nodeName.toLowerCase();
-    }
 
-    /**
-     * @param {Node} node
-     */
-    function nodeStream(node) {
-      /** @type Event[] */
-      const result = [];
-      (function _nodeStream(node, offset) {
-        for (let child = node.firstChild; child; child = child.nextSibling) {
-          if (child.nodeType === 3) {
-            offset += child.nodeValue.length;
-          } else if (child.nodeType === 1) {
-            result.push({
-              event: 'start',
-              offset: offset,
-              node: child
-            });
-            offset = _nodeStream(child, offset);
-            // Prevent void elements from having an end tag that would actually
-            // double them in the output. There are more void elements in HTML
-            // but we list only those realistically expected in code display.
-            if (!tag(child).match(/br|hr|img|input/)) {
-              result.push({
-                event: 'stop',
-                offset: offset,
-                node: child
-              });
-            }
-          }
-        }
-        return offset;
-      })(node, 0);
-      return result;
-    }
+    const escape = escapeHTML;
+    const inherit = inherit$1;
+    const NO_MATCH = Symbol("nomatch");
+    const MAX_KEYWORD_HITS = 7;
 
     /**
-     * @param {any} original - the original stream
-     * @param {any} highlighted - stream of the highlighted source
-     * @param {string} value - the original source itself
+     * @param {any} hljs - object that is extended (legacy)
+     * @returns {HLJSApi}
      */
-    function mergeStreams(original, highlighted, value) {
-      let processed = 0;
-      let result = '';
-      const nodeStack = [];
-
-      function selectStream() {
-        if (!original.length || !highlighted.length) {
-          return original.length ? original : highlighted;
-        }
-        if (original[0].offset !== highlighted[0].offset) {
-          return (original[0].offset < highlighted[0].offset) ? original : highlighted;
-        }
+    const HLJS = function(hljs) {
+      // Global internal variables used within the highlight.js library.
+      /** @type {Record<string, Language>} */
+      const languages = Object.create(null);
+      /** @type {Record<string, string>} */
+      const aliases = Object.create(null);
+      /** @type {HLJSPlugin[]} */
+      const plugins = [];
 
-        /*
-        To avoid starting the stream just before it should stop the order is
-        ensured that original always starts first and closes last:
+      // safe/production mode - swallows more errors, tries to keep running
+      // even if a single syntax or parse hits a fatal error
+      let SAFE_MODE = true;
+      const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a 
language module?";
+      /** @type {Language} */
+      const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] };
 
-        if (event1 == 'start' && event2 == 'start')
-          return original;
-        if (event1 == 'start' && event2 == 'stop')
-          return highlighted;
-        if (event1 == 'stop' && event2 == 'start')
-          return original;
-        if (event1 == 'stop' && event2 == 'stop')
-          return highlighted;
+      // Global options used when within external APIs. This is modified when
+      // calling the `hljs.configure` function.
+      /** @type HLJSOptions */
+      let options = {
+        ignoreUnescapedHTML: false,
+        noHighlightRe: /^(no-?highlight)$/i,
+        languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i,
+        classPrefix: 'hljs-',
+        cssSelector: 'pre code',
+        languages: null,
+        // beta configuration options, subject to change, welcome to discuss
+        // https://github.com/highlightjs/highlight.js/issues/1086
+        __emitter: TokenTreeEmitter
+      };
 
-        ... which is collapsed to:
-        */
-        return highlighted[0].event === 'start' ? original : highlighted;
-      }
+      /* Utility functions */
 
       /**
-       * @param {Node} node
+       * Tests a language name to see if highlighting should be skipped
+       * @param {string} languageName
        */
-      function open(node) {
-        /** @param {Attr} attr */
-        function attributeString(attr) {
-          return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
-        }
-        // @ts-ignore
-        result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('') + '>';
+      function shouldNotHighlight(languageName) {
+        return options.noHighlightRe.test(languageName);
       }
 
       /**
-       * @param {Node} node
+       * @param {HighlightedHTMLElement} block - the HTML element to determine language for
        */
-      function close(node) {
-        result += '</' + tag(node) + '>';
-      }
+      function blockLanguage(block) {
+        let classes = block.className + ' ';
 
-      /**
-       * @param {Event} event
-       */
-      function render(event) {
-        (event.event === 'start' ? open : close)(event.node);
-      }
+        classes += block.parentNode ? block.parentNode.className : '';
 
-      while (original.length || highlighted.length) {
-        let stream = selectStream();
-        result += escapeHTML(value.substring(processed, stream[0].offset));
-        processed = stream[0].offset;
-        if (stream === original) {
-          /*
-          On any opening or closing tag of the original markup we first close
-          the entire highlighted node stack, then render the original tag along
-          with all the following original tags at the same offset and then
-          reopen all the tags on the highlighted stack.
-          */
-          nodeStack.reverse().forEach(close);
-          do {
-            render(stream.splice(0, 1)[0]);
-            stream = selectStream();
-          } while (stream === original && stream.length && stream[0].offset === processed);
-          nodeStack.reverse().forEach(open);
-        } else {
-          if (stream[0].event === 'start') {
-            nodeStack.push(stream[0].node);
-          } else {
-            nodeStack.pop();
+        // language-* takes precedence over non-prefixed class names.
+        const match = options.languageDetectRe.exec(classes);
+        if (match) {
+          const language = getLanguage(match[1]);
+          if (!language) {
+            warn(LANGUAGE_NOT_FOUND.replace("{}", match[1]));
+            warn("Falling back to no-highlight mode for this block.", block);
           }
-          render(stream.splice(0, 1)[0]);
-        }
-      }
-      return result + escapeHTML(value.substr(processed));
-    }
-
-    /*
-
-    For the reasoning behind this please see:
-    https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419
-
-    */
-
-    /**
-     * @param {string} message
-     */
-    const error = (message) => {
-      console.error(message);
-    };
-
-    /**
-     * @param {string} message
-     * @param {any} args
-     */
-    const warn = (message, ...args) => {
-      console.log(`WARN: ${message}`, ...args);
-    };
-
-    /**
-     * @param {string} version
-     * @param {string} message
-     */
-    const deprecated = (version, message) => {
-      console.log(`Deprecated as of ${version}. ${message}`);
-    };
-
-    /*
-    Syntax highlighting with language autodetection.
-    https://highlightjs.org/
-    */
-
-    const escape$1 = escapeHTML;
-    const inherit$1 = inherit;
-    const NO_MATCH = Symbol("nomatch");
-
-    /**
-     * @param {any} hljs - object that is extended (legacy)
-     * @returns {HLJSApi}
-     */
-    const HLJS = function(hljs) {
-      // Global internal variables used within the highlight.js library.
-      /** @type {Record<string, Language>} */
-      const languages = Object.create(null);
-      /** @type {Record<string, string>} */
-      const aliases = Object.create(null);
-      /** @type {HLJSPlugin[]} */
-      const plugins = [];
-
-      // safe/production mode - swallows more errors, tries to keep running
-      // even if a single syntax or parse hits a fatal error
-      let SAFE_MODE = true;
-      const fixMarkupRe = /(^(<[^>]+>|\t|)+|\n)/gm;
-      const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a 
language module?";
-      /** @type {Language} */
-      const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] };
-
-      // Global options used when within external APIs. This is modified when
-      // calling the `hljs.configure` function.
-      /** @type HLJSOptions */
-      let options = {
-        noHighlightRe: /^(no-?highlight)$/i,
-        languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i,
-        classPrefix: 'hljs-',
-        tabReplace: null,
-        useBR: false,
-        languages: null,
-        // beta configuration options, subject to change, welcome to discuss
-        // https://github.com/highlightjs/highlight.js/issues/1086
-        __emitter: TokenTreeEmitter
-      };
-
-      /* Utility functions */
-
-      /**
-       * Tests a language name to see if highlighting should be skipped
-       * @param {string} languageName
-       */
-      function shouldNotHighlight(languageName) {
-        return options.noHighlightRe.test(languageName);
-      }
-
-      /**
-       * @param {HighlightedHTMLElement} block - the HTML element to determine language for
-       */
-      function blockLanguage(block) {
-        let classes = block.className + ' ';
-
-        classes += block.parentNode ? block.parentNode.className : '';
-
-        // language-* takes precedence over non-prefixed class names.
-        const match = options.languageDetectRe.exec(classes);
-        if (match) {
-          const language = getLanguage(match[1]);
-          if (!language) {
-            warn(LANGUAGE_NOT_FOUND.replace("{}", match[1]));
-            warn("Falling back to no-highlight mode for this block.", block);
-          }
-          return language ? match[1] : 'no-highlight';
+          return language ? match[1] : 'no-highlight';
         }
 
         return classes
@@ -1579,7 +1651,7 @@ var hljs = (function () {
        * NEW API
        * highlight(code, {lang, ignoreIllegals})
        *
-       * @param {string} codeOrlanguageName - the language to use for highlighting
+       * @param {string} codeOrLanguageName - the language to use for highlighting
        * @param {string | HighlightOptions} optionsOrCode - the code to highlight
        * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail
        * @param {CompiledMode} [continuation] - current continuation mode, if any
@@ -1592,11 +1664,11 @@ var hljs = (function () {
        * @property {CompiledMode} top - top of the current mode stack
        * @property {boolean} illegal - indicates whether any illegal matches were found
       */
-      function highlight(codeOrlanguageName, optionsOrCode, ignoreIllegals, continuation) {
+      function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals, continuation) {
         let code = "";
         let languageName = "";
         if (typeof optionsOrCode === "object") {
-          code = codeOrlanguageName;
+          code = codeOrLanguageName;
           ignoreIllegals = optionsOrCode.ignoreIllegals;
           languageName = optionsOrCode.language;
           // continuation not supported at all via the new API
@@ -1606,10 +1678,14 @@ var hljs = (function () {
           // old API
           deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated.");
           deprecated("10.7.0", "Please use highlight(code, options) 
instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277";);
-          languageName = codeOrlanguageName;
+          languageName = codeOrLanguageName;
           code = optionsOrCode;
         }
 
+        // https://github.com/highlightjs/highlight.js/issues/3149
+        // eslint-disable-next-line no-undefined
+        if (ignoreIllegals === undefined) { ignoreIllegals = true; }
+
         /** @type {BeforeHighlightContext} */
         const context = {
           code,
@@ -1642,15 +1718,16 @@ var hljs = (function () {
        * @returns {HighlightResult} - result of the highlight operation
       */
       function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) {
+        const keywordHits = Object.create(null);
+
         /**
          * Return keyword data if a match is a keyword
          * @param {CompiledMode} mode - current mode
-         * @param {RegExpMatchArray} match - regexp match data
+         * @param {string} matchText - the textual match
          * @returns {KeywordData | false}
          */
-        function keywordData(mode, match) {
-          const matchText = language.case_insensitive ? match[0].toLowerCase() : match[0];
-          return Object.prototype.hasOwnProperty.call(mode.keywords, matchText) && mode.keywords[matchText];
+        function keywordData(mode, matchText) {
+          return mode.keywords[matchText];
         }
 
         function processKeywords() {
@@ -1666,13 +1743,15 @@ var hljs = (function () {
 
           while (match) {
             buf += modeBuffer.substring(lastIndex, match.index);
-            const data = keywordData(top, match);
+            const word = language.case_insensitive ? match[0].toLowerCase() : match[0];
+            const data = keywordData(top, word);
             if (data) {
               const [kind, keywordRelevance] = data;
               emitter.addText(buf);
               buf = "";
 
-              relevance += keywordRelevance;
+              keywordHits[word] = (keywordHits[word] || 0) + 1;
+              if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance;
               if (kind.startsWith("_")) {
                 // _ implied for relevance only, do not highlight
                 // by applying a class name
@@ -1702,7 +1781,7 @@ var hljs = (function () {
               return;
             }
             result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]);
-            continuations[top.subLanguage] = /** @type {CompiledMode} */ (result.top);
+            continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top);
           } else {
             result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null);
           }
@@ -1714,7 +1793,7 @@ var hljs = (function () {
           if (top.relevance > 0) {
             relevance += result.relevance;
           }
-          emitter.addSublanguage(result.emitter, result.language);
+          emitter.addSublanguage(result._emitter, result.language);
         }
 
         function processBuffer() {
@@ -1727,12 +1806,47 @@ var hljs = (function () {
         }
 
         /**
-         * @param {Mode} mode - new mode to start
+         * @param {CompiledMode} mode
+         * @param {RegExpMatchArray} match
+         */
+        function emitMultiClass(scope, match) {
+          let i = 1;
+          // eslint-disable-next-line no-undefined
+          while (match[i] !== undefined) {
+            if (!scope._emit[i]) { i++; continue; }
+            const klass = language.classNameAliases[scope[i]] || scope[i];
+            const text = match[i];
+            if (klass) {
+              emitter.addKeyword(text, klass);
+            } else {
+              modeBuffer = text;
+              processKeywords();
+              modeBuffer = "";
+            }
+            i++;
+          }
+        }
+
+        /**
+         * @param {CompiledMode} mode - new mode to start
+         * @param {RegExpMatchArray} match
          */
-        function startNewMode(mode) {
-          if (mode.className) {
-            emitter.openNode(language.classNameAliases[mode.className] || mode.className);
+        function startNewMode(mode, match) {
+          if (mode.scope && typeof mode.scope === "string") {
+            emitter.openNode(language.classNameAliases[mode.scope] || mode.scope);
           }
+          if (mode.beginScope) {
+            // beginScope just wraps the begin match itself in a scope
+            if (mode.beginScope._wrap) {
+              emitter.addKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || 
mode.beginScope._wrap);
+              modeBuffer = "";
+            } else if (mode.beginScope._multi) {
+              // at this point modeBuffer should just be the match
+              emitMultiClass(mode.beginScope, match);
+              modeBuffer = "";
+            }
+          }
+
           top = Object.create(mode, { parent: { value: top } });
           return top;
         }
@@ -1774,7 +1888,7 @@ var hljs = (function () {
          */
         function doIgnore(lexeme) {
           if (top.matcher.regexIndex === 0) {
-            // no more regexs to potentially match here, so we move the cursor forward one
+            // no more regexes to potentially match here, so we move the cursor forward one
             // space
             modeBuffer += lexeme[0];
             return 1;
@@ -1805,10 +1919,6 @@ var hljs = (function () {
             if (resp.isMatchIgnored) return doIgnore(lexeme);
           }
 
-          if (newMode && newMode.endSameAsBegin) {
-            newMode.endRe = escape(lexeme);
-          }
-
           if (newMode.skip) {
             modeBuffer += lexeme;
           } else {
@@ -1820,11 +1930,7 @@ var hljs = (function () {
               modeBuffer = lexeme;
             }
           }
-          startNewMode(newMode);
-          // if (mode["after:begin"]) {
-          //   let resp = new Response(mode);
-          //   mode["after:begin"](match, resp);
-          // }
+          startNewMode(newMode, match);
           return newMode.returnBegin ? 0 : lexeme.length;
         }
 
@@ -1841,7 +1947,13 @@ var hljs = (function () {
           if (!endMode) { return NO_MATCH; }
 
           const origin = top;
-          if (origin.skip) {
+          if (top.endScope && top.endScope._wrap) {
+            processBuffer();
+            emitter.addKeyword(lexeme, top.endScope._wrap);
+          } else if (top.endScope && top.endScope._multi) {
+            processBuffer();
+            emitMultiClass(top.endScope, match);
+          } else if (origin.skip) {
             modeBuffer += lexeme;
           } else {
             if (!(origin.returnEnd || origin.excludeEnd)) {
@@ -1853,7 +1965,7 @@ var hljs = (function () {
             }
           }
           do {
-            if (top.className) {
+            if (top.scope && !top.isMultiClass) {
               emitter.closeNode();
             }
             if (!top.skip && !top.subLanguage) {
@@ -1862,10 +1974,7 @@ var hljs = (function () {
             top = top.parent;
           } while (top !== endMode.parent);
           if (endMode.starts) {
-            if (endMode.endSameAsBegin) {
-              endMode.starts.endRe = endMode.endRe;
-            }
-            startNewMode(endMode.starts);
+            startNewMode(endMode.starts, match);
           }
           return origin.returnEnd ? 0 : lexeme.length;
         }
@@ -1873,8 +1982,8 @@ var hljs = (function () {
         function processContinuations() {
           const list = [];
           for (let current = top; current !== language; current = current.parent) {
-            if (current.className) {
-              list.unshift(current.className);
+            if (current.scope) {
+              list.unshift(current.scope);
             }
           }
           list.forEach(item => emitter.openNode(item));
@@ -1886,7 +1995,7 @@ var hljs = (function () {
         /**
          *  Process an individual match
          *
-         * @param {string} textBeforeMatch - text preceeding the match (since the last match)
+         * @param {string} textBeforeMatch - text preceding the match (since the last match)
          * @param {EnhancedMatch} [match] - the match itself
          */
         function processLexeme(textBeforeMatch, match) {
@@ -1909,7 +2018,7 @@ var hljs = (function () {
             modeBuffer += codeToHighlight.slice(match.index, match.index + 1);
             if (!SAFE_MODE) {
               /** @type {AnnotatedError} */
-              const err = new Error('0 width match regex');
+              const err = new Error(`0 width match regex (${languageName})`);
               err.languageName = languageName;
               err.badRule = lastMatch.rule;
               throw err;
@@ -1923,7 +2032,7 @@ var hljs = (function () {
           } else if (match.type === "illegal" && !ignoreIllegals) {
             // illegal match, we do not continue processing
             /** @type {AnnotatedError} */
-            const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || 
'<unnamed>') + '"');
+            const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '<unnamed>') 
+ '"');
             err.mode = top;
             throw err;
           } else if (match.type === "end") {
@@ -1951,13 +2060,9 @@ var hljs = (function () {
           }
 
           /*
-          Why might be find ourselves here?  Only one occasion now.  An end match that was
-          triggered but could not be completed.  When might this happen?  When an `endSameasBegin`
-          rule sets the end rule to a specific match.  Since the overall mode termination rule that's
-          being used to scan the text isn't recompiled that means that any match that LOOKS like
-          the end (but is not, because it is not an exact match to the beginning) will
-          end up here.  A definite end match, but when `doEndMatch` tries to "reapply"
-          the end rule and fails to match, we wind up here, and just silently ignore the end.
+          Why might be find ourselves here?  An potential end match that was
+          triggered but could not be completed.  IE, `doEndMatch` returned NO_MATCH.
+          (this could be because a callback requests the match be ignored, etc)
 
           This causes no real harm other than stopping a few times too many.
           */
@@ -1972,7 +2077,7 @@ var hljs = (function () {
           throw new Error('Unknown language: "' + languageName + '"');
         }
 
-        const md = compileLanguage(language, { plugins });
+        const md = compileLanguage(language);
         let result = '';
         /** @type {CompiledMode} */
         let top = continuation || md;
@@ -2015,38 +2120,38 @@ var hljs = (function () {
           result = emitter.toHTML();
 
           return {
-            // avoid possible breakage with v10 clients expecting
-            // this to always be an integer
-            relevance: Math.floor(relevance),
-            value: result,
             language: languageName,
+            value: result,
+            relevance: relevance,
             illegal: false,
-            emitter: emitter,
-            top: top
+            _emitter: emitter,
+            _top: top
           };
         } catch (err) {
           if (err.message && err.message.includes('Illegal')) {
             return {
+              language: languageName,
+              value: escape(codeToHighlight),
               illegal: true,
-              illegalBy: {
-                msg: err.message,
+              relevance: 0,
+              _illegalBy: {
+                message: err.message,
+                index: index,
                 context: codeToHighlight.slice(index - 100, index + 100),
-                mode: err.mode
+                mode: err.mode,
+                resultSoFar: result
               },
-              sofar: result,
-              relevance: 0,
-              value: escape$1(codeToHighlight),
-              emitter: emitter
+              _emitter: emitter
             };
           } else if (SAFE_MODE) {
             return {
+              language: languageName,
+              value: escape(codeToHighlight),
               illegal: false,
               relevance: 0,
-              value: escape$1(codeToHighlight),
-              emitter: emitter,
-              language: languageName,
-              top: top,
-              errorRaised: err
+              errorRaised: err,
+              _emitter: emitter,
+              _top: top
             };
           } else {
             throw err;
@@ -2063,13 +2168,13 @@ var hljs = (function () {
        */
       function justTextHighlightResult(code) {
         const result = {
-          relevance: 0,
-          emitter: new options.__emitter(options),
-          value: escape$1(code),
+          value: escape(code),
           illegal: false,
-          top: PLAINTEXT_LANGUAGE
+          relevance: 0,
+          _top: PLAINTEXT_LANGUAGE,
+          _emitter: new options.__emitter(options)
         };
-        result.emitter.addText(code);
+        result._emitter.addText(code);
         return result;
       }
 
@@ -2080,7 +2185,7 @@ var hljs = (function () {
       - language (detected language)
       - relevance (int)
       - value (an HTML string with highlighting markup)
-      - second_best (object with the same structure for second-best heuristically
+      - secondBest (object with the same structure for second-best heuristically
         detected language, may be absent)
 
         @param {string} code
@@ -2121,35 +2226,11 @@ var hljs = (function () {
 
         /** @type {AutoHighlightResult} */
         const result = best;
-        result.second_best = secondBest;
+        result.secondBest = secondBest;
 
         return result;
       }
 
-      /**
-      Post-processing of the highlighted markup:
-
-      - replace TABs with something more useful
-      - replace real line-breaks with '<br>' for non-pre containers
-
-        @param {string} html
-        @returns {string}
-      */
-      function fixMarkup(html) {
-        if (!(options.tabReplace || options.useBR)) {
-          return html;
-        }
-
-        return html.replace(fixMarkupRe, match => {
-          if (match === '\n') {
-            return options.useBR ? '<br>' : match;
-          } else if (options.tabReplace) {
-            return match.replace(/\t/g, options.tabReplace);
-          }
-          return match;
-        });
-      }
-
       /**
        * Builds new class name for block given the language name
        *
@@ -2158,41 +2239,14 @@ var hljs = (function () {
        * @param {string} [resultLang]
        */
       function updateClassName(element, currentLang, resultLang) {
-        const language = currentLang ? aliases[currentLang] : resultLang;
+        const language = (currentLang && aliases[currentLang]) || resultLang;
 
         element.classList.add("hljs");
-        if (language) element.classList.add(language);
+        element.classList.add(`language-${language}`);
       }
 
-      /** @type {HLJSPlugin} */
-      const brPlugin = {
-        "before:highlightElement": ({ el }) => {
-          if (options.useBR) {
-            el.innerHTML = el.innerHTML.replace(/\n/g, '').replace(/<br[ /]*>/g, '\n');
-          }
-        },
-        "after:highlightElement": ({ result }) => {
-          if (options.useBR) {
-            result.value = result.value.replace(/\n/g, "<br>");
-          }
-        }
-      };
-
-      const TAB_REPLACE_RE = /^(<[^>]+>|\t)+/gm;
-      /** @type {HLJSPlugin} */
-      const tabReplacePlugin = {
-        "after:highlightElement": ({ result }) => {
-          if (options.tabReplace) {
-            result.value = result.value.replace(TAB_REPLACE_RE, (m) =>
-              m.replace(/\t/g, options.tabReplace)
-            );
-          }
-        }
-      };
-
       /**
-       * Applies highlighting to a DOM node containing code. Accepts a DOM node and
-       * two optional parameters for fixMarkup.
+       * Applies highlighting to a DOM node containing code.
        *
        * @param {HighlightedHTMLElement} element - the HTML element to highlight
       */
@@ -2203,33 +2257,36 @@ var hljs = (function () {
 
         if (shouldNotHighlight(language)) return;
 
-        // support for v10 API
         fire("before:highlightElement",
           { el: element, language: language });
 
+        // we should be all text, no child nodes
+        if (!options.ignoreUnescapedHTML && element.children.length > 0) {
+          console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious 
security risk.");
+          console.warn("https://github.com/highlightjs/highlight.js/issues/2886";);
+          console.warn(element);
+        }
+
         node = element;
         const text = node.textContent;
         const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text);
 
-        // support for v10 API
-        fire("after:highlightElement", { el: element, result, text });
-
         element.innerHTML = result.value;
         updateClassName(element, language, result.language);
         element.result = {
           language: result.language,
           // TODO: remove with version 11.0
           re: result.relevance,
-          relavance: result.relevance
+          relevance: result.relevance
         };
-        if (result.second_best) {
-          element.second_best = {
-            language: result.second_best.language,
-            // TODO: remove with version 11.0
-            re: result.second_best.relevance,
-            relavance: result.second_best.relevance
+        if (result.secondBest) {
+          element.secondBest = {
+            language: result.secondBest.language,
+            relevance: result.secondBest.relevance
           };
         }
+
+        fire("after:highlightElement", { el: element, result, text });
       }
 
       /**
@@ -2238,34 +2295,19 @@ var hljs = (function () {
        * @param {Partial<HLJSOptions>} userOptions
        */
       function configure(userOptions) {
-        if (userOptions.useBR) {
-          deprecated("10.3.0", "'useBR' will be removed entirely in v11.0");
-          deprecated("10.3.0", "Please see https://github.com/highlightjs/highlight.js/issues/2559";);
-        }
-        options = inherit$1(options, userOptions);
+        options = inherit(options, userOptions);
       }
 
-      /**
-       * Highlights to all <pre><code> blocks on a page
-       *
-       * @type {Function & {called?: boolean}}
-       */
       // TODO: remove v12, deprecated
       const initHighlighting = () => {
-        if (initHighlighting.called) return;
-        initHighlighting.called = true;
-
-        deprecated("10.6.0", "initHighlighting() is deprecated.  Use highlightAll() instead.");
-
-        const blocks = document.querySelectorAll('pre code');
-        blocks.forEach(highlightElement);
+        highlightAll();
+        deprecated("10.6.0", "initHighlighting() deprecated.  Use highlightAll() now.");
       };
 
-      // Higlights all when DOMContentLoaded fires
       // TODO: remove v12, deprecated
       function initHighlightingOnLoad() {
-        deprecated("10.6.0", "initHighlightingOnLoad() is deprecated.  Use highlightAll() instead.");
-        wantsHighlight = true;
+        highlightAll();
+        deprecated("10.6.0", "initHighlightingOnLoad() deprecated.  Use highlightAll() now.");
       }
 
       let wantsHighlight = false;
@@ -2280,7 +2322,7 @@ var hljs = (function () {
           return;
         }
 
-        const blocks = document.querySelectorAll('pre code');
+        const blocks = document.querySelectorAll(options.cssSelector);
         blocks.forEach(highlightElement);
       }
 
@@ -2345,26 +2387,6 @@ var hljs = (function () {
         return Object.keys(languages);
       }
 
-      /**
-        intended usage: When one language truly requires another
-
-        Unlike `getLanguage`, this will throw when the requested language
-        is not available.
-
-        @param {string} name - name of the language to fetch/require
-        @returns {Language | never}
-      */
-      function requireLanguage(name) {
-        deprecated("10.4.0", "requireLanguage will be removed entirely in v11.");
-        deprecated("10.4.0", "Please see https://github.com/highlightjs/highlight.js/pull/2844";);
-
-        const lang = getLanguage(name);
-        if (lang) { return lang; }
-
-        const err = new Error('The \'{}\' language is required, but not loaded.'.replace('{}', name));
-        throw err;
-      }
-
       /**
        * @param {string} name - name of the language to retrieve
        * @returns {Language | undefined}
@@ -2440,19 +2462,6 @@ var hljs = (function () {
         });
       }
 
-      /**
-      Note: fixMarkup is deprecated and will be removed entirely in v11
-
-      @param {string} arg
-      @returns {string}
-      */
-      function deprecateFixMarkup(arg) {
-        deprecated("10.2.0", "fixMarkup will be removed entirely in v11.0");
-        deprecated("10.2.0", "Please see https://github.com/highlightjs/highlight.js/issues/2534";);
-
-        return fixMarkup(arg);
-      }
-
       /**
        *
        * @param {HighlightedHTMLElement} el
@@ -2469,7 +2478,6 @@ var hljs = (function () {
         highlight,
         highlightAuto,
         highlightAll,
-        fixMarkup: deprecateFixMarkup,
         highlightElement,
         // TODO: Remove with v12 API
         highlightBlock: deprecateHighlightBlock,
@@ -2481,1563 +2489,1531 @@ var hljs = (function () {
         listLanguages,
         getLanguage,
         registerAliases,
-        requireLanguage,
         autoDetection,
-        inherit: inherit$1,
-        addPlugin,
-        // plugins for frameworks
-        vuePlugin: BuildVuePlugin(hljs).VuePlugin
+        inherit,
+        addPlugin
       });
 
       hljs.debugMode = function() { SAFE_MODE = false; };
       hljs.safeMode = function() { SAFE_MODE = true; };
       hljs.versionString = version;
 
-      for (const key in MODES) {
+      for (const key in MODES$1) {
         // @ts-ignore
-        if (typeof MODES[key] === "object") {
+        if (typeof MODES$1[key] === "object") {
           // @ts-ignore
-          deepFreezeEs6(MODES[key]);
+          deepFreeze$1(MODES$1[key]);
         }
       }
 
-      // merge all the modes/regexs into our main object
-      Object.assign(hljs, MODES);
+      // merge all the modes/regexes into our main object
+      Object.assign(hljs, MODES$1);
 
-      // built-in plugins, likely to be moved out of core in the future
-      hljs.addPlugin(brPlugin); // slated to be removed in v11
-      hljs.addPlugin(mergeHTMLPlugin);
-      hljs.addPlugin(tabReplacePlugin);
       return hljs;
     };
 
     // export an "instance" of the highlighter
-    var highlight = HLJS({});
-
-    return highlight;
-
-}());
-if (typeof exports === 'object' && typeof module !== 'undefined') { module.exports = hljs; }
-
-hljs.registerLanguage('css', function () {
-  'use strict';
-
-  const MODES = (hljs) => {
-    return {
-      IMPORTANT: {
-        className: 'meta',
-        begin: '!important'
-      },
-      HEXCOLOR: {
-        className: 'number',
-        begin: '#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})'
-      },
-      ATTRIBUTE_SELECTOR_MODE: {
-        className: 'selector-attr',
-        begin: /\[/,
-        end: /\]/,
-        illegal: '$',
-        contains: [
-          hljs.APOS_STRING_MODE,
-          hljs.QUOTE_STRING_MODE
-        ]
-      }
-    };
-  };
-
-  const TAGS = [
-    'a',
-    'abbr',
-    'address',
-    'article',
-    'aside',
-    'audio',
-    'b',
-    'blockquote',
-    'body',
-    'button',
-    'canvas',
-    'caption',
-    'cite',
-    'code',
-    'dd',
-    'del',
-    'details',
-    'dfn',
-    'div',
-    'dl',
-    'dt',
-    'em',
-    'fieldset',
-    'figcaption',
-    'figure',
-    'footer',
-    'form',
-    'h1',
-    'h2',
-    'h3',
-    'h4',
-    'h5',
-    'h6',
-    'header',
-    'hgroup',
-    'html',
-    'i',
-    'iframe',
-    'img',
-    'input',
-    'ins',
-    'kbd',
-    'label',
-    'legend',
-    'li',
-    'main',
-    'mark',
-    'menu',
-    'nav',
-    'object',
-    'ol',
-    'p',
-    'q',
-    'quote',
-    'samp',
-    'section',
-    'span',
-    'strong',
-    'summary',
-    'sup',
-    'table',
-    'tbody',
-    'td',
-    'textarea',
-    'tfoot',
-    'th',
-    'thead',
-    'time',
-    'tr',
-    'ul',
-    'var',
-    'video'
-  ];
-
-  const MEDIA_FEATURES = [
-    'any-hover',
-    'any-pointer',
-    'aspect-ratio',
-    'color',
-    'color-gamut',
-    'color-index',
-    'device-aspect-ratio',
-    'device-height',
-    'device-width',
-    'display-mode',
-    'forced-colors',
-    'grid',
-    'height',
-    'hover',
-    'inverted-colors',
-    'monochrome',
-    'orientation',
-    'overflow-block',
-    'overflow-inline',
-    'pointer',
-    'prefers-color-scheme',
-    'prefers-contrast',
-    'prefers-reduced-motion',
-    'prefers-reduced-transparency',
-    'resolution',
-    'scan',
-    'scripting',
-    'update',
-    'width',
-    // TODO: find a better solution?
-    'min-width',
-    'max-width',
-    'min-height',
-    'max-height'
-  ];
-
-  // https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
-  const PSEUDO_CLASSES = [
-    'active',
-    'any-link',
-    'blank',
-    'checked',
-    'current',
-    'default',
-    'defined',
-    'dir', // dir()
-    'disabled',
-    'drop',
-    'empty',
-    'enabled',
-    'first',
-    'first-child',
-    'first-of-type',
-    'fullscreen',
-    'future',
-    'focus',
-    'focus-visible',
-    'focus-within',
-    'has', // has()
-    'host', // host or host()
-    'host-context', // host-context()
-    'hover',
-    'indeterminate',
-    'in-range',
-    'invalid',
-    'is', // is()
-    'lang', // lang()
-    'last-child',
-    'last-of-type',
-    'left',
-    'link',
-    'local-link',
-    'not', // not()
-    'nth-child', // nth-child()
-    'nth-col', // nth-col()
-    'nth-last-child', // nth-last-child()
-    'nth-last-col', // nth-last-col()
-    'nth-last-of-type', //nth-last-of-type()
-    'nth-of-type', //nth-of-type()
-    'only-child',
-    'only-of-type',
-    'optional',
-    'out-of-range',
-    'past',
-    'placeholder-shown',
-    'read-only',
-    'read-write',
-    'required',
-    'right',
-    'root',
-    'scope',
-    'target',
-    'target-within',
-    'user-invalid',
-    'valid',
-    'visited',
-    'where' // where()
-  ];
-
-  // https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
-  const PSEUDO_ELEMENTS = [
-    'after',
-    'backdrop',
-    'before',
-    'cue',
-    'cue-region',
-    'first-letter',
-    'first-line',
-    'grammar-error',
-    'marker',
-    'part',
-    'placeholder',
-    'selection',
-    'slotted',
-    'spelling-error'
-  ];
-
-  const ATTRIBUTES = [
-    'align-content',
-    'align-items',
-    'align-self',
-    'animation',
-    'animation-delay',
-    'animation-direction',
-    'animation-duration',
-    'animation-fill-mode',
-    'animation-iteration-count',
-    'animation-name',
-    'animation-play-state',
-    'animation-timing-function',
-    'auto',
-    'backface-visibility',
-    'background',
-    'background-attachment',
-    'background-clip',
-    'background-color',
-    'background-image',
-    'background-origin',
-    'background-position',
-    'background-repeat',
-    'background-size',
-    'border',
-    'border-bottom',
-    'border-bottom-color',
-    'border-bottom-left-radius',
-    'border-bottom-right-radius',
-    'border-bottom-style',
-    'border-bottom-width',
-    'border-collapse',
-    'border-color',
-    'border-image',
-    'border-image-outset',
-    'border-image-repeat',
-    'border-image-slice',
-    'border-image-source',
-    'border-image-width',
-    'border-left',
-    'border-left-color',
-    'border-left-style',
-    'border-left-width',
-    'border-radius',
-    'border-right',
-    'border-right-color',
-    'border-right-style',
-    'border-right-width',
-    'border-spacing',
-    'border-style',
-    'border-top',
-    'border-top-color',
-    'border-top-left-radius',
-    'border-top-right-radius',
-    'border-top-style',
-    'border-top-width',
-    'border-width',
-    'bottom',
-    'box-decoration-break',
-    'box-shadow',
-    'box-sizing',
-    'break-after',
-    'break-before',
-    'break-inside',
-    'caption-side',
-    'clear',
-    'clip',
-    'clip-path',
-    'color',
-    'column-count',
-    'column-fill',
-    'column-gap',
-    'column-rule',
-    'column-rule-color',
-    'column-rule-style',
-    'column-rule-width',
-    'column-span',
-    'column-width',
-    'columns',
-    'content',
-    'counter-increment',
-    'counter-reset',
-    'cursor',
-    'direction',
-    'display',
-    'empty-cells',
-    'filter',
-    'flex',
-    'flex-basis',
-    'flex-direction',
-    'flex-flow',
-    'flex-grow',
-    'flex-shrink',
-    'flex-wrap',
-    'float',
-    'font',
-    'font-display',
-    'font-family',
-    'font-feature-settings',
-    'font-kerning',
-    'font-language-override',
-    'font-size',
-    'font-size-adjust',
-    'font-smoothing',
-    'font-stretch',
-    'font-style',
-    'font-variant',
-    'font-variant-ligatures',
-    'font-variation-settings',
-    'font-weight',
-    'height',
-    'hyphens',
-    'icon',
-    'image-orientation',
-    'image-rendering',
-    'image-resolution',
-    'ime-mode',
-    'inherit',
-    'initial',
-    'justify-content',
-    'left',
-    'letter-spacing',
-    'line-height',
-    'list-style',
-    'list-style-image',
-    'list-style-position',
-    'list-style-type',
-    'margin',
-    'margin-bottom',
-    'margin-left',
-    'margin-right',
-    'margin-top',
-    'marks',
-    'mask',
-    'max-height',
-    'max-width',
-    'min-height',
-    'min-width',
-    'nav-down',
-    'nav-index',
-    'nav-left',
-    'nav-right',
-    'nav-up',
-    'none',
-    'normal',
-    'object-fit',
-    'object-position',
-    'opacity',
-    'order',
-    'orphans',
-    'outline',
-    'outline-color',
-    'outline-offset',
-    'outline-style',
-    'outline-width',
-    'overflow',
-    'overflow-wrap',
-    'overflow-x',
-    'overflow-y',
-    'padding',
-    'padding-bottom',
-    'padding-left',
-    'padding-right',
-    'padding-top',
-    'page-break-after',
-    'page-break-before',
-    'page-break-inside',
-    'perspective',
-    'perspective-origin',
-    'pointer-events',
-    'position',
-    'quotes',
-    'resize',
-    'right',
-    'src', // @font-face
-    'tab-size',
-    'table-layout',
-    'text-align',
-    'text-align-last',
-    'text-decoration',
-    'text-decoration-color',
-    'text-decoration-line',
-    'text-decoration-style',
-    'text-indent',
-    'text-overflow',
-    'text-rendering',
-    'text-shadow',
-    'text-transform',
-    'text-underline-position',
-    'top',
-    'transform',
-    'transform-origin',
-    'transform-style',
-    'transition',
-    'transition-delay',
-    'transition-duration',
-    'transition-property',
-    'transition-timing-function',
-    'unicode-bidi',
-    'vertical-align',
-    'visibility',
-    'white-space',
-    'widows',
-    'width',
-    'word-break',
-    'word-spacing',
-    'word-wrap',
-    'z-index'
-    // reverse makes sure longer attributes `font-weight` are matched fully
-    // instead of getting false positives on say `font`
-  ].reverse();
-
-  /**
-   * @param {string} value
-   * @returns {RegExp}
-   * */
-
-  /**
-   * @param {RegExp | string } re
-   * @returns {string}
-   */
-  function source(re) {
-    if (!re) return null;
-    if (typeof re === "string") return re;
-
-    return re.source;
-  }
-
-  /**
-   * @param {RegExp | string } re
-   * @returns {string}
-   */
-  function lookahead(re) {
-    return concat('(?=', re, ')');
-  }
-
-  /**
-   * @param {...(RegExp | string) } args
-   * @returns {string}
-   */
-  function concat(...args) {
-    const joined = args.map((x) => source(x)).join("");
-    return joined;
-  }
-
-  /*
-  Language: CSS
-  Category: common, css
-  Website: https://developer.mozilla.org/en-US/docs/Web/CSS
-  */
-
-  /** @type LanguageFn */
-  function css(hljs) {
-    const modes = MODES(hljs);
-    const FUNCTION_DISPATCH = {
-      className: "built_in",
-      begin: /[\w-]+(?=\()/
-    };
-    const VENDOR_PREFIX = {
-      begin: /-(webkit|moz|ms|o)-(?=[a-z])/
-    };
-    const AT_MODIFIERS = "and or not only";
-    const AT_PROPERTY_RE = /@-?\w[\w]*(-\w+)*/; // @-webkit-keyframes
-    const IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*';
-    const STRINGS = [
-      hljs.APOS_STRING_MODE,
-      hljs.QUOTE_STRING_MODE
-    ];
+    var HighlightJS = HLJS({});
 
-    return {
-      name: 'CSS',
-      case_insensitive: true,
-      illegal: /[=|'\$]/,
-      keywords: {
-        keyframePosition: "from to"
-      },
-      classNameAliases: {
-        // for visual continuity with `tag {}` and because we
-        // don't have a great class for this?
-        keyframePosition: "selector-tag"
-      },
-      contains: [
-        hljs.C_BLOCK_COMMENT_MODE,
-        VENDOR_PREFIX,
-        // to recognize keyframe 40% etc which are outside the scope of our
-        // attribute value mode
-        hljs.CSS_NUMBER_MODE,
-        {
-          className: 'selector-id',
-          begin: /#[A-Za-z0-9_-]+/,
-          relevance: 0
-        },
-        {
-          className: 'selector-class',
-          begin: '\\.' + IDENT_RE,
-          relevance: 0
-        },
-        modes.ATTRIBUTE_SELECTOR_MODE,
-        {
-          className: 'selector-pseudo',
-          variants: [
-            {
-              begin: ':(' + PSEUDO_CLASSES.join('|') + ')'
-            },
-            {
-              begin: '::(' + PSEUDO_ELEMENTS.join('|') + ')'
-            }
-          ]
-        },
-        // we may actually need this (12/2020)
-        // { // pseudo-selector params
-        //   begin: /\(/,
-        //   end: /\)/,
-        //   contains: [ hljs.CSS_NUMBER_MODE ]
-        // },
-        {
-          className: 'attribute',
-          begin: '\\b(' + ATTRIBUTES.join('|') + ')\\b'
+    const MODES = (hljs) => {
+      return {
+        IMPORTANT: {
+          scope: 'meta',
+          begin: '!important'
         },
-        // attribute values
-        {
-          begin: ':',
-          end: '[;}]',
-          contains: [
-            modes.HEXCOLOR,
-            modes.IMPORTANT,
-            hljs.CSS_NUMBER_MODE,
-            ...STRINGS,
-            // needed to highlight these as strings and to avoid issues with
-            // illegal characters that might be inside urls that would tigger the
-            // languages illegal stack
-            {
-              begin: /(url|data-uri)\(/,
-              end: /\)/,
-              relevance: 0, // from keywords
-              keywords: {
-                built_in: "url data-uri"
-              },
-              contains: [
-                {
-                  className: "string",
-                  // any character other than `)` as in `url()` will be the start
-                  // of a string, which ends with `)` (from the parent mode)
-                  begin: /[^)]/,
-                  endsWithParent: true,
-                  excludeEnd: true
-                }
-              ]
-            },
-            FUNCTION_DISPATCH
-          ]
+        HEXCOLOR: {
+          scope: 'number',
+          begin: '#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})'
         },
-        {
-          begin: lookahead(/@/),
-          end: '[{;]',
-          relevance: 0,
-          illegal: /:/, // break on Less variables @var: ...
+        ATTRIBUTE_SELECTOR_MODE: {
+          scope: 'selector-attr',
+          begin: /\[/,
+          end: /\]/,
+          illegal: '$',
           contains: [
-            {
-              className: 'keyword',
-              begin: AT_PROPERTY_RE
-            },
-            {
-              begin: /\s/,
-              endsWithParent: true,
-              excludeEnd: true,
-              relevance: 0,
-              keywords: {
-                $pattern: /[a-z-]+/,
-                keyword: AT_MODIFIERS,
-                attribute: MEDIA_FEATURES.join(" ")
-              },
-              contains: [
-                {
-                  begin: /[a-z-]+(?=:)/,
-                  className: "attribute"
-                },
-                ...STRINGS,
-                hljs.CSS_NUMBER_MODE
-              ]
-            }
+            hljs.APOS_STRING_MODE,
+            hljs.QUOTE_STRING_MODE
           ]
         },
-        {
-          className: 'selector-tag',
-          begin: '\\b(' + TAGS.join('|') + ')\\b'
+        CSS_NUMBER_MODE: {
+          scope: 'number',
+          begin: hljs.NUMBER_RE + '(' +
+            '%|em|ex|ch|rem' +
+            '|vw|vh|vmin|vmax' +
+            '|cm|mm|in|pt|pc|px' +
+            '|deg|grad|rad|turn' +
+            '|s|ms' +
+            '|Hz|kHz' +
+            '|dpi|dpcm|dppx' +
+            ')?',
+          relevance: 0
         }
-      ]
+      };
     };
-  }
 
-  return css;
+    const TAGS = [
+      'a',
+      'abbr',
+      'address',
+      'article',
+      'aside',
+      'audio',
+      'b',
+      'blockquote',
+      'body',
+      'button',
+      'canvas',
+      'caption',
+      'cite',
+      'code',
+      'dd',
+      'del',
+      'details',
+      'dfn',
+      'div',
+      'dl',
+      'dt',
+      'em',
+      'fieldset',
+      'figcaption',
+      'figure',
+      'footer',
+      'form',
+      'h1',
+      'h2',
+      'h3',
+      'h4',
+      'h5',
+      'h6',
+      'header',
+      'hgroup',
+      'html',
+      'i',
+      'iframe',
+      'img',
+      'input',
+      'ins',
+      'kbd',
+      'label',
+      'legend',
+      'li',
+      'main',
+      'mark',
+      'menu',
+      'nav',
+      'object',
+      'ol',
+      'p',
+      'q',
+      'quote',
+      'samp',
+      'section',
+      'span',
+      'strong',
+      'summary',
+      'sup',
+      'table',
+      'tbody',
+      'td',
+      'textarea',
+      'tfoot',
+      'th',
+      'thead',
+      'time',
+      'tr',
+      'ul',
+      'var',
+      'video'
+    ];
 
-  return module.exports.definer || module.exports;
+    const MEDIA_FEATURES = [
+      'any-hover',
+      'any-pointer',
+      'aspect-ratio',
+      'color',
+      'color-gamut',
+      'color-index',
+      'device-aspect-ratio',
+      'device-height',
+      'device-width',
+      'display-mode',
+      'forced-colors',
+      'grid',
+      'height',
+      'hover',
+      'inverted-colors',
+      'monochrome',
+      'orientation',
+      'overflow-block',
+      'overflow-inline',
+      'pointer',
+      'prefers-color-scheme',
+      'prefers-contrast',
+      'prefers-reduced-motion',
+      'prefers-reduced-transparency',
+      'resolution',
+      'scan',
+      'scripting',
+      'update',
+      'width',
+      // TODO: find a better solution?
+      'min-width',
+      'max-width',
+      'min-height',
+      'max-height'
+    ];
 
-}());
+    // https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
+    const PSEUDO_CLASSES = [
+      'active',
+      'any-link',
+      'blank',
+      'checked',
+      'current',
+      'default',
+      'defined',
+      'dir', // dir()
+      'disabled',
+      'drop',
+      'empty',
+      'enabled',
+      'first',
+      'first-child',
+      'first-of-type',
+      'fullscreen',
+      'future',
+      'focus',
+      'focus-visible',
+      'focus-within',
+      'has', // has()
+      'host', // host or host()
+      'host-context', // host-context()
+      'hover',
+      'indeterminate',
+      'in-range',
+      'invalid',
+      'is', // is()
+      'lang', // lang()
+      'last-child',
+      'last-of-type',
+      'left',
+      'link',
+      'local-link',
+      'not', // not()
+      'nth-child', // nth-child()
+      'nth-col', // nth-col()
+      'nth-last-child', // nth-last-child()
+      'nth-last-col', // nth-last-col()
+      'nth-last-of-type', //nth-last-of-type()
+      'nth-of-type', //nth-of-type()
+      'only-child',
+      'only-of-type',
+      'optional',
+      'out-of-range',
+      'past',
+      'placeholder-shown',
+      'read-only',
+      'read-write',
+      'required',
+      'right',
+      'root',
+      'scope',
+      'target',
+      'target-within',
+      'user-invalid',
+      'valid',
+      'visited',
+      'where' // where()
+    ];
 
-hljs.registerLanguage('javascript', function () {
-  'use strict';
-
-  const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*';
-  const KEYWORDS = [
-    "as", // for exports
-    "in",
-    "of",
-    "if",
-    "for",
-    "while",
-    "finally",
-    "var",
-    "new",
-    "function",
-    "do",
-    "return",
-    "void",
-    "else",
-    "break",
-    "catch",
-    "instanceof",
-    "with",
-    "throw",
-    "case",
-    "default",
-    "try",
-    "switch",
-    "continue",
-    "typeof",
-    "delete",
-    "let",
-    "yield",
-    "const",
-    "class",
-    // JS handles these with a special rule
-    // "get",
-    // "set",
-    "debugger",
-    "async",
-    "await",
-    "static",
-    "import",
-    "from",
-    "export",
-    "extends"
-  ];
-  const LITERALS = [
-    "true",
-    "false",
-    "null",
-    "undefined",
-    "NaN",
-    "Infinity"
-  ];
-
-  const TYPES = [
-    "Intl",
-    "DataView",
-    "Number",
-    "Math",
-    "Date",
-    "String",
-    "RegExp",
-    "Object",
-    "Function",
-    "Boolean",
-    "Error",
-    "Symbol",
-    "Set",
-    "Map",
-    "WeakSet",
-    "WeakMap",
-    "Proxy",
-    "Reflect",
-    "JSON",
-    "Promise",
-    "Float64Array",
-    "Int16Array",
-    "Int32Array",
-    "Int8Array",
-    "Uint16Array",
-    "Uint32Array",
-    "Float32Array",
-    "Array",
-    "Uint8Array",
-    "Uint8ClampedArray",
-    "ArrayBuffer",
-    "BigInt64Array",
-    "BigUint64Array",
-    "BigInt"
-  ];
-
-  const ERROR_TYPES = [
-    "EvalError",
-    "InternalError",
-    "RangeError",
-    "ReferenceError",
-    "SyntaxError",
-    "TypeError",
-    "URIError"
-  ];
-
-  const BUILT_IN_GLOBALS = [
-    "setInterval",
-    "setTimeout",
-    "clearInterval",
-    "clearTimeout",
-
-    "require",
-    "exports",
-
-    "eval",
-    "isFinite",
-    "isNaN",
-    "parseFloat",
-    "parseInt",
-    "decodeURI",
-    "decodeURIComponent",
-    "encodeURI",
-    "encodeURIComponent",
-    "escape",
-    "unescape"
-  ];
-
-  const BUILT_IN_VARIABLES = [
-    "arguments",
-    "this",
-    "super",
-    "console",
-    "window",
-    "document",
-    "localStorage",
-    "module",
-    "global" // Node.js
-  ];
-
-  const BUILT_INS = [].concat(
-    BUILT_IN_GLOBALS,
-    BUILT_IN_VARIABLES,
-    TYPES,
-    ERROR_TYPES
-  );
-
-  /**
-   * @param {string} value
-   * @returns {RegExp}
-   * */
-
-  /**
-   * @param {RegExp | string } re
-   * @returns {string}
-   */
-  function source(re) {
-    if (!re) return null;
-    if (typeof re === "string") return re;
-
-    return re.source;
-  }
-
-  /**
-   * @param {RegExp | string } re
-   * @returns {string}
-   */
-  function lookahead(re) {
-    return concat('(?=', re, ')');
-  }
-
-  /**
-   * @param {...(RegExp | string) } args
-   * @returns {string}
-   */
-  function concat(...args) {
-    const joined = args.map((x) => source(x)).join("");
-    return joined;
-  }
-
-  /*
-  Language: JavaScript
-  Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language 
with first-class functions.
-  Category: common, scripting
-  Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript
-  */
-
-  /** @type LanguageFn */
-  function javascript(hljs) {
-    /**
-     * Takes a string like "<Booger" and checks to see
-     * if we can find a matching "</Booger" later in the
-     * content.
-     * @param {RegExpMatchArray} match
-     * @param {{after:number}} param1
-     */
-    const hasClosingTag = (match, { after }) => {
-      const tag = "</" + match[0].slice(1);
-      const pos = match.input.indexOf(tag, after);
-      return pos !== -1;
-    };
+    // https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
+    const PSEUDO_ELEMENTS = [
+      'after',
+      'backdrop',
+      'before',
+      'cue',
+      'cue-region',
+      'first-letter',
+      'first-line',
+      'grammar-error',
+      'marker',
+      'part',
+      'placeholder',
+      'selection',
+      'slotted',
+      'spelling-error'
+    ];
 
-    const IDENT_RE$1 = IDENT_RE;
-    const FRAGMENT = {
-      begin: '<>',
-      end: '</>'
-    };
-    const XML_TAG = {
-      begin: /<[A-Za-z0-9\\._:-]+/,
-      end: /\/[A-Za-z0-9\\._:-]+>|\/>/,
-      /**
-       * @param {RegExpMatchArray} match
-       * @param {CallbackResponse} response
-       */
-      isTrulyOpeningTag: (match, response) => {
-        const afterMatchIndex = match[0].length + match.index;
-        const nextChar = match.input[afterMatchIndex];
-        // nested type?
-        // HTML should not include another raw `<` inside a tag
-        // But a type might: `<Array<Array<number>>`, etc.
-        if (nextChar === "<") {
-          response.ignoreMatch();
-          return;
-        }
-        // <something>
-        // This is now either a tag or a type.
-        if (nextChar === ">") {
-          // if we cannot find a matching closing tag, then we
-          // will ignore it
-          if (!hasClosingTag(match, { after: afterMatchIndex })) {
-            response.ignoreMatch();
-          }
-        }
-      }
-    };
-    const KEYWORDS$1 = {
-      $pattern: IDENT_RE,
-      keyword: KEYWORDS,
-      literal: LITERALS,
-      built_in: BUILT_INS
-    };
+    const ATTRIBUTES = [
+      'align-content',
+      'align-items',
+      'align-self',
+      'animation',
+      'animation-delay',
+      'animation-direction',
+      'animation-duration',
+      'animation-fill-mode',
+      'animation-iteration-count',
+      'animation-name',
+      'animation-play-state',
+      'animation-timing-function',
+      'auto',
+      'backface-visibility',
+      'background',
+      'background-attachment',
+      'background-clip',
+      'background-color',
+      'background-image',
+      'background-origin',
+      'background-position',
+      'background-repeat',
+      'background-size',
+      'border',
+      'border-bottom',
+      'border-bottom-color',
+      'border-bottom-left-radius',
+      'border-bottom-right-radius',
+      'border-bottom-style',
+      'border-bottom-width',
+      'border-collapse',
+      'border-color',
+      'border-image',
+      'border-image-outset',
+      'border-image-repeat',
+      'border-image-slice',
+      'border-image-source',
+      'border-image-width',
+      'border-left',
+      'border-left-color',
+      'border-left-style',
+      'border-left-width',
+      'border-radius',
+      'border-right',
+      'border-right-color',
+      'border-right-style',
+      'border-right-width',
+      'border-spacing',
+      'border-style',
+      'border-top',
+      'border-top-color',
+      'border-top-left-radius',
+      'border-top-right-radius',
+      'border-top-style',
+      'border-top-width',
+      'border-width',
+      'bottom',
+      'box-decoration-break',
+      'box-shadow',
+      'box-sizing',
+      'break-after',
+      'break-before',
+      'break-inside',
+      'caption-side',
+      'clear',
+      'clip',
+      'clip-path',
+      'color',
+      'column-count',
+      'column-fill',
+      'column-gap',
+      'column-rule',
+      'column-rule-color',
+      'column-rule-style',
+      'column-rule-width',
+      'column-span',
+      'column-width',
+      'columns',
+      'content',
+      'counter-increment',
+      'counter-reset',
+      'cursor',
+      'direction',
+      'display',
+      'empty-cells',
+      'filter',
+      'flex',
+      'flex-basis',
+      'flex-direction',
+      'flex-flow',
+      'flex-grow',
+      'flex-shrink',
+      'flex-wrap',
+      'float',
+      'font',
+      'font-display',
+      'font-family',
+      'font-feature-settings',
+      'font-kerning',
+      'font-language-override',
+      'font-size',
+      'font-size-adjust',
+      'font-smoothing',
+      'font-stretch',
+      'font-style',
+      'font-variant',
+      'font-variant-ligatures',
+      'font-variation-settings',
+      'font-weight',
+      'height',
+      'hyphens',
+      'icon',
+      'image-orientation',
+      'image-rendering',
+      'image-resolution',
+      'ime-mode',
+      'inherit',
+      'initial',
+      'justify-content',
+      'left',
+      'letter-spacing',
+      'line-height',
+      'list-style',
+      'list-style-image',
+      'list-style-position',
+      'list-style-type',
+      'margin',
+      'margin-bottom',
+      'margin-left',
+      'margin-right',
+      'margin-top',
+      'marks',
+      'mask',
+      'max-height',
+      'max-width',
+      'min-height',
+      'min-width',
+      'nav-down',
+      'nav-index',
+      'nav-left',
+      'nav-right',
+      'nav-up',
+      'none',
+      'normal',
+      'object-fit',
+      'object-position',
+      'opacity',
+      'order',
+      'orphans',
+      'outline',
+      'outline-color',
+      'outline-offset',
+      'outline-style',
+      'outline-width',
+      'overflow',
+      'overflow-wrap',
+      'overflow-x',
+      'overflow-y',
+      'padding',
+      'padding-bottom',
+      'padding-left',
+      'padding-right',
+      'padding-top',
+      'page-break-after',
+      'page-break-before',
+      'page-break-inside',
+      'perspective',
+      'perspective-origin',
+      'pointer-events',
+      'position',
+      'quotes',
+      'resize',
+      'right',
+      'src', // @font-face
+      'tab-size',
+      'table-layout',
+      'text-align',
+      'text-align-last',
+      'text-decoration',
+      'text-decoration-color',
+      'text-decoration-line',
+      'text-decoration-style',
+      'text-indent',
+      'text-overflow',
+      'text-rendering',
+      'text-shadow',
+      'text-transform',
+      'text-underline-position',
+      'top',
+      'transform',
+      'transform-origin',
+      'transform-style',
+      'transition',
+      'transition-delay',
+      'transition-duration',
+      'transition-property',
+      'transition-timing-function',
+      'unicode-bidi',
+      'vertical-align',
+      'visibility',
+      'white-space',
+      'widows',
+      'width',
+      'word-break',
+      'word-spacing',
+      'word-wrap',
+      'z-index'
+      // reverse makes sure longer attributes `font-weight` are matched fully
+      // instead of getting false positives on say `font`
+    ].reverse();
 
-    // https://tc39.es/ecma262/#sec-literals-numeric-literals
-    const decimalDigits = '[0-9](_?[0-9])*';
-    const frac = `\\.(${decimalDigits})`;
-    // DecimalIntegerLiteral, including Annex B NonOctalDecimalIntegerLiteral
-    // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
-    const decimalInteger = `0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*`;
-    const NUMBER = {
-      className: 'number',
-      variants: [
-        // DecimalLiteral
-        { begin: `(\\b(${decimalInteger})((${frac})|\\.)?|(${frac}))` +
-          `[eE][+-]?(${decimalDigits})\\b` },
-        { begin: `\\b(${decimalInteger})\\b((${frac})\\b|\\.)?|(${frac})\\b` },
-
-        // DecimalBigIntegerLiteral
-        { begin: `\\b(0|[1-9](_?[0-9])*)n\\b` },
-
-        // NonDecimalIntegerLiteral
-        { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b" },
-        { begin: "\\b0[bB][0-1](_?[0-1])*n?\\b" },
-        { begin: "\\b0[oO][0-7](_?[0-7])*n?\\b" },
-
-        // LegacyOctalIntegerLiteral (does not include underscore separators)
-        // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
-        { begin: "\\b0[0-7]+n?\\b" },
-      ],
-      relevance: 0
-    };
+    /*
+    Language: CSS
+    Category: common, css, web
+    Website: https://developer.mozilla.org/en-US/docs/Web/CSS
+    */
 
-    const SUBST = {
-      className: 'subst',
-      begin: '\\$\\{',
-      end: '\\}',
-      keywords: KEYWORDS$1,
-      contains: [] // defined later
-    };
-    const HTML_TEMPLATE = {
-      begin: 'html`',
-      end: '',
-      starts: {
-        end: '`',
-        returnEnd: false,
-        contains: [
-          hljs.BACKSLASH_ESCAPE,
-          SUBST
-        ],
-        subLanguage: 'xml'
-      }
-    };
-    const CSS_TEMPLATE = {
-      begin: 'css`',
-      end: '',
-      starts: {
-        end: '`',
-        returnEnd: false,
-        contains: [
-          hljs.BACKSLASH_ESCAPE,
-          SUBST
-        ],
-        subLanguage: 'css'
-      }
-    };
-    const TEMPLATE_STRING = {
-      className: 'string',
-      begin: '`',
-      end: '`',
-      contains: [
-        hljs.BACKSLASH_ESCAPE,
-        SUBST
-      ]
-    };
-    const JSDOC_COMMENT = hljs.COMMENT(
-      /\/\*\*(?!\/)/,
-      '\\*/',
-      {
-        relevance: 0,
+    /** @type LanguageFn */
+    function css(hljs) {
+      const modes = MODES(hljs);
+      const FUNCTION_DISPATCH = {
+        className: "built_in",
+        begin: /[\w-]+(?=\()/
+      };
+      const VENDOR_PREFIX = {
+        begin: /-(webkit|moz|ms|o)-(?=[a-z])/
+      };
+      const AT_MODIFIERS = "and or not only";
+      const AT_PROPERTY_RE = /@-?\w[\w]*(-\w+)*/; // @-webkit-keyframes
+      const IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*';
+      const STRINGS = [
+        hljs.APOS_STRING_MODE,
+        hljs.QUOTE_STRING_MODE
+      ];
+
+      return {
+        name: 'CSS',
+        case_insensitive: true,
+        illegal: /[=|'\$]/,
+        keywords: {
+          keyframePosition: "from to"
+        },
+        classNameAliases: {
+          // for visual continuity with `tag {}` and because we
+          // don't have a great class for this?
+          keyframePosition: "selector-tag"
+        },
         contains: [
+          hljs.C_BLOCK_COMMENT_MODE,
+          VENDOR_PREFIX,
+          // to recognize keyframe 40% etc which are outside the scope of our
+          // attribute value mode
+          modes.CSS_NUMBER_MODE,
           {
-            className: 'doctag',
-            begin: '@[A-Za-z]+',
+            className: 'selector-id',
+            begin: /#[A-Za-z0-9_-]+/,
+            relevance: 0
+          },
+          {
+            className: 'selector-class',
+            begin: '\\.' + IDENT_RE,
+            relevance: 0
+          },
+          modes.ATTRIBUTE_SELECTOR_MODE,
+          {
+            className: 'selector-pseudo',
+            variants: [
+              {
+                begin: ':(' + PSEUDO_CLASSES.join('|') + ')'
+              },
+              {
+                begin: '::(' + PSEUDO_ELEMENTS.join('|') + ')'
+              }
+            ]
+          },
+          // we may actually need this (12/2020)
+          // { // pseudo-selector params
+          //   begin: /\(/,
+          //   end: /\)/,
+          //   contains: [ hljs.CSS_NUMBER_MODE ]
+          // },
+          {
+            className: 'attribute',
+            begin: '\\b(' + ATTRIBUTES.join('|') + ')\\b'
+          },
+          // attribute values
+          {
+            begin: ':',
+            end: '[;}]',
             contains: [
+              modes.HEXCOLOR,
+              modes.IMPORTANT,
+              modes.CSS_NUMBER_MODE,
+              ...STRINGS,
+              // needed to highlight these as strings and to avoid issues with
+              // illegal characters that might be inside urls that would tigger the
+              // languages illegal stack
               {
-                className: 'type',
-                begin: '\\{',
-                end: '\\}',
-                relevance: 0
+                begin: /(url|data-uri)\(/,
+                end: /\)/,
+                relevance: 0, // from keywords
+                keywords: {
+                  built_in: "url data-uri"
+                },
+                contains: [
+                  {
+                    className: "string",
+                    // any character other than `)` as in `url()` will be the start
+                    // of a string, which ends with `)` (from the parent mode)
+                    begin: /[^)]/,
+                    endsWithParent: true,
+                    excludeEnd: true
+                  }
+                ]
               },
+              FUNCTION_DISPATCH
+            ]
+          },
+          {
+            begin: lookahead(/@/),
+            end: '[{;]',
+            relevance: 0,
+            illegal: /:/, // break on Less variables @var: ...
+            contains: [
               {
-                className: 'variable',
-                begin: IDENT_RE$1 + '(?=\\s*(-)|$)',
-                endsParent: true,
-                relevance: 0
+                className: 'keyword',
+                begin: AT_PROPERTY_RE
               },
-              // eat spaces (not newlines) so we can find
-              // types or variables
               {
-                begin: /(?=[^\n])\s/,
-                relevance: 0
+                begin: /\s/,
+                endsWithParent: true,
+                excludeEnd: true,
+                relevance: 0,
+                keywords: {
+                  $pattern: /[a-z-]+/,
+                  keyword: AT_MODIFIERS,
+                  attribute: MEDIA_FEATURES.join(" ")
+                },
+                contains: [
+                  {
+                    begin: /[a-z-]+(?=:)/,
+                    className: "attribute"
+                  },
+                  ...STRINGS,
+                  modes.CSS_NUMBER_MODE
+                ]
               }
             ]
+          },
+          {
+            className: 'selector-tag',
+            begin: '\\b(' + TAGS.join('|') + ')\\b'
           }
         ]
-      }
-    );
-    const COMMENT = {
-      className: "comment",
-      variants: [
-        JSDOC_COMMENT,
-        hljs.C_BLOCK_COMMENT_MODE,
-        hljs.C_LINE_COMMENT_MODE
-      ]
-    };
-    const SUBST_INTERNALS = [
-      hljs.APOS_STRING_MODE,
-      hljs.QUOTE_STRING_MODE,
-      HTML_TEMPLATE,
-      CSS_TEMPLATE,
-      TEMPLATE_STRING,
-      NUMBER,
-      hljs.REGEXP_MODE
+      };
+    }
+
+    const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*';
+    const KEYWORDS = [
+      "as", // for exports
+      "in",
+      "of",
+      "if",
+      "for",
+      "while",
+      "finally",
+      "var",
+      "new",
+      "function",
+      "do",
+      "return",
+      "void",
+      "else",
+      "break",
+      "catch",
+      "instanceof",
+      "with",
+      "throw",
+      "case",
+      "default",
+      "try",
+      "switch",
+      "continue",
+      "typeof",
+      "delete",
+      "let",
+      "yield",
+      "const",
+      "class",
+      // JS handles these with a special rule
+      // "get",
+      // "set",
+      "debugger",
+      "async",
+      "await",
+      "static",
+      "import",
+      "from",
+      "export",
+      "extends"
+    ];
+    const LITERALS = [
+      "true",
+      "false",
+      "null",
+      "undefined",
+      "NaN",
+      "Infinity"
     ];
-    SUBST.contains = SUBST_INTERNALS
-      .concat({
-        // we need to pair up {} inside our subst to prevent
-        // it from ending too early by matching another }
-        begin: /\{/,
-        end: /\}/,
-        keywords: KEYWORDS$1,
-        contains: [
-          "self"
-        ].concat(SUBST_INTERNALS)
-      });
-    const SUBST_AND_COMMENTS = [].concat(COMMENT, SUBST.contains);
-    const PARAMS_CONTAINS = SUBST_AND_COMMENTS.concat([
-      // eat recursive parens in sub expressions
-      {
-        begin: /\(/,
-        end: /\)/,
-        keywords: KEYWORDS$1,
-        contains: ["self"].concat(SUBST_AND_COMMENTS)
-      }
-    ]);
-    const PARAMS = {
-      className: 'params',
-      begin: /\(/,
-      end: /\)/,
-      excludeBegin: true,
-      excludeEnd: true,
-      keywords: KEYWORDS$1,
-      contains: PARAMS_CONTAINS
-    };
 
-    return {
-      name: 'Javascript',
-      aliases: ['js', 'jsx', 'mjs', 'cjs'],
-      keywords: KEYWORDS$1,
-      // this will be extended by TypeScript
-      exports: { PARAMS_CONTAINS },
-      illegal: /#(?![$_A-z])/,
-      contains: [
-        hljs.SHEBANG({
-          label: "shebang",
-          binary: "node",
-          relevance: 5
-        }),
-        {
-          label: "use_strict",
-          className: 'meta',
-          relevance: 10,
-          begin: /^\s*['"]use (strict|asm)['"]/
-        },
-        hljs.APOS_STRING_MODE,
-        hljs.QUOTE_STRING_MODE,
-        HTML_TEMPLATE,
-        CSS_TEMPLATE,
-        TEMPLATE_STRING,
-        COMMENT,
-        NUMBER,
-        { // object attr container
-          begin: concat(/[{,\n]\s*/,
-            // we need to look ahead to make sure that we actually have an
-            // attribute coming up so we don't steal a comma from a potential
-            // "value" container
-            //
-            // NOTE: this might not work how you think.  We don't actually always
-            // enter this mode and stay.  Instead it might merely match `,
-            // <comments up next>` and then immediately end after the , because it
-            // fails to find any actual attrs. But this still does the job because
-            // it prevents the value contain rule from grabbing this instead and
-            // prevening this rule from firing when we actually DO have keys.
-            lookahead(concat(
-              // we also need to allow for multiple possible comments inbetween
-              // the first key:value pairing
-              /(((\/\/.*$)|(\/\*(\*[^/]|[^*])*\*\/))\s*)*/,
-              IDENT_RE$1 + '\\s*:'))),
-          relevance: 0,
-          contains: [
-            {
-              className: 'attr',
-              begin: IDENT_RE$1 + lookahead('\\s*:'),
-              relevance: 0
-            }
-          ]
-        },
-        { // "value" container
-          begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
-          keywords: 'return throw case',
-          contains: [
-            COMMENT,
-            hljs.REGEXP_MODE,
-            {
-              className: 'function',
-              // we have to count the parens to make sure we actually have the
-              // correct bounding ( ) before the =>.  There could be any number of
-              // sub-expressions inside also surrounded by parens.
-              begin: '(\\(' +
-              '[^()]*(\\(' +
-              '[^()]*(\\(' +
-              '[^()]*' +
-              '\\)[^()]*)*' +
-              '\\)[^()]*)*' +
-              '\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>',
-              returnBegin: true,
-              end: '\\s*=>',
-              contains: [
-                {
-                  className: 'params',
-                  variants: [
-                    {
-                      begin: hljs.UNDERSCORE_IDENT_RE,
-                      relevance: 0
-                    },
-                    {
-                      className: null,
-                      begin: /\(\s*\)/,
-                      skip: true
-                    },
-                    {
-                      begin: /\(/,
-                      end: /\)/,
-                      excludeBegin: true,
-                      excludeEnd: true,
-                      keywords: KEYWORDS$1,
-                      contains: PARAMS_CONTAINS
-                    }
-                  ]
-                }
-              ]
-            },
-            { // could be a comma delimited list of params to a function call
-              begin: /,/, relevance: 0
-            },
-            {
-              className: '',
-              begin: /\s/,
-              end: /\s*/,
-              skip: true
-            },
-            { // JSX
-              variants: [
-                { begin: FRAGMENT.begin, end: FRAGMENT.end },
-                {
-                  begin: XML_TAG.begin,
-                  // we carefully check the opening tag to see if it truly
-                  // is a tag and not a false positive
-                  'on:begin': XML_TAG.isTrulyOpeningTag,
-                  end: XML_TAG.end
-                }
-              ],
-              subLanguage: 'xml',
-              contains: [
-                {
-                  begin: XML_TAG.begin,
-                  end: XML_TAG.end,
-                  skip: true,
-                  contains: ['self']
-                }
-              ]
+    const TYPES = [
+      "Intl",
+      "DataView",
+      "Number",
+      "Math",
+      "Date",
+      "String",
+      "RegExp",
+      "Object",
+      "Function",
+      "Boolean",
+      "Error",
+      "Symbol",
+      "Set",
+      "Map",
+      "WeakSet",
+      "WeakMap",
+      "Proxy",
+      "Reflect",
+      "JSON",
+      "Promise",
+      "Float64Array",
+      "Int16Array",
+      "Int32Array",
+      "Int8Array",
+      "Uint16Array",
+      "Uint32Array",
+      "Float32Array",
+      "Array",
+      "Uint8Array",
+      "Uint8ClampedArray",
+      "ArrayBuffer",
+      "BigInt64Array",
+      "BigUint64Array",
+      "BigInt"
+    ];
+
+    const ERROR_TYPES = [
+      "EvalError",
+      "InternalError",
+      "RangeError",
+      "ReferenceError",
+      "SyntaxError",
+      "TypeError",
+      "URIError"
+    ];
+
+    const BUILT_IN_GLOBALS = [
+      "setInterval",
+      "setTimeout",
+      "clearInterval",
+      "clearTimeout",
+
+      "require",
+      "exports",
+
+      "eval",
+      "isFinite",
+      "isNaN",
+      "parseFloat",
+      "parseInt",
+      "decodeURI",
+      "decodeURIComponent",
+      "encodeURI",
+      "encodeURIComponent",
+      "escape",
+      "unescape"
+    ];
+
+    const BUILT_IN_VARIABLES = [
+      "arguments",
+      "this",
+      "super",
+      "console",
+      "window",
+      "document",
+      "localStorage",
+      "module",
+      "global" // Node.js
+    ];
+
+    const BUILT_INS = [].concat(
+      BUILT_IN_GLOBALS,
+      TYPES,
+      ERROR_TYPES
+    );
+
+    /*
+    Language: JavaScript
+    Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming 
language with first-class functions.
+    Category: common, scripting, web
+    Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript
+    */
+
+    /** @type LanguageFn */
+    function javascript(hljs) {
+      /**
+       * Takes a string like "<Booger" and checks to see
+       * if we can find a matching "</Booger" later in the
+       * content.
+       * @param {RegExpMatchArray} match
+       * @param {{after:number}} param1
+       */
+      const hasClosingTag = (match, { after }) => {
+        const tag = "</" + match[0].slice(1);
+        const pos = match.input.indexOf(tag, after);
+        return pos !== -1;
+      };
+
+      const IDENT_RE$1 = IDENT_RE;
+      const FRAGMENT = {
+        begin: '<>',
+        end: '</>'
+      };
+      const XML_TAG = {
+        begin: /<[A-Za-z0-9\\._:-]+/,
+        end: /\/[A-Za-z0-9\\._:-]+>|\/>/,
+        /**
+         * @param {RegExpMatchArray} match
+         * @param {CallbackResponse} response
+         */
+        isTrulyOpeningTag: (match, response) => {
+          const afterMatchIndex = match[0].length + match.index;
+          const nextChar = match.input[afterMatchIndex];
+          // nested type?
+          // HTML should not include another raw `<` inside a tag
+          // But a type might: `<Array<Array<number>>`, etc.
+          if (nextChar === "<") {
+            response.ignoreMatch();
+            return;
+          }
+          // <something>
+          // This is now either a tag or a type.
+          if (nextChar === ">") {
+            // if we cannot find a matching closing tag, then we
+            // will ignore it
+            if (!hasClosingTag(match, { after: afterMatchIndex })) {
+              response.ignoreMatch();
             }
-          ],
-          relevance: 0
-        },
-        {
-          className: 'function',
-          beginKeywords: 'function',
-          end: /[{;]/,
-          excludeEnd: true,
-          keywords: KEYWORDS$1,
+          }
+        }
+      };
+      const KEYWORDS$1 = {
+        $pattern: IDENT_RE,
+        keyword: KEYWORDS,
+        literal: LITERALS,
+        built_in: BUILT_INS,
+        "variable.language": BUILT_IN_VARIABLES
+      };
+
+      // https://tc39.es/ecma262/#sec-literals-numeric-literals
+      const decimalDigits = '[0-9](_?[0-9])*';
+      const frac = `\\.(${decimalDigits})`;
+      // DecimalIntegerLiteral, including Annex B NonOctalDecimalIntegerLiteral
+      // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
+      const decimalInteger = `0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*`;
+      const NUMBER = {
+        className: 'number',
+        variants: [
+          // DecimalLiteral
+          { begin: `(\\b(${decimalInteger})((${frac})|\\.)?|(${frac}))` +
+            `[eE][+-]?(${decimalDigits})\\b` },
+          { begin: `\\b(${decimalInteger})\\b((${frac})\\b|\\.)?|(${frac})\\b` },
+
+          // DecimalBigIntegerLiteral
+          { begin: `\\b(0|[1-9](_?[0-9])*)n\\b` },
+
+          // NonDecimalIntegerLiteral
+          { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b" },
+          { begin: "\\b0[bB][0-1](_?[0-1])*n?\\b" },
+          { begin: "\\b0[oO][0-7](_?[0-7])*n?\\b" },
+
+          // LegacyOctalIntegerLiteral (does not include underscore separators)
+          // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
+          { begin: "\\b0[0-7]+n?\\b" },
+        ],
+        relevance: 0
+      };
+
+      const SUBST = {
+        className: 'subst',
+        begin: '\\$\\{',
+        end: '\\}',
+        keywords: KEYWORDS$1,
+        contains: [] // defined later
+      };
+      const HTML_TEMPLATE = {
+        begin: 'html`',
+        end: '',
+        starts: {
+          end: '`',
+          returnEnd: false,
           contains: [
-            'self',
-            hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1 }),
-            PARAMS
+            hljs.BACKSLASH_ESCAPE,
+            SUBST
           ],
-          illegal: /%/
-        },
-        {
-          // prevent this from getting swallowed up by function
-          // since they appear "function like"
-          beginKeywords: "while if switch catch for"
-        },
-        {
-          className: 'function',
-          // we have to count the parens to make sure we actually have the correct
-          // bounding ( ).  There could be any number of sub-expressions inside
-          // also surrounded by parens.
-          begin: hljs.UNDERSCORE_IDENT_RE +
-            '\\(' + // first parens
-            '[^()]*(\\(' +
-              '[^()]*(\\(' +
-                '[^()]*' +
-              '\\)[^()]*)*' +
-            '\\)[^()]*)*' +
-            '\\)\\s*\\{', // end parens
-          returnBegin:true,
+          subLanguage: 'xml'
+        }
+      };
+      const CSS_TEMPLATE = {
+        begin: 'css`',
+        end: '',
+        starts: {
+          end: '`',
+          returnEnd: false,
           contains: [
-            PARAMS,
-            hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1 }),
-          ]
-        },
-        // hack: prevents detection of keywords in some circumstances
-        // .keyword()
-        // $keyword = x
-        {
-          variants: [
-            { begin: '\\.' + IDENT_RE$1 },
-            { begin: '\\$' + IDENT_RE$1 }
+            hljs.BACKSLASH_ESCAPE,
+            SUBST
           ],
-          relevance: 0
-        },
-        { // ES6 class
-          className: 'class',
-          beginKeywords: 'class',
-          end: /[{;=]/,
-          excludeEnd: true,
-          illegal: /[:"[\]]/,
-          contains: [
-            { beginKeywords: 'extends' },
-            hljs.UNDERSCORE_TITLE_MODE
-          ]
-        },
-        {
-          begin: /\b(?=constructor)/,
-          end: /[{;]/,
-          excludeEnd: true,
-          contains: [
-            hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1 }),
-            'self',
-            PARAMS
-          ]
-        },
-        {
-          begin: '(get|set)\\s+(?=' + IDENT_RE$1 + '\\()',
-          end: /\{/,
-          keywords: "get set",
-          contains: [
-            hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1 }),
-            { begin: /\(\)/ }, // eat to avoid empty params
-            PARAMS
-          ]
-        },
-        {
-          begin: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and 
`$.something`
-        }
-      ]
-    };
-  }
-
-  return javascript;
-
-  return module.exports.definer || module.exports;
-
-}());
-
-hljs.registerLanguage('xml', function () {
-  'use strict';
-
-  /**
-   * @param {string} value
-   * @returns {RegExp}
-   * */
-
-  /**
-   * @param {RegExp | string } re
-   * @returns {string}
-   */
-  function source(re) {
-    if (!re) return null;
-    if (typeof re === "string") return re;
-
-    return re.source;
-  }
-
-  /**
-   * @param {RegExp | string } re
-   * @returns {string}
-   */
-  function lookahead(re) {
-    return concat('(?=', re, ')');
-  }
-
-  /**
-   * @param {RegExp | string } re
-   * @returns {string}
-   */
-  function optional(re) {
-    return concat('(', re, ')?');
-  }
-
-  /**
-   * @param {...(RegExp | string) } args
-   * @returns {string}
-   */
-  function concat(...args) {
-    const joined = args.map((x) => source(x)).join("");
-    return joined;
-  }
-
-  /**
-   * Any of the passed expresssions may match
-   *
-   * Creates a huge this | this | that | that match
-   * @param {(RegExp | string)[] } args
-   * @returns {string}
-   */
-  function either(...args) {
-    const joined = '(' + args.map((x) => source(x)).join("|") + ")";
-    return joined;
-  }
-
-  /*
-  Language: HTML, XML
-  Website: https://www.w3.org/XML/
-  Category: common
-  Audit: 2020
-  */
-
-  /** @type LanguageFn */
-  function xml(hljs) {
-    // Element names can contain letters, digits, hyphens, underscores, and periods
-    const TAG_NAME_RE = concat(/[A-Z_]/, optional(/[A-Z0-9_.-]*:/), /[A-Z0-9_.-]*/);
-    const XML_IDENT_RE = /[A-Za-z0-9._:-]+/;
-    const XML_ENTITIES = {
-      className: 'symbol',
-      begin: /&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/
-    };
-    const XML_META_KEYWORDS = {
-      begin: /\s/,
-      contains: [
-        {
-          className: 'meta-keyword',
-          begin: /#?[a-z_][a-z1-9_-]+/,
-          illegal: /\n/
+          subLanguage: 'css'
         }
-      ]
-    };
-    const XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, {
-      begin: /\(/,
-      end: /\)/
-    });
-    const APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, {
-      className: 'meta-string'
-    });
-    const QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, {
-      className: 'meta-string'
-    });
-    const TAG_INTERNALS = {
-      endsWithParent: true,
-      illegal: /</,
-      relevance: 0,
-      contains: [
-        {
-          className: 'attr',
-          begin: XML_IDENT_RE,
-          relevance: 0
-        },
+      };
+      const TEMPLATE_STRING = {
+        className: 'string',
+        begin: '`',
+        end: '`',
+        contains: [
+          hljs.BACKSLASH_ESCAPE,
+          SUBST
+        ]
+      };
+      const JSDOC_COMMENT = hljs.COMMENT(
+        /\/\*\*(?!\/)/,
+        '\\*/',
         {
-          begin: /=\s*/,
           relevance: 0,
           contains: [
             {
-              className: 'string',
-              endsParent: true,
-              variants: [
+              begin: '(?=@[A-Za-z]+)',
+              relevance: 0,
+              contains: [
+                {
+                  className: 'doctag',
+                  begin: '@[A-Za-z]+'
+                },
                 {
-                  begin: /"/,
-                  end: /"/,
-                  contains: [ XML_ENTITIES ]
+                  className: 'type',
+                  begin: '\\{',
+                  end: '\\}',
+                  excludeEnd: true,
+                  excludeBegin: true,
+                  relevance: 0
                 },
                 {
-                  begin: /'/,
-                  end: /'/,
-                  contains: [ XML_ENTITIES ]
+                  className: 'variable',
+                  begin: IDENT_RE$1 + '(?=\\s*(-)|$)',
+                  endsParent: true,
+                  relevance: 0
                 },
+                // eat spaces (not newlines) so we can find
+                // types or variables
                 {
-                  begin: /[^\s"'=<>`]+/
+                  begin: /(?=[^\n])\s/,
+                  relevance: 0
                 }
               ]
             }
           ]
         }
-      ]
-    };
-    return {
-      name: 'HTML, XML',
-      aliases: [
-        'html',
-        'xhtml',
-        'rss',
-        'atom',
-        'xjb',
-        'xsd',
-        'xsl',
-        'plist',
-        'wsf',
-        'svg'
-      ],
-      case_insensitive: true,
-      contains: [
-        {
-          className: 'meta',
-          begin: /<![a-z]/,
-          end: />/,
-          relevance: 10,
+      );
+      const COMMENT = {
+        className: "comment",
+        variants: [
+          JSDOC_COMMENT,
+          hljs.C_BLOCK_COMMENT_MODE,
+          hljs.C_LINE_COMMENT_MODE
+        ]
+      };
+      const SUBST_INTERNALS = [
+        hljs.APOS_STRING_MODE,
+        hljs.QUOTE_STRING_MODE,
+        HTML_TEMPLATE,
+        CSS_TEMPLATE,
+        TEMPLATE_STRING,
+        NUMBER,
+        hljs.REGEXP_MODE
+      ];
+      SUBST.contains = SUBST_INTERNALS
+        .concat({
+          // we need to pair up {} inside our subst to prevent
+          // it from ending too early by matching another }
+          begin: /\{/,
+          end: /\}/,
+          keywords: KEYWORDS$1,
           contains: [
-            XML_META_KEYWORDS,
-            QUOTE_META_STRING_MODE,
-            APOS_META_STRING_MODE,
-            XML_META_PAR_KEYWORDS,
-            {
-              begin: /\[/,
-              end: /\]/,
-              contains: [
-                {
-                  className: 'meta',
-                  begin: /<![a-z]/,
-                  end: />/,
-                  contains: [
-                    XML_META_KEYWORDS,
-                    XML_META_PAR_KEYWORDS,
-                    QUOTE_META_STRING_MODE,
-                    APOS_META_STRING_MODE
-                  ]
-                }
-              ]
+            "self"
+          ].concat(SUBST_INTERNALS)
+        });
+      const SUBST_AND_COMMENTS = [].concat(COMMENT, SUBST.contains);
+      const PARAMS_CONTAINS = SUBST_AND_COMMENTS.concat([
+        // eat recursive parens in sub expressions
+        {
+          begin: /\(/,
+          end: /\)/,
+          keywords: KEYWORDS$1,
+          contains: ["self"].concat(SUBST_AND_COMMENTS)
+        }
+      ]);
+      const PARAMS = {
+        className: 'params',
+        begin: /\(/,
+        end: /\)/,
+        excludeBegin: true,
+        excludeEnd: true,
+        keywords: KEYWORDS$1,
+        contains: PARAMS_CONTAINS
+      };
+
+      // ES6 classes
+      const CLASS_OR_EXTENDS = {
+        variants: [
+          {
+            match: [
+              /class/,
+              /\s+/,
+              IDENT_RE$1
+            ],
+            scope: {
+              1: "keyword",
+              3: "title.class"
+            }
+          },
+          {
+            match: [
+              /extends/,
+              /\s+/,
+              concat(IDENT_RE$1, "(", concat(/\./, IDENT_RE$1), ")*")
+            ],
+            scope: {
+              1: "keyword",
+              3: "title.class.inherited"
             }
+          }
+        ]
+      };
+
+      const CLASS_REFERENCE = {
+        relevance: 0,
+        match: /\b[A-Z][a-z]+([A-Z][a-z]+)*/,
+        className: "title.class",
+        keywords: {
+          _: [
+            // se we still get relevance credit for JS library classes
+            ...TYPES,
+            ...ERROR_TYPES
           ]
-        },
-        hljs.COMMENT(
-          /<!--/,
-          /-->/,
+        }
+      };
+
+      const USE_STRICT = {
+        label: "use_strict",
+        className: 'meta',
+        relevance: 10,
+        begin: /^\s*['"]use (strict|asm)['"]/
+      };
+
+      const FUNCTION_DEFINITION = {
+        variants: [
           {
-            relevance: 10
+            match: [
+              /function/,
+              /\s+/,
+              IDENT_RE$1,
+              /(?=\s*\()/
+            ]
+          },
+          // anonymous function
+          {
+            match: [
+              /function/,
+              /\s*(?=\()/
+            ]
           }
-        ),
-        {
-          begin: /<!\[CDATA\[/,
-          end: /\]\]>/,
-          relevance: 10
+        ],
+        className: {
+          1: "keyword",
+          3: "title.function"
         },
-        XML_ENTITIES,
-        {
-          className: 'meta',
-          begin: /<\?xml/,
-          end: /\?>/,
-          relevance: 10
+        label: "func.def",
+        contains: [ PARAMS ],
+        illegal: /%/
+      };
+
+      const UPPER_CASE_CONSTANT = {
+        relevance: 0,
+        match: /\b[A-Z][A-Z_]+\b/,
+        className: "variable.constant"
+      };
+
+      function noneOf(list) {
+        return concat("(?!", list.join("|"), ")");
+      }
+
+      const FUNCTION_CALL = {
+        match: concat(
+          /\b/,
+          noneOf([
+            ...BUILT_IN_GLOBALS,
+            "super"
+          ]),
+          IDENT_RE$1, lookahead(/\(/)),
+        className: "title.function",
+        relevance: 0
+      };
+
+      const PROPERTY_ACCESS = {
+        begin: concat(/\./, lookahead(
+          concat(IDENT_RE$1, /(?![0-9A-Za-z$_(])/)
+        )),
+        end: IDENT_RE$1,
+        excludeBegin: true,
+        keywords: "prototype",
+        className: "property",
+        relevance: 0
+      };
+
+      const GETTER_OR_SETTER = {
+        match: [
+          /get|set/,
+          /\s+/,
+          IDENT_RE$1,
+          /(?=\()/
+        ],
+        className: {
+          1: "keyword",
+          3: "title.function"
         },
-        {
-          className: 'tag',
-          /*
-          The lookahead pattern (?=...) ensures that 'begin' only matches
-          '<style' as a single word, followed by a whitespace or an
-          ending braket. The '$' is needed for the lexeme to be recognized
-          by hljs.subMode() that tests lexemes outside the stream.
-          */
-          begin: /<style(?=\s|>)/,
-          end: />/,
-          keywords: {
-            name: 'style'
+        contains: [
+          { // eat to avoid empty params
+            begin: /\(\)/
           },
-          contains: [ TAG_INTERNALS ],
-          starts: {
-            end: /<\/style>/,
-            returnEnd: true,
-            subLanguage: [
-              'css',
-              'xml'
+          PARAMS
+        ]
+      };
+
+      const FUNC_LEAD_IN_RE = '(\\(' +
+        '[^()]*(\\(' +
+        '[^()]*(\\(' +
+        '[^()]*' +
+        '\\)[^()]*)*' +
+        '\\)[^()]*)*' +
+        '\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>';
+
+      const FUNCTION_VARIABLE = {
+        match: [
+          /const|var|let/, /\s+/,
+          IDENT_RE$1, /\s*/,
+          /=\s*/,
+          lookahead(FUNC_LEAD_IN_RE)
+        ],
+        className: {
+          1: "keyword",
+          3: "title.function"
+        },
+        contains: [
+          PARAMS
+        ]
+      };
+
+      return {
+        name: 'Javascript',
+        aliases: ['js', 'jsx', 'mjs', 'cjs'],
+        keywords: KEYWORDS$1,
+        // this will be extended by TypeScript
+        exports: { PARAMS_CONTAINS },
+        illegal: /#(?![$_A-z])/,
+        contains: [
+          hljs.SHEBANG({
+            label: "shebang",
+            binary: "node",
+            relevance: 5
+          }),
+          USE_STRICT,
+          hljs.APOS_STRING_MODE,
+          hljs.QUOTE_STRING_MODE,
+          HTML_TEMPLATE,
+          CSS_TEMPLATE,
+          TEMPLATE_STRING,
+          COMMENT,
+          NUMBER,
+          CLASS_REFERENCE,
+          {
+            className: 'attr',
+            begin: IDENT_RE$1 + lookahead(':'),
+            relevance: 0
+          },
+          FUNCTION_VARIABLE,
+          { // "value" container
+            begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
+            keywords: 'return throw case',
+            relevance: 0,
+            contains: [
+              COMMENT,
+              hljs.REGEXP_MODE,
+              {
+                className: 'function',
+                // we have to count the parens to make sure we actually have the
+                // correct bounding ( ) before the =>.  There could be any number of
+                // sub-expressions inside also surrounded by parens.
+                begin: FUNC_LEAD_IN_RE,
+                returnBegin: true,
+                end: '\\s*=>',
+                contains: [
+                  {
+                    className: 'params',
+                    variants: [
+                      {
+                        begin: hljs.UNDERSCORE_IDENT_RE,
+                        relevance: 0
+                      },
+                      {
+                        className: null,
+                        begin: /\(\s*\)/,
+                        skip: true
+                      },
+                      {
+                        begin: /\(/,
+                        end: /\)/,
+                        excludeBegin: true,
+                        excludeEnd: true,
+                        keywords: KEYWORDS$1,
+                        contains: PARAMS_CONTAINS
+                      }
+                    ]
+                  }
+                ]
+              },
+              { // could be a comma delimited list of params to a function call
+                begin: /,/,
+                relevance: 0
+              },
+              {
+                match: /\s+/,
+                relevance: 0
+              },
+              { // JSX
+                variants: [
+                  { begin: FRAGMENT.begin, end: FRAGMENT.end },
+                  {
+                    begin: XML_TAG.begin,
+                    // we carefully check the opening tag to see if it truly
+                    // is a tag and not a false positive
+                    'on:begin': XML_TAG.isTrulyOpeningTag,
+                    end: XML_TAG.end
+                  }
+                ],
+                subLanguage: 'xml',
+                contains: [
+                  {
+                    begin: XML_TAG.begin,
+                    end: XML_TAG.end,
+                    skip: true,
+                    contains: ['self']
+                  }
+                ]
+              }
+            ],
+          },
+          FUNCTION_DEFINITION,
+          {
+            // prevent this from getting swallowed up by function
+            // since they appear "function like"
+            beginKeywords: "while if switch catch for"
+          },
+          {
+            // we have to count the parens to make sure we actually have the correct
+            // bounding ( ).  There could be any number of sub-expressions inside
+            // also surrounded by parens.
+            begin: '\\b(?!function)' + hljs.UNDERSCORE_IDENT_RE +
+              '\\(' + // first parens
+              '[^()]*(\\(' +
+                '[^()]*(\\(' +
+                  '[^()]*' +
+                '\\)[^()]*)*' +
+              '\\)[^()]*)*' +
+              '\\)\\s*\\{', // end parens
+            returnBegin:true,
+            label: "func.def",
+            contains: [
+              PARAMS,
+              hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1, className: "title.function" })
             ]
+          },
+          // catch ... so it won't trigger the property rule below
+          {
+            match: /\.\.\./,
+            relevance: 0
+          },
+          PROPERTY_ACCESS,
+          // hack: prevents detection of keywords in some circumstances
+          // .keyword()
+          // $keyword = x
+          {
+            match: '\\$' + IDENT_RE$1,
+            relevance: 0
+          },
+          {
+            match: [ /\bconstructor(?=\s*\()/ ],
+            className: { 1: "title.function" },
+            contains: [ PARAMS ]
+          },
+          FUNCTION_CALL,
+          UPPER_CASE_CONSTANT,
+          CLASS_OR_EXTENDS,
+          GETTER_OR_SETTER,
+          {
+            match: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and 
`$.something`
           }
-        },
-        {
-          className: 'tag',
-          // See the comment in the <style tag about the lookahead pattern
-          begin: /<script(?=\s|>)/,
-          end: />/,
-          keywords: {
-            name: 'script'
+        ]
+      };
+    }
+
+    /*
+    Language: HTML, XML
+    Website: https://www.w3.org/XML/
+    Category: common, web
+    Audit: 2020
+    */
+
+    /** @type LanguageFn */
+    function xml(hljs) {
+      // Element names can contain letters, digits, hyphens, underscores, and periods
+      const TAG_NAME_RE = concat(/[A-Z_]/, optional(/[A-Z0-9_.-]*:/), /[A-Z0-9_.-]*/);
+      const XML_IDENT_RE = /[A-Za-z0-9._:-]+/;
+      const XML_ENTITIES = {
+        className: 'symbol',
+        begin: /&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/
+      };
+      const XML_META_KEYWORDS = {
+        begin: /\s/,
+        contains: [
+          {
+            className: 'keyword',
+            begin: /#?[a-z_][a-z1-9_-]+/,
+            illegal: /\n/
+          }
+        ]
+      };
+      const XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, {
+        begin: /\(/,
+        end: /\)/
+      });
+      const APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, {
+        className: 'string'
+      });
+      const QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, {
+        className: 'string'
+      });
+      const TAG_INTERNALS = {
+        endsWithParent: true,
+        illegal: /</,
+        relevance: 0,
+        contains: [
+          {
+            className: 'attr',
+            begin: XML_IDENT_RE,
+            relevance: 0
           },
-          contains: [ TAG_INTERNALS ],
-          starts: {
-            end: /<\/script>/,
-            returnEnd: true,
-            subLanguage: [
-              'javascript',
-              'handlebars',
-              'xml'
+          {
+            begin: /=\s*/,
+            relevance: 0,
+            contains: [
+              {
+                className: 'string',
+                endsParent: true,
+                variants: [
+                  {
+                    begin: /"/,
+                    end: /"/,
+                    contains: [ XML_ENTITIES ]
+                  },
+                  {
+                    begin: /'/,
+                    end: /'/,
+                    contains: [ XML_ENTITIES ]
+                  },
+                  {
+                    begin: /[^\s"'=<>`]+/
+                  }
+                ]
+              }
             ]
           }
-        },
-        // we need this for now for jSX
-        {
-          className: 'tag',
-          begin: /<>|<\/>/
-        },
-        // open tag
-        {
-          className: 'tag',
-          begin: concat(
-            /</,
-            lookahead(concat(
-              TAG_NAME_RE,
-              // <tag/>
-              // <tag>
-              // <tag ...
-              either(/\/>/, />/, /\s/)
-            ))
-          ),
-          end: /\/?>/,
-          contains: [
+        ]
+      };
+      return {
+        name: 'HTML, XML',
+        aliases: [
+          'html',
+          'xhtml',
+          'rss',
+          'atom',
+          'xjb',
+          'xsd',
+          'xsl',
+          'plist',
+          'wsf',
+          'svg'
+        ],
+        case_insensitive: true,
+        contains: [
+          {
+            className: 'meta',
+            begin: /<![a-z]/,
+            end: />/,
+            relevance: 10,
+            contains: [
+              XML_META_KEYWORDS,
+              QUOTE_META_STRING_MODE,
+              APOS_META_STRING_MODE,
+              XML_META_PAR_KEYWORDS,
+              {
+                begin: /\[/,
+                end: /\]/,
+                contains: [
+                  {
+                    className: 'meta',
+                    begin: /<![a-z]/,
+                    end: />/,
+                    contains: [
+                      XML_META_KEYWORDS,
+                      XML_META_PAR_KEYWORDS,
+                      QUOTE_META_STRING_MODE,
+                      APOS_META_STRING_MODE
+                    ]
+                  }
+                ]
+              }
+            ]
+          },
+          hljs.COMMENT(
+            /<!--/,
+            /-->/,
             {
-              className: 'name',
-              begin: TAG_NAME_RE,
-              relevance: 0,
-              starts: TAG_INTERNALS
+              relevance: 10
             }
-          ]
-        },
-        // close tag
-        {
-          className: 'tag',
-          begin: concat(
-            /<\//,
-            lookahead(concat(
-              TAG_NAME_RE, />/
-            ))
           ),
-          contains: [
-            {
-              className: 'name',
-              begin: TAG_NAME_RE,
-              relevance: 0
+          {
+            begin: /<!\[CDATA\[/,
+            end: /\]\]>/,
+            relevance: 10
+          },
+          XML_ENTITIES,
+          {
+            className: 'meta',
+            begin: /<\?xml/,
+            end: /\?>/,
+            relevance: 10
+          },
+          {
+            className: 'tag',
+            /*
+            The lookahead pattern (?=...) ensures that 'begin' only matches
+            '<style' as a single word, followed by a whitespace or an
+            ending bracket.
+            */
+            begin: /<style(?=\s|>)/,
+            end: />/,
+            keywords: {
+              name: 'style'
             },
-            {
-              begin: />/,
-              relevance: 0,
-              endsParent: true
+            contains: [ TAG_INTERNALS ],
+            starts: {
+              end: /<\/style>/,
+              returnEnd: true,
+              subLanguage: [
+                'css',
+                'xml'
+              ]
             }
-          ]
-        }
-      ]
-    };
-  }
+          },
+          {
+            className: 'tag',
+            // See the comment in the <style tag about the lookahead pattern
+            begin: /<script(?=\s|>)/,
+            end: />/,
+            keywords: {
+              name: 'script'
+            },
+            contains: [ TAG_INTERNALS ],
+            starts: {
+              end: /<\/script>/,
+              returnEnd: true,
+              subLanguage: [
+                'javascript',
+                'handlebars',
+                'xml'
+              ]
+            }
+          },
+          // we need this for now for jSX
+          {
+            className: 'tag',
+            begin: /<>|<\/>/
+          },
+          // open tag
+          {
+            className: 'tag',
+            begin: concat(
+              /</,
+              lookahead(concat(
+                TAG_NAME_RE,
+                // <tag/>
+                // <tag>
+                // <tag ...
+                either(/\/>/, />/, /\s/)
+              ))
+            ),
+            end: /\/?>/,
+            contains: [
+              {
+                className: 'name',
+                begin: TAG_NAME_RE,
+                relevance: 0,
+                starts: TAG_INTERNALS
+              }
+            ]
+          },
+          // close tag
+          {
+            className: 'tag',
+            begin: concat(
+              /<\//,
+              lookahead(concat(
+                TAG_NAME_RE, />/
+              ))
+            ),
+            contains: [
+              {
+                className: 'name',
+                begin: TAG_NAME_RE,
+                relevance: 0
+              },
+              {
+                begin: />/,
+                relevance: 0,
+                endsParent: true
+              }
+            ]
+          }
+        ]
+      };
+    }
 
-  return xml;
+    var builtIns = /*#__PURE__*/Object.freeze({
+        __proto__: null,
+        grmr_css: css,
+        grmr_javascript: javascript,
+        grmr_xml: xml
+    });
+
+    const hljs = HighlightJS;
 
-  return module.exports.definer || module.exports;
+    for (const key of Object.keys(builtIns)) {
+      const languageName = key.replace("grmr_", "");
+      hljs.registerLanguage(languageName, builtIns[key]);
+    }
+
+    return hljs;
 
 }());
+if (typeof exports === 'object' && typeof module !== 'undefined') { module.exports = hljs; }
diff --git a/third-party/highlightjs/highlightjs.gresource.xml 
b/third-party/highlightjs/highlightjs.gresource.xml
index db1415675..0b27b4165 100644
--- a/third-party/highlightjs/highlightjs.gresource.xml
+++ b/third-party/highlightjs/highlightjs.gresource.xml
@@ -4,7 +4,7 @@
     <file compressed="true">highlight.js</file>
     <file compressed="true">highlightjs-line-numbers.js</file>
     <file compressed="true">epiphany.css</file>
-    <file compressed="true">nnfx.css</file>
+    <file compressed="true">nnfx-light.css</file>
     <file compressed="true">nnfx-dark.css</file>
   </gresource>
 </gresources>
diff --git a/third-party/highlightjs/nnfx-dark.css b/third-party/highlightjs/nnfx-dark.css
index 0751ee5d9..fad542af2 100644
--- a/third-party/highlightjs/nnfx-dark.css
+++ b/third-party/highlightjs/nnfx-dark.css
@@ -1,20 +1,21 @@
-/**
- * nnfx dark - a theme inspired by Netscape Navigator/Firefox
- *
- * @version 1.0.0
- * @author (c) 2020 Jim Mason <jmason ibinx com>
- * @license https://creativecommons.org/licenses/by-sa/4.0  CC BY-SA 4.0
- */
+ /*!
+  Theme: nnfx dark
+  Description: a theme inspired by Netscape Navigator/Firefox
+  Author: (c) 2020-2021 Jim Mason <jmason ibinx com>
+  Maintainer: @RocketMan
+  License: https://creativecommons.org/licenses/by-sa/4.0  CC BY-SA 4.0
+  Updated: 2021-05-17
+
+  @version 1.1.0
+*/
 
 .hljs {
-  display: block;
-  overflow-x: auto;
-  padding: 0.5em;
   background: #333;
   color: #fff;
 }
 
-.xml .hljs-meta {
+.language-xml .hljs-meta,
+.language-xml .hljs-meta-string {
   font-weight: bold;
   font-style: italic;
   color: #69f;
@@ -27,7 +28,8 @@
 }
 
 .hljs-name,
-.hljs-keyword {
+.hljs-keyword,
+.hljs-built_in {
   color: #a7a;
 }
 
@@ -40,14 +42,9 @@
   font-weight: normal;
 }
 
-.hljs-variable,
-.hljs-template-variable {
-  color: #588;
-}
-
 .hljs-code,
 .hljs-string,
-.hljs-meta-string,
+.hljs-meta .hljs-string,
 .hljs-number,
 .hljs-regexp,
 .hljs-link {
@@ -57,24 +54,23 @@
 .hljs-title,
 .hljs-symbol,
 .hljs-bullet,
-.hljs-built_in,
-.hljs-builtin-name {
+.hljs-variable,
+.hljs-template-variable {
   color: #d40;
 }
 
-.hljs-section,
-.hljs-meta {
-  color: #a85;
-}
-
+.hljs-title.class_,
 .hljs-class .hljs-title,
 .hljs-type {
+  font-weight: bold;
   color: #96c;
 }
 
+.hljs-title.function_,
 .hljs-function .hljs-title,
 .hljs-attr,
-.hljs-subst {
+.hljs-subst,
+.hljs-tag {
   color: #fff;
 }
 
@@ -91,9 +87,21 @@
   background-color: #c99;
 }
 
+.hljs-meta {
+  color: #69f;
+}
+
+.hljs-section,
 .hljs-selector-id,
-.hljs-selector-class {
-  color: #964;
+.hljs-selector-class,
+.hljs-selector-pseudo,
+.hljs-selector-tag {
+  font-weight: bold;
+  color: #69f;
+}
+
+.hljs-selector-pseudo {
+  font-style: italic;
 }
 
 .hljs-doctag,
diff --git a/third-party/highlightjs/nnfx.css b/third-party/highlightjs/nnfx-light.css
similarity index 58%
rename from third-party/highlightjs/nnfx.css
rename to third-party/highlightjs/nnfx-light.css
index e7beaa518..675b81643 100644
--- a/third-party/highlightjs/nnfx.css
+++ b/third-party/highlightjs/nnfx-light.css
@@ -1,20 +1,21 @@
-/**
- * nnfx - a theme inspired by Netscape Navigator/Firefox
- *
- * @version 1.0.0
- * @author (c) 2020 Jim Mason <jmason ibinx com>
- * @license https://creativecommons.org/licenses/by-sa/4.0  CC BY-SA 4.0
- */
+ /*!
+  Theme: nnfx light
+  Description: a theme inspired by Netscape Navigator/Firefox
+  Author: (c) 2020-2021 Jim Mason <jmason ibinx com>
+  Maintainer: @RocketMan
+  License: https://creativecommons.org/licenses/by-sa/4.0  CC BY-SA 4.0
+  Updated: 2021-05-17
+
+  @version 1.1.0
+*/
 
 .hljs {
-  display: block;
-  overflow-x: auto;
-  padding: 0.5em;
   background: #fff;
   color: #000;
 }
 
-.xml .hljs-meta {
+.language-xml .hljs-meta,
+.language-xml .hljs-meta-string {
   font-weight: bold;
   font-style: italic;
   color: #48b;
@@ -27,7 +28,8 @@
 }
 
 .hljs-name,
-.hljs-keyword {
+.hljs-keyword,
+.hljs-built_in {
   color: #808;
 }
 
@@ -40,14 +42,9 @@
   font-weight: normal;
 }
 
-.hljs-variable,
-.hljs-template-variable {
-  color: #477;
-}
-
 .hljs-code,
 .hljs-string,
-.hljs-meta-string,
+.hljs-meta .hljs-string,
 .hljs-number,
 .hljs-regexp,
 .hljs-link {
@@ -57,24 +54,23 @@
 .hljs-title,
 .hljs-symbol,
 .hljs-bullet,
-.hljs-built_in,
-.hljs-builtin-name {
+.hljs-variable,
+.hljs-template-variable {
   color: #f40;
 }
 
-.hljs-section,
-.hljs-meta {
-  color: #642;
-}
-
+.hljs-title.class_,
 .hljs-class .hljs-title,
 .hljs-type {
+  font-weight: bold;
   color: #639;
 }
 
+.hljs-title.function_,
 .hljs-function .hljs-title,
 .hljs-attr,
-.hljs-subst {
+.hljs-subst,
+.hljs-tag {
   color: #000;
 }
 
@@ -91,9 +87,21 @@
   background-color: #fbb;
 }
 
+.hljs-meta {
+  color: #269;
+}
+
+.hljs-section,
 .hljs-selector-id,
-.hljs-selector-class {
-  color: #964;
+.hljs-selector-class,
+.hljs-selector-pseudo,
+.hljs-selector-tag {
+  font-weight: bold;
+  color: #48b;
+}
+
+.hljs-selector-pseudo {
+  font-style: italic;
 }
 
 .hljs-doctag,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]