chrome-devtools-frontend
Version:
Chrome DevTools UI
887 lines (811 loc) • 309 kB
JavaScript
/**
* @license
* Copyright 2017 The Lighthouse Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @typedef {import('../types/lhr/audit-details').default.SnippetValue} SnippetValue */
const ELLIPSIS = '\u2026';
const NBSP = '\xa0';
const PASS_THRESHOLD = 0.9;
const RATINGS$1 = {
PASS: {label: 'pass', minScore: PASS_THRESHOLD},
AVERAGE: {label: 'average', minScore: 0.5},
FAIL: {label: 'fail'},
ERROR: {label: 'error'},
};
// 25 most used tld plus one domains (aka public suffixes) from http archive.
// @see https://github.com/GoogleChrome/lighthouse/pull/5065#discussion_r191926212
// The canonical list is https://publicsuffix.org/learn/ but we're only using subset to conserve bytes
const listOfTlds = [
'com', 'co', 'gov', 'edu', 'ac', 'org', 'go', 'gob', 'or', 'net', 'in', 'ne', 'nic', 'gouv',
'web', 'spb', 'blog', 'jus', 'kiev', 'mil', 'wi', 'qc', 'ca', 'bel', 'on',
];
class Util {
static get RATINGS() {
return RATINGS$1;
}
static get PASS_THRESHOLD() {
return PASS_THRESHOLD;
}
static get MS_DISPLAY_VALUE() {
return `%10d${NBSP}ms`;
}
/**
* If LHR is older than 10.0 it will not have the `finalDisplayedUrl` property.
* Old LHRs should have the `finalUrl` property which will work fine for the report.
*
* @param {LH.Result} lhr
*/
static getFinalDisplayedUrl(lhr) {
if (lhr.finalDisplayedUrl) return lhr.finalDisplayedUrl;
if (lhr.finalUrl) return lhr.finalUrl;
throw new Error('Could not determine final displayed URL');
}
/**
* If LHR is older than 10.0 it will not have the `mainDocumentUrl` property.
* Old LHRs should have the `finalUrl` property which is the same as `mainDocumentUrl`.
*
* @param {LH.Result} lhr
*/
static getMainDocumentUrl(lhr) {
return lhr.mainDocumentUrl || lhr.finalUrl;
}
/**
* @param {LH.Result} lhr
* @return {LH.Result.FullPageScreenshot=}
*/
static getFullPageScreenshot(lhr) {
if (lhr.fullPageScreenshot) {
return lhr.fullPageScreenshot;
}
// Prior to 10.0.
const details = /** @type {LH.Result.FullPageScreenshot=} */ (
lhr.audits['full-page-screenshot']?.details);
return details;
}
/**
* Split a string by markdown code spans (enclosed in `backticks`), splitting
* into segments that were enclosed in backticks (marked as `isCode === true`)
* and those that outside the backticks (`isCode === false`).
* @param {string} text
* @return {Array<{isCode: true, text: string}|{isCode: false, text: string}>}
*/
static splitMarkdownCodeSpans(text) {
/** @type {Array<{isCode: true, text: string}|{isCode: false, text: string}>} */
const segments = [];
// Split on backticked code spans.
const parts = text.split(/`(.*?)`/g);
for (let i = 0; i < parts.length; i ++) {
const text = parts[i];
// Empty strings are an artifact of splitting, not meaningful.
if (!text) continue;
// Alternates between plain text and code segments.
const isCode = i % 2 !== 0;
segments.push({
isCode,
text,
});
}
return segments;
}
/**
* Split a string on markdown links (e.g. [some link](https://...)) into
* segments of plain text that weren't part of a link (marked as
* `isLink === false`), and segments with text content and a URL that did make
* up a link (marked as `isLink === true`).
* @param {string} text
* @return {Array<{isLink: true, text: string, linkHref: string}|{isLink: false, text: string}>}
*/
static splitMarkdownLink(text) {
/** @type {Array<{isLink: true, text: string, linkHref: string}|{isLink: false, text: string}>} */
const segments = [];
const parts = text.split(/\[([^\]]+?)\]\((https?:\/\/.*?)\)/g);
while (parts.length) {
// Shift off the same number of elements as the pre-split and capture groups.
const [preambleText, linkText, linkHref] = parts.splice(0, 3);
if (preambleText) { // Skip empty text as it's an artifact of splitting, not meaningful.
segments.push({
isLink: false,
text: preambleText,
});
}
// Append link if there are any.
if (linkText && linkHref) {
segments.push({
isLink: true,
text: linkText,
linkHref,
});
}
}
return segments;
}
/**
* @param {string} string
* @param {number} characterLimit
* @param {string} ellipseSuffix
*/
static truncate(string, characterLimit, ellipseSuffix = '…') {
// Early return for the case where there are fewer bytes than the character limit.
if (string.length <= characterLimit) {
return string;
}
const segmenter = new Intl.Segmenter(undefined, {granularity: 'grapheme'});
const iterator = segmenter.segment(string)[Symbol.iterator]();
let lastSegmentIndex = 0;
for (let i = 0; i <= characterLimit - ellipseSuffix.length; i++) {
const result = iterator.next();
if (result.done) {
return string;
}
lastSegmentIndex = result.value.index;
}
for (let i = 0; i < ellipseSuffix.length; i++) {
if (iterator.next().done) {
return string;
}
}
return string.slice(0, lastSegmentIndex) + ellipseSuffix;
}
/**
* @param {URL} parsedUrl
* @param {{numPathParts?: number, preserveQuery?: boolean, preserveHost?: boolean}=} options
* @return {string}
*/
static getURLDisplayName(parsedUrl, options) {
// Closure optional properties aren't optional in tsc, so fallback needs undefined values.
options = options || {numPathParts: undefined, preserveQuery: undefined,
preserveHost: undefined};
const numPathParts = options.numPathParts !== undefined ? options.numPathParts : 2;
const preserveQuery = options.preserveQuery !== undefined ? options.preserveQuery : true;
const preserveHost = options.preserveHost || false;
let name;
if (parsedUrl.protocol === 'about:' || parsedUrl.protocol === 'data:') {
// Handle 'about:*' and 'data:*' URLs specially since they have no path.
name = parsedUrl.href;
} else {
name = parsedUrl.pathname;
const parts = name.split('/').filter(part => part.length);
if (numPathParts && parts.length > numPathParts) {
name = ELLIPSIS + parts.slice(-1 * numPathParts).join('/');
}
if (preserveHost) {
name = `${parsedUrl.host}/${name.replace(/^\//, '')}`;
}
if (preserveQuery) {
name = `${name}${parsedUrl.search}`;
}
}
const MAX_LENGTH = 64;
if (parsedUrl.protocol !== 'data:') {
// Even non-data uris can be 10k characters long.
name = name.slice(0, 200);
// Always elide hexadecimal hash
name = name.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g, `$1${ELLIPSIS}`);
// Also elide other hash-like mixed-case strings
name = name.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,
`$1${ELLIPSIS}`);
// Also elide long number sequences
name = name.replace(/(\d{3})\d{6,}/g, `$1${ELLIPSIS}`);
// Merge any adjacent ellipses
name = name.replace(/\u2026+/g, ELLIPSIS);
// Elide query params first
if (name.length > MAX_LENGTH && name.includes('?')) {
// Try to leave the first query parameter intact
name = name.replace(/\?([^=]*)(=)?.*/, `?$1$2${ELLIPSIS}`);
// Remove it all if it's still too long
if (name.length > MAX_LENGTH) {
name = name.replace(/\?.*/, `?${ELLIPSIS}`);
}
}
}
// Elide too long names next
if (name.length > MAX_LENGTH) {
const dotIndex = name.lastIndexOf('.');
if (dotIndex >= 0) {
name = name.slice(0, MAX_LENGTH - 1 - (name.length - dotIndex)) +
// Show file extension
`${ELLIPSIS}${name.slice(dotIndex)}`;
} else {
name = name.slice(0, MAX_LENGTH - 1) + ELLIPSIS;
}
}
return name;
}
/**
* Split a URL into a file, hostname and origin for easy display.
* @param {string} url
* @return {{file: string, hostname: string, origin: string}}
*/
static parseURL(url) {
const parsedUrl = new URL(url);
return {
file: Util.getURLDisplayName(parsedUrl),
hostname: parsedUrl.hostname,
origin: parsedUrl.origin,
};
}
/**
* @param {string|URL} value
* @return {!URL}
*/
static createOrReturnURL(value) {
if (value instanceof URL) {
return value;
}
return new URL(value);
}
/**
* Gets the tld of a domain
*
* @param {string} hostname
* @return {string} tld
*/
static getTld(hostname) {
const tlds = hostname.split('.').slice(-2);
if (!listOfTlds.includes(tlds[0])) {
return `.${tlds[tlds.length - 1]}`;
}
return `.${tlds.join('.')}`;
}
/**
* Returns a primary domain for provided hostname (e.g. www.example.com -> example.com).
* @param {string|URL} url hostname or URL object
* @return {string}
*/
static getRootDomain(url) {
const hostname = Util.createOrReturnURL(url).hostname;
const tld = Util.getTld(hostname);
// tld is .com or .co.uk which means we means that length is 1 to big
// .com => 2 & .co.uk => 3
const splitTld = tld.split('.');
// get TLD + root domain
return hostname.split('.').slice(-splitTld.length).join('.');
}
/**
* Returns only lines that are near a message, or the first few lines if there are
* no line messages.
* @param {SnippetValue['lines']} lines
* @param {SnippetValue['lineMessages']} lineMessages
* @param {number} surroundingLineCount Number of lines to include before and after
* the message. If this is e.g. 2 this function might return 5 lines.
*/
static filterRelevantLines(lines, lineMessages, surroundingLineCount) {
if (lineMessages.length === 0) {
// no lines with messages, just return the first bunch of lines
return lines.slice(0, surroundingLineCount * 2 + 1);
}
const minGapSize = 3;
const lineNumbersToKeep = new Set();
// Sort messages so we can check lineNumbersToKeep to see how big the gap to
// the previous line is.
lineMessages = lineMessages.sort((a, b) => (a.lineNumber || 0) - (b.lineNumber || 0));
lineMessages.forEach(({lineNumber}) => {
let firstSurroundingLineNumber = lineNumber - surroundingLineCount;
let lastSurroundingLineNumber = lineNumber + surroundingLineCount;
while (firstSurroundingLineNumber < 1) {
// make sure we still show (surroundingLineCount * 2 + 1) lines in total
firstSurroundingLineNumber++;
lastSurroundingLineNumber++;
}
// If only a few lines would be omitted normally then we prefer to include
// extra lines to avoid the tiny gap
if (lineNumbersToKeep.has(firstSurroundingLineNumber - minGapSize - 1)) {
firstSurroundingLineNumber -= minGapSize;
}
for (let i = firstSurroundingLineNumber; i <= lastSurroundingLineNumber; i++) {
const surroundingLineNumber = i;
lineNumbersToKeep.add(surroundingLineNumber);
}
});
return lines.filter(line => lineNumbersToKeep.has(line.lineNumber));
}
}
// auto-generated by build/build-report-components.js
/** @typedef {import('./dom.js').DOM} DOM */
/* eslint-disable max-len, quotes, comma-spacing */
/**
* @param {DOM} dom
*/
function create3pFilterComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("style");
el1.append("\n .lh-3p-filter {\n color: var(--color-gray-600);\n float: right;\n padding: 6px var(--stackpack-padding-horizontal);\n }\n .lh-3p-filter-label, .lh-3p-filter-input {\n vertical-align: middle;\n user-select: none;\n }\n .lh-3p-filter-input:disabled + .lh-3p-ui-string {\n text-decoration: line-through;\n }\n ");
el0.append(el1);
const el2 = dom.createElement("div", "lh-3p-filter");
const el3 = dom.createElement("label", "lh-3p-filter-label");
const el4 = dom.createElement("input", "lh-3p-filter-input");
el4.setAttribute('type', 'checkbox');
el4.setAttribute('checked', '');
const el5 = dom.createElement("span", "lh-3p-ui-string");
el5.append("Show 3rd party resources");
const el6 = dom.createElement("span", "lh-3p-filter-count");
el3.append(" ",el4," ",el5," (",el6,") ");
el2.append(" ",el3," ");
el0.append(el2);
return el0;
}
/**
* @param {DOM} dom
*/
function createAuditComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-audit");
const el2 = dom.createElement("details", "lh-expandable-details");
const el3 = dom.createElement("summary");
const el4 = dom.createElement("div", "lh-audit__header lh-expandable-details__summary");
const el5 = dom.createElement("span", "lh-audit__score-icon");
const el6 = dom.createElement("span", "lh-audit__title-and-text");
const el7 = dom.createElement("span", "lh-audit__title");
const el8 = dom.createElement("span", "lh-audit__display-text");
el6.append(" ",el7," ",el8," ");
const el9 = dom.createElement("div", "lh-chevron-container");
el4.append(" ",el5," ",el6," ",el9," ");
el3.append(" ",el4," ");
const el10 = dom.createElement("div", "lh-audit__description");
const el11 = dom.createElement("div", "lh-audit__stackpacks");
el2.append(" ",el3," ",el10," ",el11," ");
el1.append(" ",el2," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createCategoryHeaderComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-category-header");
const el2 = dom.createElement("div", "lh-score__gauge");
el2.setAttribute('role', 'heading');
el2.setAttribute('aria-level', '2');
const el3 = dom.createElement("div", "lh-category-header__description");
el1.append(" ",el2," ",el3," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createChevronComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElementNS("http://www.w3.org/2000/svg", "svg", "lh-chevron");
el1.setAttribute('viewBox', '0 0 100 100');
const el2 = dom.createElementNS("http://www.w3.org/2000/svg", "g", "lh-chevron__lines");
const el3 = dom.createElementNS("http://www.w3.org/2000/svg", "path", "lh-chevron__line lh-chevron__line-left");
el3.setAttribute('d', 'M10 50h40');
const el4 = dom.createElementNS("http://www.w3.org/2000/svg", "path", "lh-chevron__line lh-chevron__line-right");
el4.setAttribute('d', 'M90 50H50');
el2.append(" ",el3," ",el4," ");
el1.append(" ",el2," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createClumpComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-audit-group");
const el2 = dom.createElement("details", "lh-clump");
const el3 = dom.createElement("summary");
const el4 = dom.createElement("div", "lh-audit-group__summary");
const el5 = dom.createElement("div", "lh-audit-group__header");
const el6 = dom.createElement("span", "lh-audit-group__title");
const el7 = dom.createElement("span", "lh-audit-group__itemcount");
el5.append(" ",el6," ",el7," "," "," ");
const el8 = dom.createElement("div", "lh-clump-toggle");
const el9 = dom.createElement("span", "lh-clump-toggletext--show");
const el10 = dom.createElement("span", "lh-clump-toggletext--hide");
el8.append(" ",el9," ",el10," ");
el4.append(" ",el5," ",el8," ");
el3.append(" ",el4," ");
el2.append(" ",el3," ");
el1.append(" "," ",el2," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createCrcComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-crc-container");
const el2 = dom.createElement("style");
el2.append("\n .lh-crc .lh-tree-marker {\n width: 12px;\n height: 26px;\n display: block;\n float: left;\n background-position: top left;\n }\n .lh-crc .lh-horiz-down {\n background: url('data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><g fill=\"%23D8D8D8\" fill-rule=\"evenodd\"><path d=\"M16 12v2H-2v-2z\"/><path d=\"M9 12v14H7V12z\"/></g></svg>');\n }\n .lh-crc .lh-right {\n background: url('data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M16 12v2H0v-2z\" fill=\"%23D8D8D8\" fill-rule=\"evenodd\"/></svg>');\n }\n .lh-crc .lh-up-right {\n background: url('data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 0h2v14H7zm2 12h7v2H9z\" fill=\"%23D8D8D8\" fill-rule=\"evenodd\"/></svg>');\n }\n .lh-crc .lh-vert-right {\n background: url('data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 0h2v27H7zm2 12h7v2H9z\" fill=\"%23D8D8D8\" fill-rule=\"evenodd\"/></svg>');\n }\n .lh-crc .lh-vert {\n background: url('data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 0h2v26H7z\" fill=\"%23D8D8D8\" fill-rule=\"evenodd\"/></svg>');\n }\n .lh-crc .lh-crc-tree {\n font-size: 14px;\n width: 100%;\n overflow-x: auto;\n }\n .lh-crc .lh-crc-node {\n height: 26px;\n line-height: 26px;\n white-space: nowrap;\n }\n .lh-crc .lh-crc-node__tree-value {\n margin-left: 10px;\n }\n .lh-crc .lh-crc-node__tree-value div {\n display: inline;\n }\n .lh-crc .lh-crc-node__chain-duration {\n font-weight: 700;\n }\n .lh-crc .lh-crc-initial-nav {\n color: #595959;\n font-style: italic;\n }\n .lh-crc__summary-value {\n margin-bottom: 10px;\n }\n ");
const el3 = dom.createElement("div");
const el4 = dom.createElement("div", "lh-crc__summary-value");
const el5 = dom.createElement("span", "lh-crc__longest_duration_label");
const el6 = dom.createElement("b", "lh-crc__longest_duration");
el4.append(" ",el5," ",el6," ");
el3.append(" ",el4," ");
const el7 = dom.createElement("div", "lh-crc");
const el8 = dom.createElement("div", "lh-crc-initial-nav");
el7.append(" ",el8," "," ");
el1.append(" ",el2," ",el3," ",el7," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createCrcChainComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-crc-node");
const el2 = dom.createElement("span", "lh-crc-node__tree-marker");
const el3 = dom.createElement("span", "lh-crc-node__tree-value");
el1.append(" ",el2," ",el3," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createElementScreenshotComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-element-screenshot");
const el2 = dom.createElement("div", "lh-element-screenshot__content");
const el3 = dom.createElement("div", "lh-element-screenshot__image");
const el4 = dom.createElement("div", "lh-element-screenshot__mask");
const el5 = dom.createElementNS("http://www.w3.org/2000/svg", "svg");
el5.setAttribute('height', '0');
el5.setAttribute('width', '0');
const el6 = dom.createElementNS("http://www.w3.org/2000/svg", "defs");
const el7 = dom.createElementNS("http://www.w3.org/2000/svg", "clipPath");
el7.setAttribute('clipPathUnits', 'objectBoundingBox');
el6.append(" ",el7," "," ");
el5.append(" ",el6," ");
el4.append(" ",el5," ");
const el8 = dom.createElement("div", "lh-element-screenshot__element-marker");
el3.append(" ",el4," ",el8," ");
el2.append(" ",el3," ");
el1.append(" ",el2," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createFooterComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("style");
el1.append("\n .lh-footer {\n padding: var(--footer-padding-vertical) calc(var(--default-padding) * 2);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n }\n .lh-footer .lh-generated {\n text-align: center;\n }\n ");
el0.append(el1);
const el2 = dom.createElement("footer", "lh-footer");
const el3 = dom.createElement("ul", "lh-meta__items");
el3.append(" ");
const el4 = dom.createElement("div", "lh-generated");
const el5 = dom.createElement("b");
el5.append("Lighthouse");
const el6 = dom.createElement("span", "lh-footer__version");
const el7 = dom.createElement("a", "lh-footer__version_issue");
el7.setAttribute('href', 'https://github.com/GoogleChrome/Lighthouse/issues');
el7.setAttribute('target', '_blank');
el7.setAttribute('rel', 'noopener');
el7.append("File an issue");
el4.append(" "," Generated by ",el5," ",el6," | ",el7," ");
el2.append(" ",el3," ",el4," ");
el0.append(el2);
return el0;
}
/**
* @param {DOM} dom
*/
function createFractionComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("a", "lh-fraction__wrapper");
const el2 = dom.createElement("div", "lh-fraction__content-wrapper");
const el3 = dom.createElement("div", "lh-fraction__content");
const el4 = dom.createElement("div", "lh-fraction__background");
el3.append(" ",el4," ");
el2.append(" ",el3," ");
const el5 = dom.createElement("div", "lh-fraction__label");
el1.append(" ",el2," ",el5," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createGaugeComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("a", "lh-gauge__wrapper");
const el2 = dom.createElement("div", "lh-gauge__svg-wrapper");
const el3 = dom.createElementNS("http://www.w3.org/2000/svg", "svg", "lh-gauge");
el3.setAttribute('viewBox', '0 0 120 120');
const el4 = dom.createElementNS("http://www.w3.org/2000/svg", "circle", "lh-gauge-base");
el4.setAttribute('r', '56');
el4.setAttribute('cx', '60');
el4.setAttribute('cy', '60');
el4.setAttribute('stroke-width', '8');
const el5 = dom.createElementNS("http://www.w3.org/2000/svg", "circle", "lh-gauge-arc");
el5.setAttribute('r', '56');
el5.setAttribute('cx', '60');
el5.setAttribute('cy', '60');
el5.setAttribute('stroke-width', '8');
el3.append(" ",el4," ",el5," ");
el2.append(" ",el3," ");
const el6 = dom.createElement("div", "lh-gauge__percentage");
const el7 = dom.createElement("div", "lh-gauge__label");
el1.append(" "," ",el2," ",el6," "," ",el7," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createGaugePwaComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("style");
el1.append("\n .lh-gauge--pwa .lh-gauge--pwa__component {\n display: none;\n }\n .lh-gauge--pwa__wrapper:not(.lh-badged--all) .lh-gauge--pwa__logo > path {\n /* Gray logo unless everything is passing. */\n fill: #B0B0B0;\n }\n\n .lh-gauge--pwa__disc {\n fill: var(--color-gray-200);\n }\n\n .lh-gauge--pwa__logo--primary-color {\n fill: #304FFE;\n }\n\n .lh-gauge--pwa__logo--secondary-color {\n fill: #3D3D3D;\n }\n .lh-dark .lh-gauge--pwa__logo--secondary-color {\n fill: #D8B6B6;\n }\n\n /* No passing groups. */\n .lh-gauge--pwa__wrapper:not([class*='lh-badged--']) .lh-gauge--pwa__na-line {\n display: inline;\n }\n /* Just optimized. Same n/a line as no passing groups. */\n .lh-gauge--pwa__wrapper.lh-badged--pwa-optimized:not(.lh-badged--pwa-installable) .lh-gauge--pwa__na-line {\n display: inline;\n }\n\n /* Just installable. */\n .lh-gauge--pwa__wrapper.lh-badged--pwa-installable .lh-gauge--pwa__installable-badge {\n display: inline;\n }\n\n /* All passing groups. */\n .lh-gauge--pwa__wrapper.lh-badged--all .lh-gauge--pwa__check-circle {\n display: inline;\n }\n ");
el0.append(el1);
const el2 = dom.createElement("a", "lh-gauge__wrapper lh-gauge--pwa__wrapper");
const el3 = dom.createElementNS("http://www.w3.org/2000/svg", "svg", "lh-gauge lh-gauge--pwa");
el3.setAttribute('viewBox', '0 0 60 60');
const el4 = dom.createElementNS("http://www.w3.org/2000/svg", "defs");
const el5 = dom.createElementNS("http://www.w3.org/2000/svg", "linearGradient");
el5.setAttribute('id', 'lh-gauge--pwa__check-circle__gradient');
el5.setAttribute('x1', '50%');
el5.setAttribute('y1', '0%');
el5.setAttribute('x2', '50%');
el5.setAttribute('y2', '100%');
const el6 = dom.createElementNS("http://www.w3.org/2000/svg", "stop");
el6.setAttribute('stop-color', '#00C852');
el6.setAttribute('offset', '0%');
const el7 = dom.createElementNS("http://www.w3.org/2000/svg", "stop");
el7.setAttribute('stop-color', '#009688');
el7.setAttribute('offset', '100%');
el5.append(" ",el6," ",el7," ");
const el8 = dom.createElementNS("http://www.w3.org/2000/svg", "linearGradient");
el8.setAttribute('id', 'lh-gauge--pwa__installable__shadow-gradient');
el8.setAttribute('x1', '76.056%');
el8.setAttribute('x2', '24.111%');
el8.setAttribute('y1', '82.995%');
el8.setAttribute('y2', '24.735%');
const el9 = dom.createElementNS("http://www.w3.org/2000/svg", "stop");
el9.setAttribute('stop-color', '#A5D6A7');
el9.setAttribute('offset', '0%');
const el10 = dom.createElementNS("http://www.w3.org/2000/svg", "stop");
el10.setAttribute('stop-color', '#80CBC4');
el10.setAttribute('offset', '100%');
el8.append(" ",el9," ",el10," ");
const el11 = dom.createElementNS("http://www.w3.org/2000/svg", "g");
el11.setAttribute('id', 'lh-gauge--pwa__installable-badge');
const el12 = dom.createElementNS("http://www.w3.org/2000/svg", "circle");
el12.setAttribute('fill', '#FFFFFF');
el12.setAttribute('cx', '10');
el12.setAttribute('cy', '10');
el12.setAttribute('r', '10');
const el13 = dom.createElementNS("http://www.w3.org/2000/svg", "path");
el13.setAttribute('fill', '#009688');
el13.setAttribute('d', 'M10 4.167A5.835 5.835 0 0 0 4.167 10 5.835 5.835 0 0 0 10 15.833 5.835 5.835 0 0 0 15.833 10 5.835 5.835 0 0 0 10 4.167zm2.917 6.416h-2.334v2.334H9.417v-2.334H7.083V9.417h2.334V7.083h1.166v2.334h2.334v1.166z');
el11.append(" ",el12," ",el13," ");
el4.append(" ",el5," ",el8," ",el11," ");
const el14 = dom.createElementNS("http://www.w3.org/2000/svg", "g");
el14.setAttribute('stroke', 'none');
el14.setAttribute('fill-rule', 'nonzero');
const el15 = dom.createElementNS("http://www.w3.org/2000/svg", "circle", "lh-gauge--pwa__disc");
el15.setAttribute('cx', '30');
el15.setAttribute('cy', '30');
el15.setAttribute('r', '30');
const el16 = dom.createElementNS("http://www.w3.org/2000/svg", "g", "lh-gauge--pwa__logo");
const el17 = dom.createElementNS("http://www.w3.org/2000/svg", "path", "lh-gauge--pwa__logo--secondary-color");
el17.setAttribute('d', 'M35.66 19.39l.7-1.75h2L37.4 15 38.6 12l3.4 9h-2.51l-.58-1.61z');
const el18 = dom.createElementNS("http://www.w3.org/2000/svg", "path", "lh-gauge--pwa__logo--primary-color");
el18.setAttribute('d', 'M33.52 21l3.65-9h-2.42l-2.5 5.82L30.5 12h-1.86l-1.9 5.82-1.35-2.65-1.21 3.72L25.4 21h2.38l1.72-5.2 1.64 5.2z');
const el19 = dom.createElementNS("http://www.w3.org/2000/svg", "path", "lh-gauge--pwa__logo--secondary-color");
el19.setAttribute('fill-rule', 'nonzero');
el19.setAttribute('d', 'M20.3 17.91h1.48c.45 0 .85-.05 1.2-.15l.39-1.18 1.07-3.3a2.64 2.64 0 0 0-.28-.37c-.55-.6-1.36-.91-2.42-.91H18v9h2.3V17.9zm1.96-3.84c.22.22.33.5.33.87 0 .36-.1.65-.29.87-.2.23-.59.35-1.15.35h-.86v-2.41h.87c.52 0 .89.1 1.1.32z');
el16.append(" ",el17," ",el18," ",el19," ");
const el20 = dom.createElementNS("http://www.w3.org/2000/svg", "rect", "lh-gauge--pwa__component lh-gauge--pwa__na-line");
el20.setAttribute('fill', '#FFFFFF');
el20.setAttribute('x', '20');
el20.setAttribute('y', '32');
el20.setAttribute('width', '20');
el20.setAttribute('height', '4');
el20.setAttribute('rx', '2');
const el21 = dom.createElementNS("http://www.w3.org/2000/svg", "g", "lh-gauge--pwa__component lh-gauge--pwa__installable-badge");
el21.setAttribute('transform', 'translate(20, 29)');
const el22 = dom.createElementNS("http://www.w3.org/2000/svg", "path");
el22.setAttribute('fill', 'url(#lh-gauge--pwa__installable__shadow-gradient)');
el22.setAttribute('d', 'M33.629 19.487c-4.272 5.453-10.391 9.39-17.415 10.869L3 17.142 17.142 3 33.63 19.487z');
const el23 = dom.createElementNS("http://www.w3.org/2000/svg", "use");
el23.setAttribute('href', '#lh-gauge--pwa__installable-badge');
el21.append(" ",el22," ",el23," ");
const el24 = dom.createElementNS("http://www.w3.org/2000/svg", "g", "lh-gauge--pwa__component lh-gauge--pwa__check-circle");
el24.setAttribute('transform', 'translate(18, 28)');
const el25 = dom.createElementNS("http://www.w3.org/2000/svg", "circle");
el25.setAttribute('fill', '#FFFFFF');
el25.setAttribute('cx', '12');
el25.setAttribute('cy', '12');
el25.setAttribute('r', '12');
const el26 = dom.createElementNS("http://www.w3.org/2000/svg", "path");
el26.setAttribute('fill', 'url(#lh-gauge--pwa__check-circle__gradient)');
el26.setAttribute('d', 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z');
el24.append(" ",el25," ",el26," ");
el14.append(" "," ",el15," ",el16," "," ",el20," "," ",el21," "," ",el24," ");
el3.append(" ",el4," ",el14," ");
const el27 = dom.createElement("div", "lh-gauge__label");
el2.append(" ",el3," ",el27," ");
el0.append(el2);
return el0;
}
/**
* @param {DOM} dom
*/
function createHeadingComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("style");
el1.append("\n /* CSS Fireworks. Originally by Eddie Lin\n https://codepen.io/paulirish/pen/yEVMbP\n */\n .lh-pyro {\n display: none;\n z-index: 1;\n pointer-events: none;\n }\n .lh-score100 .lh-pyro {\n display: block;\n }\n .lh-score100 .lh-lighthouse stop:first-child {\n stop-color: hsla(200, 12%, 95%, 0);\n }\n .lh-score100 .lh-lighthouse stop:last-child {\n stop-color: hsla(65, 81%, 76%, 1);\n }\n\n .lh-pyro > .lh-pyro-before, .lh-pyro > .lh-pyro-after {\n position: absolute;\n width: 5px;\n height: 5px;\n border-radius: 2.5px;\n box-shadow: 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff;\n animation: 1s bang ease-out infinite backwards, 1s gravity ease-in infinite backwards, 5s position linear infinite backwards;\n animation-delay: 1s, 1s, 1s;\n }\n\n .lh-pyro > .lh-pyro-after {\n animation-delay: 2.25s, 2.25s, 2.25s;\n animation-duration: 1.25s, 1.25s, 6.25s;\n }\n\n @keyframes bang {\n to {\n box-shadow: -70px -115.67px #47ebbc, -28px -99.67px #eb47a4, 58px -31.67px #7eeb47, 13px -141.67px #eb47c5, -19px 6.33px #7347eb, -2px -74.67px #ebd247, 24px -151.67px #eb47e0, 57px -138.67px #b4eb47, -51px -104.67px #479eeb, 62px 8.33px #ebcf47, -93px 0.33px #d547eb, -16px -118.67px #47bfeb, 53px -84.67px #47eb83, 66px -57.67px #eb47bf, -93px -65.67px #91eb47, 30px -13.67px #86eb47, -2px -59.67px #83eb47, -44px 1.33px #eb47eb, 61px -58.67px #47eb73, 5px -22.67px #47e8eb, -66px -28.67px #ebe247, 42px -123.67px #eb5547, -75px 26.33px #7beb47, 15px -52.67px #a147eb, 36px -51.67px #eb8347, -38px -12.67px #eb5547, -46px -59.67px #47eb81, 78px -114.67px #eb47ba, 15px -156.67px #eb47bf, -36px 1.33px #eb4783, -72px -86.67px #eba147, 31px -46.67px #ebe247, -68px 29.33px #47e2eb, -55px 19.33px #ebe047, -56px 27.33px #4776eb, -13px -91.67px #eb5547, -47px -138.67px #47ebc7, -18px -96.67px #eb47ac, 11px -88.67px #4783eb, -67px -28.67px #47baeb, 53px 10.33px #ba47eb, 11px 19.33px #5247eb, -5px -11.67px #eb4791, -68px -4.67px #47eba7, 95px -37.67px #eb478b, -67px -162.67px #eb5d47, -54px -120.67px #eb6847, 49px -12.67px #ebe047, 88px 8.33px #47ebda, 97px 33.33px #eb8147, 6px -71.67px #ebbc47;\n }\n }\n @keyframes gravity {\n to {\n transform: translateY(80px);\n opacity: 0;\n }\n }\n @keyframes position {\n 0%, 19.9% {\n margin-top: 4%;\n margin-left: 47%;\n }\n 20%, 39.9% {\n margin-top: 7%;\n margin-left: 30%;\n }\n 40%, 59.9% {\n margin-top: 6%;\n margin-left: 70%;\n }\n 60%, 79.9% {\n margin-top: 3%;\n margin-left: 20%;\n }\n 80%, 99.9% {\n margin-top: 3%;\n margin-left: 80%;\n }\n }\n ");
el0.append(el1);
const el2 = dom.createElement("div", "lh-header-container");
const el3 = dom.createElement("div", "lh-scores-wrapper-placeholder");
el2.append(" ",el3," ");
el0.append(el2);
return el0;
}
/**
* @param {DOM} dom
*/
function createMetricComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-metric");
const el2 = dom.createElement("div", "lh-metric__innerwrap");
const el3 = dom.createElement("div", "lh-metric__icon");
const el4 = dom.createElement("span", "lh-metric__title");
const el5 = dom.createElement("div", "lh-metric__value");
const el6 = dom.createElement("div", "lh-metric__description");
el2.append(" ",el3," ",el4," ",el5," ",el6," ");
el1.append(" ",el2," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createOpportunityComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-audit lh-audit--load-opportunity");
const el2 = dom.createElement("details", "lh-expandable-details");
const el3 = dom.createElement("summary");
const el4 = dom.createElement("div", "lh-audit__header");
const el5 = dom.createElement("div", "lh-load-opportunity__cols");
const el6 = dom.createElement("div", "lh-load-opportunity__col lh-load-opportunity__col--one");
const el7 = dom.createElement("span", "lh-audit__score-icon");
const el8 = dom.createElement("div", "lh-audit__title");
el6.append(" ",el7," ",el8," ");
const el9 = dom.createElement("div", "lh-load-opportunity__col lh-load-opportunity__col--two");
const el10 = dom.createElement("div", "lh-load-opportunity__sparkline");
const el11 = dom.createElement("div", "lh-sparkline");
const el12 = dom.createElement("div", "lh-sparkline__bar");
el11.append(el12);
el10.append(" ",el11," ");
const el13 = dom.createElement("div", "lh-audit__display-text");
const el14 = dom.createElement("div", "lh-chevron-container");
el9.append(" ",el10," ",el13," ",el14," ");
el5.append(" ",el6," ",el9," ");
el4.append(" ",el5," ");
el3.append(" ",el4," ");
const el15 = dom.createElement("div", "lh-audit__description");
const el16 = dom.createElement("div", "lh-audit__stackpacks");
el2.append(" ",el3," ",el15," ",el16," ");
el1.append(" ",el2," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createOpportunityHeaderComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-load-opportunity__header lh-load-opportunity__cols");
const el2 = dom.createElement("div", "lh-load-opportunity__col lh-load-opportunity__col--one");
const el3 = dom.createElement("div", "lh-load-opportunity__col lh-load-opportunity__col--two");
el1.append(" ",el2," ",el3," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createScorescaleComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-scorescale");
const el2 = dom.createElement("span", "lh-scorescale-range lh-scorescale-range--fail");
el2.append("0–49");
const el3 = dom.createElement("span", "lh-scorescale-range lh-scorescale-range--average");
el3.append("50–89");
const el4 = dom.createElement("span", "lh-scorescale-range lh-scorescale-range--pass");
el4.append("90–100");
el1.append(" ",el2," ",el3," ",el4," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createScoresWrapperComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("style");
el1.append("\n .lh-scores-container {\n display: flex;\n flex-direction: column;\n padding: var(--default-padding) 0;\n position: relative;\n width: 100%;\n }\n\n .lh-sticky-header {\n --gauge-circle-size: var(--gauge-circle-size-sm);\n --plugin-badge-size: 16px;\n --plugin-icon-size: 75%;\n --gauge-wrapper-width: 60px;\n --gauge-percentage-font-size: 13px;\n position: fixed;\n left: 0;\n right: 0;\n top: var(--topbar-height);\n font-weight: 500;\n display: none;\n justify-content: center;\n background-color: var(--sticky-header-background-color);\n border-bottom: 1px solid var(--color-gray-200);\n padding-top: var(--score-container-padding);\n padding-bottom: 4px;\n z-index: 1;\n pointer-events: none;\n }\n\n .lh-devtools .lh-sticky-header {\n /* The report within DevTools is placed in a container with overflow, which changes the placement of this header unless we change `position` to `sticky.` */\n position: sticky;\n }\n\n .lh-sticky-header--visible {\n display: grid;\n grid-auto-flow: column;\n pointer-events: auto;\n }\n\n /* Disable the gauge arc animation for the sticky header, so toggling display: none\n does not play the animation. */\n .lh-sticky-header .lh-gauge-arc {\n animation: none;\n }\n\n .lh-sticky-header .lh-gauge__label,\n .lh-sticky-header .lh-fraction__label {\n display: none;\n }\n\n .lh-highlighter {\n width: var(--gauge-wrapper-width);\n height: 1px;\n background-color: var(--highlighter-background-color);\n /* Position at bottom of first gauge in sticky header. */\n position: absolute;\n grid-column: 1;\n bottom: -1px;\n }\n\n .lh-gauge__wrapper:first-of-type {\n contain: none;\n }\n ");
el0.append(el1);
const el2 = dom.createElement("div", "lh-scores-wrapper");
const el3 = dom.createElement("div", "lh-scores-container");
const el4 = dom.createElement("div", "lh-pyro");
const el5 = dom.createElement("div", "lh-pyro-before");
const el6 = dom.createElement("div", "lh-pyro-after");
el4.append(" ",el5," ",el6," ");
el3.append(" ",el4," ");
el2.append(" ",el3," ");
el0.append(el2);
return el0;
}
/**
* @param {DOM} dom
*/
function createSnippetComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-snippet");
const el2 = dom.createElement("style");
el2.append("\n :root {\n --snippet-highlight-light: #fbf1f2;\n --snippet-highlight-dark: #ffd6d8;\n }\n\n .lh-snippet__header {\n position: relative;\n overflow: hidden;\n padding: 10px;\n border-bottom: none;\n color: var(--snippet-color);\n background-color: var(--snippet-background-color);\n border: 1px solid var(--report-border-color-secondary);\n }\n .lh-snippet__title {\n font-weight: bold;\n float: left;\n }\n .lh-snippet__node {\n float: left;\n margin-left: 4px;\n }\n .lh-snippet__toggle-expand {\n padding: 1px 7px;\n margin-top: -1px;\n margin-right: -7px;\n float: right;\n background: transparent;\n border: none;\n cursor: pointer;\n font-size: 14px;\n color: #0c50c7;\n }\n\n .lh-snippet__snippet {\n overflow: auto;\n border: 1px solid var(--report-border-color-secondary);\n }\n /* Container needed so that all children grow to the width of the scroll container */\n .lh-snippet__snippet-inner {\n display: inline-block;\n min-width: 100%;\n }\n\n .lh-snippet:not(.lh-snippet--expanded) .lh-snippet__show-if-expanded {\n display: none;\n }\n .lh-snippet.lh-snippet--expanded .lh-snippet__show-if-collapsed {\n display: none;\n }\n\n .lh-snippet__line {\n background: white;\n white-space: pre;\n display: flex;\n }\n .lh-snippet__line:not(.lh-snippet__line--message):first-child {\n padding-top: 4px;\n }\n .lh-snippet__line:not(.lh-snippet__line--message):last-child {\n padding-bottom: 4px;\n }\n .lh-snippet__line--content-highlighted {\n background: var(--snippet-highlight-dark);\n }\n .lh-snippet__line--message {\n background: var(--snippet-highlight-light);\n }\n .lh-snippet__line--message .lh-snippet__line-number {\n padding-top: 10px;\n padding-bottom: 10px;\n }\n .lh-snippet__line--message code {\n padding: 10px;\n padding-left: 5px;\n color: var(--color-fail);\n font-family: var(--report-font-family);\n }\n .lh-snippet__line--message code {\n white-space: normal;\n }\n .lh-snippet__line-icon {\n padding-top: 10px;\n display: none;\n }\n .lh-snippet__line--message .lh-snippet__line-icon {\n display: block;\n }\n .lh-snippet__line-icon:before {\n content: \"\";\n display: inline-block;\n vertical-align: middle;\n margin-right: 4px;\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n background-image: var(--fail-icon-url);\n }\n .lh-snippet__line-number {\n flex-shrink: 0;\n width: 40px;\n text-align: right;\n font-family: monospace;\n padding-right: 5px;\n margin-right: 5px;\n color: var(--color-gray-600);\n user-select: none;\n }\n ");
el1.append(" ",el2," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createSnippetContentComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-snippet__snippet");
const el2 = dom.createElement("div", "lh-snippet__snippet-inner");
el1.append(" ",el2," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createSnippetHeaderComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-snippet__header");
const el2 = dom.createElement("div", "lh-snippet__title");
const el3 = dom.createElement("div", "lh-snippet__node");
const el4 = dom.createElement("button", "lh-snippet__toggle-expand");
const el5 = dom.createElement("span", "lh-snippet__btn-label-collapse lh-snippet__show-if-expanded");
const el6 = dom.createElement("span", "lh-snippet__btn-label-expand lh-snippet__show-if-collapsed");
el4.append(" ",el5," ",el6," ");
el1.append(" ",el2," ",el3," ",el4," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createSnippetLineComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("div", "lh-snippet__line");
const el2 = dom.createElement("div", "lh-snippet__line-number");
const el3 = dom.createElement("div", "lh-snippet__line-icon");
const el4 = dom.createElement("code");
el1.append(" ",el2," ",el3," ",el4," ");
el0.append(el1);
return el0;
}
/**
* @param {DOM} dom
*/
function createStylesComponent(dom) {
const el0 = dom.createFragment();
const el1 = dom.createElement("style");
el1.append("/**\n * @license\n * Copyright 2017 The Lighthouse Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS-IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n Naming convention:\n\n If a variable is used for a specific component: --{component}-{property name}-{modifier}\n\n Both {component} and {property name} should be kebab-case. If the target is the entire page,\n use 'report' for the component. The property name should not be abbreviated. Use the\n property name the variable is intended for - if it's used for multiple, a common descriptor\n is fine (ex: 'size' for a variable applied to 'width' and 'height'). If a variable is shared\n across multiple components, either create more variables or just drop the \"{component}-\"\n part of the name. Append any modifiers at the end (ex: 'big', 'dark').\n\n For colors: --color-{hue}-{intensity}\n\n {intensity} is the Material Design tag - 700, A700, etc.\n*/\n.lh-vars {\n /* Palette using Material Design Colors\n * https://www.materialui.co/colors */\n --color-amber-50: #FFF8E1;\n --color-blue-200: #90CAF9;\n --color-blue-900: #0D47A1;\n --color-blue-A700: #2962FF;\n --color-blue-primary: #06f;\n --color-cyan-500: #00BCD4;\n --color-gray-100: #F5F5F5;\n --color-gray-300: #CFCFCF;\n --color-gray-200: #E0E0E0;\n --color-gray-400: #BDBDBD;\n --color-gray-50: #FAFAFA;\n --color-gray-500: #9E9E9E;\n --color-gray-600: #757575;\n --color-gray-700: #616161;\n --color-gray-800: #424242;\n --color-gray-900: #212121;\n --color-gray: #000000;\n --color-green-700: #080;\n --color-green: #0c6;\n --color-lime-400: #D3E156;\n --color-orange-50: #FFF3E0;\n --color-orange-700: #C33300;\n --color-orange: #fa3;\n --color-red-700: #c00;\n --color-red: #f33;\n --color-teal-600: #00897B;\n --color-white: #FFFFFF;\n\n /* Context-specific colors */\n --color-average-secondary: var(--color-orange-700);\n --color-average: var(--color-orange);\n --color-fail-secondary: var(--color-red-700);\n --color-fail: var(--color-red);\n --color-hover: var(--color-gray-50);\n --color-informative: var(--color-blue-900);\n --color-pass-secondary: var(--color-green-700);\n --color-pass: var(--color-green);\n --color-not-applicable: var(--color-gray-600);\n\n /* Component variables */\n --audit-description-padding-left: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right));\n --audit-explanation-line-height: 16px;\n --audit-group-margin-bottom: calc(var(--default-padding) * 6);\n --audit-group-padding-vertical: 8px;\n --audit-margin-horizontal: 5px;\n --audit-padding-vertical: 8px;\n --category-padding: calc(var(--default-padding) * 6) var(--edge-gap-padding) calc(var(--default-padding) * 4);\n --chevron-line-stroke: var(--color-gray-600);\n --chevron-size: 12px;\n --default-padding: 8px;\n --edge-gap-padding: calc(var(--default-padding) * 4);\n --env-item-background-color: var(--color-gray-100);\n --env-item-font-size: 28px;\n --env-item-line-height: 36px;\n --env-item-padding: 10px 0px;\n --env-name-min-width: 220px;\n --footer-padding-vertical: 16px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 48px;\n --gauge-circle-size-sm: 32px;\n --gauge-label-font-size-big: 18px;\n --gauge-label-font-size: var(--report-font-size-secondary);\n --gauge-label-line-height-big: 24px;\n --gauge-label-line-height: var(--report-line-height-secondary);\n --gauge-percentage-font-size-big: 38px;\n --gauge-percentage-font-size: var(--report-font-size-secondary);\n --gauge-wrapper-width: 120px;\n --header-line-height: 24px;\n --highlighter-background-color: var(--report-text-color);\n --icon-square-size: calc(var(--score-icon-size) * 0.88);\n --image-preview-size: 48px;\n --link-color: var(--color-blue-primary);\n --locale-selector-background-color: var(--color-white);\n --metric-toggle-lines-fill: #7F7F7F;\n --metric-value-font-size: calc(var(--report-font-size) * 1.8);\n --metrics-toggle-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-white);\n --plugin-badge-size-big: calc(var(--gauge-circle-size-big) / 2.7);\n --plugin-badge-size: calc(var(--gauge-circle-size) / 2.7);\n --plugin-icon-size: 65%;\n --pwa-icon-margin: 0 var(--default-padding);\n --pwa-icon-size: var(--topbar-logo-size);\n --report-background-color: #fff;\n --report-border-color-secondary: #ebebeb;\n --report-font-family-monospace: 'Roboto Mono', 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: Roboto, Helvetica, Arial, sans-serif;\n --report-font-size: 14px;\n --report-font-size-secondary: 12px;\n --rep